Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

Reply
 
Thread Tools Display Modes
  #1  
Old 09-21-2008, 11:37 PM
Cantus
Fire Beetle
 
Join Date: Sep 2008
Location: New York
Posts: 18
Default Damage Bonus Functions

First of all, I have to say a big "thank you" to all of the amazingly talented folks who make this project possible!

I've enjoyed playing on EQEmu servers for three years now, so it's way past time that I offered something back. I hope it's alright if I offer some code changes for the senior developers to consider including in the next build!

I do work as a software engineer, so my guild leader on PEQ The Grand Creation (Reno) convinced me to take a look at the code used to calculate two-handed weapon damage bonuses. I did, and it's pretty seriously broken, so I hope it's alright that I've put some work into fixing it.


Let me first list the current function used to calculate damage bonuses, so that I can point out what needed to be fixed in it. This method starts on line 1935 in the 2008-09-02 version of attack.cpp:

Code:
int Mob::GetWeaponDamageBonus(const Item_Struct* Weapon)
{
	// Kaiyodo - Calculate the damage bonus for a weapon on the main hand
	if (GetLevel() < 28)
		return(0);
	
	// Check we're on of the classes that gets a damage bonus
	if (!IsWarriorClass())
		return 0;
	
	int BasicBonus = ((GetLevel() - 25) / 3) + 1;
	
	if(!Weapon)
		return(BasicBonus);
	
	// If we have no weapon, or only a single handed weapon, just return the default
	// damage bonus of (Level - 25) / 3
	if (Weapon->ItemClass == ItemClassCommon)
		return BasicBonus;
	
	if ((Weapon->ItemType == ItemType1HS) || (Weapon->ItemType == ItemTypePierce) || (Weapon->ItemType == ItemType1HB))
		return BasicBonus;
	
	// Things get more complicated with 2 handers, the bonus is based on the delay of
	// the weapon as well as a number stored inside the weapon.
	int WeaponBonus = 0;	// How do you find this out?
	
	// Data for this, again, from www.monkly-business.com
	if (Weapon->Delay <= 27)
		return (WeaponBonus + BasicBonus + 1);
	if (Weapon->Delay <= 39)
		return (WeaponBonus + BasicBonus + ((GetLevel()-27) / 4));
	if (Weapon->Delay <= 42)
		return (WeaponBonus + BasicBonus + ((GetLevel()-27) / 4) + 1);
	// Weapon must be > 42 delay
	return (WeaponBonus + BasicBonus + ((GetLevel()-27) / 4) + ((Weapon->Delay-34) / 3));
}

Here are some of the more major items that needed to be fixed:

Code:
int BasicBonus = ((GetLevel() - 25) / 3) + 1;
The correct formula for calculating 1H weapon damage bonuses is (GetLevel() - 25) / 3. The "+ 1" is unnecessary, and artificially increases the damage bonus for all weapons.


Code:
// If we have no weapon, or only a single handed weapon, just return the default
// damage bonus of (Level - 25) / 3
if (Weapon->ItemClass == ItemClassCommon)
	return BasicBonus;
This is the BIGGEST problem with this function. Weapon->ItemClass can have one of three values: ItemClassCommon, ItemClassContainer, or ItemClassBook.

We know that this function is only called if the item in the player's mainhand is a weapon (see line 904 in attack.cpp), so Weapon->ItemClass will ALWAYS be equal to ItemClassCommon.

This line ensures that any additional code in this function will NEVER BE EXECUTED.

So even though there was some code later in this function to approximate damage bonuses for 2H weapons, it never gets executed. With the function as it is currently, 2H weapons always receive the exact same damage bonus as 1H weapons do.


Code:
if ((Weapon->ItemType == ItemType1HS) || (Weapon->ItemType == ItemTypePierce) || (Weapon->ItemType == ItemType1HB))
	return BasicBonus;
Not that it matters, as the bug mentioned above ensures that we'd never actually evaluate this conditional, but ItemTypeHand2Hand is omitted. So Hand to Hand weapons would have been evaluated using the two-handed formulae, and therefore would have had damage bonuses that were unfairly high.

The code for calculating damage bonuses for 2H weapons was a good attempt to approximate the actual formula that Sony/Verant uses. But it's inaccurate in many cases.

With a ton of help from Reno, Janusd, and Romai, I've constructed a formula to accurately return damage bonuses for all two-handed weapons currently in existence, for levels 28 - 80. I warn you: at first, this function may look absolutely ridiculous. But I assure you that quite a bit of work and thought went into it. It uses a hybrid of formulas and lookup tables designed for maximum efficiency. It looks big and ugly, but for the server it's a very good way of getting an accurate result without slowing things down.


Before I post the new formula to calculate 2H damage bonuses, let me post my suggestion for re-writing the above Mob::GetWeaponDamageBonus() function:
* If you don't like all of my comments, please feel free to remove them! I figure it's better to err on the side of too many comments, rather than too few!
Code:
int Mob::GetWeaponDamageBonus(const Item_Struct* Weapon)
{
	// This function calculates and returns the damage bonus for the weapon identified by the parameter "Weapon".
	// Modified 9/21/2008 by Cantus

	// Assert: This function should only be called for hits by the mainhand, as damage bonuses apply only to the
	//         weapon in the primary slot. Be sure to check that Hand == 13 before calling.

	// Assert: The caller should ensure that Weapon is actually a weapon before calling this function.
	//         The ItemInst::IsWeapon() method can be used to quickly determine this.

	if( GetLevel() < 28 || !IsWarriorClass() )
	{
		// Either the PC's level is less than 28 (damage bonuses do not begin to apply until level 28),
		// or the PC is not a melee class (only melee classes receive a damage bonus).

		return 0;
	}

	if( Weapon == NULL || Weapon->ItemType == ItemType1HS || Weapon->ItemType == ItemType1HB || Weapon->ItemType == ItemTypeHand2Hand || Weapon->ItemType == ItemTypePierce )
	{
		// The weapon in the player's main (primary) hand is a one-handed weapon, or there is no item equipped at all.
		//
		// According to player posts on Allakhazam, 1H damage bonuses apply to bare fists (nothing equipped in the mainhand,
		// as indicated by Weapon == NULL).
		//
		// The following formula returns the correct damage bonus for all 1H weapons:

		return (GetLevel() - 25) / 3;
	}

	// If we've gotten to this point, the weapon in the mainhand is a two-handed weapon.
	// Calculating damage bonuses for 2H weapons is more complicated, as it's based on PC level AND the delay of the weapon.
	// The formula to calculate 2H bonuses is HIDEOUS. It's a huge conglomeration of ternary operators and multiple operations.
	//
	// The following formula uses a hybrid approach. In cases where the Level and Delay merit a formula
	// that does not use many operators, the formula is used. In other cases, lookup tables are used for speed.
	// Though the body of the formula looks ridiculous, it's actually a very efficient way of calculating these bonuses.

	return Calculate2HDamageBonus( GetLevel(), Weapon->Delay );
}


Now, you'll also need a copy of the new Calculate2HDamageBonus() function. As I warned you, it's long and ugly-looking, but please don't let that fool you into thinking it's inefficient!

Code:
// **************************************************
// *** Calculate2HDamageBonus()
// ***
// *** Returns the Damage Bonus for a 2-Handed
// *** weapon based on that weapon's delay, and
// *** the level of the character wielding it.
// ***
// *** Submitted September 2008 by Eric Penoyer
// *** (aka Cantus on PEQ The Grand Creation)
// *** EPenoyer (at) gmail.com
// ***
// *** Optimizations and Contributions by:
// *** Reno, Janusd (aka Zetrakyl), and Romai
// **************************************************

inline unsigned char Calculate2HDamageBonus( unsigned char ucPlayerLevel, const unsigned char uc2HWeaponDelay )
{

#if EQDEBUG >= 4

	// Assert: This function should not be called if ucPlayerLevel is less than 28,
	//         as damage bonuses do not apply to players levels 1-27.

	if( ucPlayerLevel < 28 )
	{
		// Damage Bonuses do not begin to apply until a character hits level 28.

		LogFile->write( EQEMuLog::Debug, "Calculate2HDamageBonus() called for player level %d. Should only be called for players levels 28+.", ucPlayerLevel );

		return (unsigned char) 0;
	}

#endif


	// This function would look much cleaner as a simple 53x150 cell matrix.
	// However, that would occupy 7,950 Bytes of memory (7.76 KB), and would likely result
	// in "thrashing the cache" when performing lookups.
	//
	// It would be nice to reverse-engineer the actual formula used by Verant/Sony to calculate
	// 2-Handed Weapon Damage Bonuses. Initially, I thought that this formula would be much more
	// efficient than performing a table lookup. But the more than Reno and I worked on figuring
	// out this formula, the more we're concluded that the formula itself is going to be ugly
	// (that is, it contains so many operations and conditionals that it's fairly CPU intensive).
	// Because of that, we're decided that a lookup table is likely to be the most efficient way
	// to calculate most of these damage bonuses.
	//
	// The function below is a hybrid between a pure formulaic approach and a pure, brute-force
	// lookup table. In cases where a formula is the best bet, I use a formula. In other places
	// where a formula would be ugly, I use a lookup table in the interests of speed. 


	if( uc2HWeaponDelay <= 27 )
	{
		// Damage Bonuses for all 2H weapons with delays of 27 or less are identical.
		// They are the same as the damage bonus would be for a corresponding 1H weapon, plus one.
		// This formula applies to all levels 28-80, and will probably continue to apply if
		// the level cap on Live ever is increased beyond 80.

		return (ucPlayerLevel - 22) / 3;
	}


	if( ucPlayerLevel == 65 && uc2HWeaponDelay <= 59 )
	{
		// Consider these two facts:
		//   * Level 65 is the maximum level on many EQ Emu servers.
		//   * If you listed the levels of all characters logged on to a server, odds are that the number you'll
		//     see most frequently is level 65. That is, there are more level 65 toons than any other single level.
		//
		// Therefore, if we can optimize this function for level 65 toons, we're speeding up the server!
		//
		// With that goal in mind, I create an array of Damage Bonuses for level 65 characters wielding 2H weapons with
		// delays between 28 and 59 (inclusive). I suspect that this one small lookup array will therefore handle
		// many of the calls to this function.

		static const unsigned char ucLevel65DamageBonusesForDelays28to59[] = {35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 42, 42, 42, 45, 45, 47, 48, 49, 49, 51, 51, 52, 53, 54, 54, 56, 56, 57, 58, 59};

		return ucLevel65DamageBonusesForDelays28to59[uc2HWeaponDelay-28];
	}


	if( ucPlayerLevel > 65 )
	{
		if( ucPlayerLevel > 80 )
		{
			// As level 80 is currently the highest achievable level on Live, we only include
			// damage bonus information up to this level.
			//
			// If there is a custom EQEmu server that allows players to level beyond 80, the
			// damage bonus for their 2H weapons will simply not increase beyond their damage
			// bonus at level 80.

			ucPlayerLevel = 80;
		}

		// Lucy does not list a chart of damage bonuses for players levels 66+,
		// so my original version of this function just applied the level 65 damage
		// bonus for level 66+ toons. That sucked for higher level toons, as their
		// 2H weapons stopped ramping up in DPS as they leveled past 65.
		//
		// Thanks to the efforts of two guys, this is no longer the case:
		//
		// Janusd (Zetrakyl) ran a nifty query against the PEQ item database to list
		// the name of an example 2H weapon that represents each possible unique 2H delay.
		//
		// Romai then wrote an excellent script to automatically look up each of those
		// weapons, open the Lucy item page associated with it, and iterate through all
		// levels in the range 66 - 80. He saved the damage bonus for that weapon for
		// each level, and that forms the basis of the lookup tables below.

		if( uc2HWeaponDelay <= 59 )
		{
			static const unsigned char ucDelay28to59Levels66to80[32][15]=
			{
			/*							Level:								*/
			/*	 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80	*/

				{36, 37, 38, 39, 41, 42, 43, 44, 45, 47, 49, 49, 49, 50, 53},	/* Delay = 28 */
				{36, 38, 38, 39, 42, 43, 43, 45, 46, 48, 49, 50, 51, 52, 54},	/* Delay = 29 */
				{37, 38, 39, 40, 43, 43, 44, 46, 47, 48, 50, 51, 52, 53, 55},	/* Delay = 30 */
				{37, 39, 40, 40, 43, 44, 45, 46, 47, 49, 51, 52, 52, 52, 54},	/* Delay = 31 */
				{38, 39, 40, 41, 44, 45, 45, 47, 48, 48, 50, 52, 53, 55, 57},	/* Delay = 32 */
				{38, 40, 41, 41, 44, 45, 46, 48, 49, 50, 52, 53, 54, 56, 58},	/* Delay = 33 */
				{39, 40, 41, 42, 45, 46, 47, 48, 49, 51, 53, 54, 55, 57, 58},	/* Delay = 34 */
				{39, 41, 42, 43, 46, 46, 47, 49, 50, 52, 54, 55, 56, 57, 59},	/* Delay = 35 */
				{40, 41, 42, 43, 46, 47, 48, 50, 51, 53, 55, 55, 56, 58, 60},	/* Delay = 36 */
				{40, 42, 43, 44, 47, 48, 49, 50, 51, 53, 55, 56, 57, 59, 61},	/* Delay = 37 */
				{41, 42, 43, 44, 47, 48, 49, 51, 52, 54, 56, 57, 58, 60, 62},	/* Delay = 38 */
				{41, 43, 44, 45, 48, 49, 50, 52, 53, 55, 57, 58, 59, 61, 63},	/* Delay = 39 */
				{43, 45, 46, 47, 50, 51, 52, 54, 55, 57, 59, 60, 61, 63, 65},	/* Delay = 40 */
				{43, 45, 46, 47, 50, 51, 52, 54, 55, 57, 59, 60, 61, 63, 65},	/* Delay = 41 */
				{44, 46, 47, 48, 51, 52, 53, 55, 56, 58, 60, 61, 62, 64, 66},	/* Delay = 42 */
				{46, 48, 49, 50, 53, 54, 55, 58, 59, 61, 63, 64, 65, 67, 69},	/* Delay = 43 */
				{47, 49, 50, 51, 54, 55, 56, 58, 59, 61, 64, 65, 66, 68, 70},	/* Delay = 44 */
				{48, 50, 51, 52, 56, 57, 58, 60, 61, 63, 65, 66, 68, 70, 72},	/* Delay = 45 */
				{50, 52, 53, 54, 57, 58, 59, 62, 63, 65, 67, 68, 69, 71, 74},	/* Delay = 46 */
				{50, 52, 53, 55, 58, 59, 60, 62, 63, 66, 68, 69, 70, 72, 74},	/* Delay = 47 */
				{51, 53, 54, 55, 58, 60, 61, 63, 64, 66, 69, 69, 71, 73, 75},	/* Delay = 48 */
				{52, 54, 55, 57, 60, 61, 62, 65, 66, 68, 70, 71, 73, 75, 77},	/* Delay = 49 */
				{53, 55, 56, 57, 61, 62, 63, 65, 67, 69, 71, 72, 74, 76, 78},	/* Delay = 50 */
				{53, 55, 57, 58, 61, 62, 64, 66, 67, 69, 72, 73, 74, 77, 79},	/* Delay = 51 */
				{55, 57, 58, 59, 63, 64, 65, 68, 69, 71, 74, 75, 76, 78, 81},	/* Delay = 52 */
				{57, 55, 59, 60, 63, 65, 66, 68, 70, 72, 74, 76, 77, 79, 82},	/* Delay = 53 */
				{56, 58, 59, 61, 64, 65, 67, 69, 70, 73, 75, 76, 78, 80, 82},	/* Delay = 54 */
				{57, 59, 61, 62, 66, 67, 68, 71, 72, 74, 77, 78, 80, 82, 84},	/* Delay = 55 */
				{58, 60, 61, 63, 66, 68, 69, 71, 73, 75, 78, 79, 80, 83, 85},	/* Delay = 56 */

				/* Important Note: Janusd's search for 2H weapons did not find	*/
				/* any 2H weapon with a delay of 57. Therefore the values below	*/
				/* are interpolated, not exact!									*/
				{59, 61, 62, 64, 67, 69, 70, 72, 74, 76, 77, 78, 81, 84, 86},	/* Delay = 57 INTERPOLATED */

				{60, 62, 63, 65, 68, 70, 71, 74, 75, 78, 80, 81, 83, 85, 88},	/* Delay = 58 */

				/* Important Note: Janusd's search for 2H weapons did not find	*/
				/* any 2H weapon with a delay of 59. Therefore the values below	*/
				/* are interpolated, not exact!									*/
				{60, 62, 64, 65, 69, 70, 72, 74, 76, 78, 81, 82, 84, 86, 89},	/* Delay = 59 INTERPOLATED */
			};

			return ucDelay28to59Levels66to80[uc2HWeaponDelay-28][ucPlayerLevel-66];
		}
		else
		{
			// Delay is 60+ 

			const static unsigned char ucDelayOver59Levels66to80[6][15] =
			{
			/*							Level:								*/
			/*	 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80	*/

				{61, 63, 65, 66, 70, 71, 73, 75, 77, 79, 82, 83, 85, 87, 90},				/* Delay = 60 */
				{65, 68, 69, 71, 75, 76, 78, 80, 82, 85, 87, 89, 91, 93, 96},				/* Delay = 65 */

				/* Important Note: Currently, the only 2H weapon with a delay	*/
				/* of 66 is not player equippable (it's None/None). So I'm		*/
				/* leaving it commented out to keep this table smaller.			*/
				//{66, 68, 70, 71, 75, 77, 78, 81, 83, 85, 88, 90, 91, 94, 97},				/* Delay = 66 */

				{70, 72, 74, 76, 80, 81, 83, 86, 88, 88, 90, 95, 97, 99, 102},				/* Delay = 70 */
				{82, 85, 87, 89, 89, 94, 98, 101, 103, 106, 109, 111, 114, 117, 120},		/* Delay = 85 */
				{90, 93, 96, 98, 103, 105, 107, 111, 113, 116, 120, 122, 125, 128, 131},	/* Delay = 95 */

				/* Important Note: Currently, the only 2H weapons with delay	*/
				/* 100 are GM-only items purchased from vendors in Sunset Home	*/
				/* (cshome). Because they are highly unlikely to be used in		*/
				/* combat, I'm commenting it out to keep the table smaller.		*/
				//{95, 98, 101, 103, 108, 110, 113, 116, 119, 122, 126, 128, 131, 134, 138},/* Delay = 100 */

				{136, 140, 144, 148, 154, 157, 161, 166, 170, 174, 179, 183, 187, 191, 196}	/* Delay = 150 */
			};

			if( uc2HWeaponDelay < 65 )
			{
				return ucDelayOver59Levels66to80[0][ucPlayerLevel-66];
			}
			else if( uc2HWeaponDelay < 70 )
			{
				return ucDelayOver59Levels66to80[1][ucPlayerLevel-66];
			}
			else if( uc2HWeaponDelay < 85 )
			{
				return ucDelayOver59Levels66to80[2][ucPlayerLevel-66];
			}
			else if( uc2HWeaponDelay < 95 )
			{
				return ucDelayOver59Levels66to80[3][ucPlayerLevel-66];
			}
			else if( uc2HWeaponDelay < 150 )
			{
				return ucDelayOver59Levels66to80[4][ucPlayerLevel-66];
			}
			else
			{
				return ucDelayOver59Levels66to80[5][ucPlayerLevel-66];
			}
		}
	}


	// If we've gotten to this point in the function without hitting a return statement,
	// we know that the character's level is between 28 and 65, and that the 2H weapon's
	// delay is 28 or higher.

	// The Damage Bonus values returned by this function (in the level 28-65 range) are
	// based on a table of 2H Weapon Damage Bonuses provided by Lucy at the following address:
	// http://lucy.allakhazam.com/dmgbonus.html

	if( uc2HWeaponDelay <= 39 )
	{
		if( ucPlayerLevel <= 53)
		{
			// The Damage Bonus for all 2H weapons with delays between 28 and 39 (inclusive) is the same for players level 53 and below...
			static const unsigned char ucDelay28to39LevelUnder54[] = {1, 1, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 8, 8, 8, 9, 9, 10, 11, 11, 11, 12, 13, 14, 16, 17};

			// As a note: The following formula accurately calculates damage bonuses for 2H weapons with delays in the range 28-39 (inclusive)
			// for characters levels 28-50 (inclusive):
			// return ( (ucPlayerLevel - 22) / 3 ) + ( (ucPlayerLevel - 25) / 5 );
			//
			// However, the small lookup array used above is actually much faster. So we'll just use it instead of the formula
			//
			// (Thanks to Reno for helping figure out the above formula!)

			return ucDelay28to39LevelUnder54[ucPlayerLevel-28];
		}
		else
		{
			// Use a matrix to look up the damage bonus for 2H weapons with delays between 28 and 39 wielded by characters level 54 and above.
			static const unsigned char ucDelay28to39Level54to64[12][11] =
			{
			/*						Level:					*/
			/*	 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64	*/

				{17, 21, 21, 23, 25, 26, 28, 30, 31, 31, 33},	/* Delay = 28 */
				{17, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34},	/* Delay = 29 */
				{18, 21, 22, 23, 25, 27, 29, 31, 32, 32, 34},	/* Delay = 30 */
				{18, 21, 22, 23, 25, 27, 29, 31, 32, 33, 34},	/* Delay = 31 */
				{18, 21, 22, 24, 26, 27, 30, 32, 32, 33, 35},	/* Delay = 32 */
				{18, 21, 22, 24, 26, 27, 30, 32, 33, 34, 35},	/* Delay = 33 */
				{18, 22, 22, 24, 26, 28, 30, 32, 33, 34, 36},	/* Delay = 34 */
				{18, 22, 23, 24, 26, 28, 31, 33, 34, 34, 36},	/* Delay = 35 */
				{18, 22, 23, 25, 27, 28, 31, 33, 34, 35, 37},	/* Delay = 36 */
				{18, 22, 23, 25, 27, 29, 31, 33, 34, 35, 37},	/* Delay = 37 */
				{18, 22, 23, 25, 27, 29, 32, 34, 35, 36, 38},	/* Delay = 38 */
				{18, 22, 23, 25, 27, 29, 32, 34, 35, 36, 38}	/* Delay = 39 */
			};

			return ucDelay28to39Level54to64[uc2HWeaponDelay-28][ucPlayerLevel-54];
		}
	}
	else if( uc2HWeaponDelay <= 59 )
	{
		if( ucPlayerLevel <= 52 )
		{
			if( uc2HWeaponDelay <= 45 )
			{
				static const unsigned char ucDelay40to45Levels28to52[6][25] =
				{
				/*												Level:														*/
				/*	 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52		*/

					{2,  2,  3,  4,  4,  4,  5,  6,  6,  7,  7,  7,  9,  9,  9,  10, 10, 11, 12, 12, 12, 13, 14, 16, 18},	/* Delay = 40 */
					{2,  2,  3,  4,  4,  4,  5,  6,  6,  7,  7,  7,  9,  9,  9,  10, 10, 11, 12, 12, 12, 13, 14, 16, 18},	/* Delay = 41 */
					{2,  2,  3,  4,  4,  4,  5,  6,  6,  7,  7,  7,  9,  9,  9,  10, 10, 11, 12, 12, 12, 13, 14, 16, 18},	/* Delay = 42 */
					{4,  4,  5,  6,  6,  6,  7,  8,  8,  9,  9,  9,  11, 11, 11, 12, 12, 13, 14, 14, 14, 15, 16, 18, 20},	/* Delay = 43 */
					{4,  4,  5,  6,  6,  6,  7,  8,  8,  9,  9,  9,  11, 11, 11, 12, 12, 13, 14, 14, 14, 15, 16, 18, 20},	/* Delay = 44 */
					{5,  5,  6,  7,  7,  7,  8,  9,  9,  10, 10, 10, 12, 12, 12, 13, 13, 14, 15, 15, 15, 16, 17, 19, 21} 	/* Delay = 45 */
				};

				return ucDelay40to45Levels28to52[uc2HWeaponDelay-40][ucPlayerLevel-28];
			}
			else
			{
				static const unsigned char ucDelay46Levels28to52[] = {6,  6,  7,  8,  8,  8,  9,  10, 10, 11, 11, 11, 13, 13, 13, 14, 14, 15, 16, 16, 16, 17, 18, 20, 22};

				return ucDelay46Levels28to52[ucPlayerLevel-28] + ((uc2HWeaponDelay-46) / 3);
			}
		}
		else
		{
			// Player is in the level range 53 - 64

			// Calculating damage bonus for 2H weapons with a delay between 40 and 59 (inclusive) involves, unforunately, a brute-force matrix lookup.
			static const unsigned char ucDelay40to59Levels53to64[20][37] = 
			{
			/*						Level:							*/
			/*	 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64		*/

				{19, 20, 24, 25, 27, 29, 31, 34, 36, 37, 38, 40},	/* Delay = 40 */
				{19, 20, 24, 25, 27, 29, 31, 34, 36, 37, 38, 40},	/* Delay = 41 */
				{19, 20, 24, 25, 27, 29, 31, 34, 36, 37, 38, 40},	/* Delay = 42 */
				{21, 22, 26, 27, 29, 31, 33, 37, 39, 40, 41, 43},	/* Delay = 43 */
				{21, 22, 26, 27, 29, 32, 34, 37, 39, 40, 41, 43},	/* Delay = 44 */
				{22, 23, 27, 28, 31, 33, 35, 38, 40, 42, 43, 45},	/* Delay = 45 */
				{23, 24, 28, 30, 32, 34, 36, 40, 42, 43, 44, 46},	/* Delay = 46 */
				{23, 24, 29, 30, 32, 34, 37, 40, 42, 43, 44, 47},	/* Delay = 47 */
				{23, 24, 29, 30, 32, 35, 37, 40, 43, 44, 45, 47},	/* Delay = 48 */
				{24, 25, 30, 31, 34, 36, 38, 42, 44, 45, 46, 49},	/* Delay = 49 */
				{24, 26, 30, 31, 34, 36, 39, 42, 44, 46, 47, 49},	/* Delay = 50 */
				{24, 26, 30, 31, 34, 36, 39, 42, 45, 46, 47, 49},	/* Delay = 51 */
				{25, 27, 31, 33, 35, 38, 40, 44, 46, 47, 49, 51},	/* Delay = 52 */
				{25, 27, 31, 33, 35, 38, 40, 44, 46, 48, 49, 51},	/* Delay = 53 */
				{26, 27, 32, 33, 36, 38, 41, 44, 47, 48, 49, 52},	/* Delay = 54 */
				{27, 28, 33, 34, 37, 39, 42, 46, 48, 50, 51, 53},	/* Delay = 55 */
				{27, 28, 33, 34, 37, 40, 42, 46, 49, 50, 51, 54},	/* Delay = 56 */
				{27, 28, 33, 34, 37, 40, 43, 46, 49, 50, 52, 54},	/* Delay = 57 */
				{28, 29, 34, 36, 39, 41, 44, 48, 50, 52, 53, 56},	/* Delay = 58 */
				{28, 29, 34, 36, 39, 41, 44, 48, 51, 52, 54, 56}	/* Delay = 59 */
			};

			return ucDelay40to59Levels53to64[uc2HWeaponDelay-40][ucPlayerLevel-53];
		}
	}
	else
	{
		// The following table allows us to look up Damage Bonuses for weapons with delays greater than or equal to 60.
		//
		// There aren't a lot of 2H weapons with a delay greater than 60. In fact, both a database and Lucy search run by janusd confirm
		// that the only unique 2H delays greater than 60 are: 65, 70, 85, 95, and 150.
		//
		// To be fair, there are also weapons with delays of 66 and 100. But they are either not equippable (None/None), or are
		// only available to GMs from merchants in Sunset Home (cshome). In order to keep this table "lean and mean", I will not
		// include the values for delays 66 and 100. If they ever are wielded, the 66 delay weapon will use the 65 delay bonuses,
		// and the 100 delay weapon will use the 95 delay bonuses. So it's not a big deal.
		//
		// Still, if someone in the future decides that they do want to include them, here are the tables for these two delays:
		//
		// {12, 12, 13, 14, 14, 14, 15, 16, 16, 17, 17, 17, 19, 19, 19, 20, 20, 21, 22, 22, 22, 23, 24, 26, 29, 30, 32, 37, 39, 42, 45, 48, 53, 55, 57, 59, 61, 64}		/* Delay = 66 */
		// {24, 24, 25, 26, 26, 26, 27, 28, 28, 29, 29, 29, 31, 31, 31, 32, 32, 33, 34, 34, 34, 35, 36, 39, 43, 45, 48, 55, 57, 62, 66, 71, 77, 80, 83, 85, 89, 92}		/* Delay = 100 */
		//
		// In case there are 2H weapons added in the future with delays other than those listed above (and until the damage bonuses
		// associated with that new delay are added to this function), this function is designed to do the following:
		//
		//		For weapons with delays in the range 60-64, use the Damage Bonus that would apply to a 2H weapon with delay 60.
		//		For weapons with delays in the range 65-69, use the Damage Bonus that would apply to a 2H weapon with delay 65
		//		For weapons with delays in the range 70-84, use the Damage Bonus that would apply to a 2H weapon with delay 70.
		//		For weapons with delays in the range 85-94, use the Damage Bonus that would apply to a 2H weapon with delay 85.
		//		For weapons with delays in the range 95-149, use the Damage Bonus that would apply to a 2H weapon with delay 95.
		//		For weapons with delays 150 or higher, use the Damage Bonus that would apply to a 2H weapon with delay 150.

		static const unsigned char ucDelayOver59Levels28to65[6][38] =
		{
		/*																	Level:																					*/
		/*	 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64. 65	*/

			{10, 10, 11, 12, 12, 12, 13, 14, 14, 15, 15, 15, 17, 17, 17, 18, 18, 19, 20, 20, 20, 21, 22, 24, 27, 28, 30, 35, 36, 39, 42, 45, 49, 51, 53, 54, 57, 59},		/* Delay = 60 */
			{12, 12, 13, 14, 14, 14, 15, 16, 16, 17, 17, 17, 19, 19, 19, 20, 20, 21, 22, 22, 22, 23, 24, 26, 29, 30, 32, 37, 39, 42, 45, 48, 52, 55, 57, 58, 61, 63},		/* Delay = 65 */
			{14, 14, 15, 16, 16, 16, 17, 18, 18, 19, 19, 19, 21, 21, 21, 22, 22, 23, 24, 24, 24, 25, 26, 28, 31, 33, 35, 40, 42, 45, 48, 52, 56, 59, 61, 62, 65, 68},		/* Delay = 70 */
			{19, 19, 20, 21, 21, 21, 22, 23, 23, 24, 24, 24, 26, 26, 26, 27, 27, 28, 29, 29, 29, 30, 31, 34, 37, 39, 41, 47, 49, 54, 57, 61, 66, 69, 72, 74, 77, 80},		/* Delay = 85 */
			{22, 22, 23, 24, 24, 24, 25, 26, 26, 27, 27, 27, 29, 29, 29, 30, 30, 31, 32, 32, 32, 33, 34, 37, 40, 43, 45, 52, 54, 59, 62, 67, 73, 76, 79, 81, 84, 88},		/* Delay = 95 */
			{40, 40, 41, 42, 42, 42, 43, 44, 44, 45, 45, 45, 47, 47, 47, 48, 48, 49, 50, 50, 50, 51, 52, 56, 61, 65, 69, 78, 82, 89, 94, 102, 110, 115, 119, 122, 127, 132}	/* Delay = 150 */
		};

		if( uc2HWeaponDelay < 65 )
		{
			return ucDelayOver59Levels28to65[0][ucPlayerLevel-28];
		}
		else if( uc2HWeaponDelay < 70 )
		{
			return ucDelayOver59Levels28to65[1][ucPlayerLevel-28];
		}
		else if( uc2HWeaponDelay < 85 )
		{
			return ucDelayOver59Levels28to65[2][ucPlayerLevel-28];
		}
		else if( uc2HWeaponDelay < 95 )
		{
			return ucDelayOver59Levels28to65[3][ucPlayerLevel-28];
		}
		else if( uc2HWeaponDelay < 150 )
		{
			return ucDelayOver59Levels28to65[4][ucPlayerLevel-28];
		}
		else
		{
			return ucDelayOver59Levels28to65[5][ucPlayerLevel-28];
		}
	}
}


I am sure that it will return accurate damage bonuses for levels 28-65. However, I believe there are a couple slight inaccuracies in the level range 66-80. Janusd and Romai provided me with the raw data for this level range, and Romai is currently working to verify these values.

Please don't let that stop you from including this code in the next build. If there are any damage bonus inaccuracies for levels 66-80, they are slight. That means that this function is FAR better than what we currently have!

If Romai informs me that there are inaccuracies, I'll correct the tables, and post to let you know to include the updates.


Again, I hope that our contributions are welcomed, and that they benefit the project. Also, I do love coding, so I'd be happy to offer my services on other projects, if needed!

Have a great day, everyone!

-Eric (Cantus)
Reply With Quote
  #2  
Old 09-22-2008, 12:04 AM
ChaosSlayer
Demi-God
 
Join Date: May 2007
Posts: 1,032
Default

It pleases me that as of late so many people have taken interest into submitign new code. =)

Just one minor note - does your code can handle things for levels BEYOND 80?
Some of runing servers with max level of 100+ or even higher - would be nice if these things would keep scaling up and don't just become broken at 70 or 80 =)
Reply With Quote
  #3  
Old 09-22-2008, 12:04 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Looks interesting hehe. I am getting:

Code:
Error: Calculate2HDamageBonus was not declared in this scope
when trying to compile it. Not sure where that needs to be declared exactly, but probably just missing something small somewhere.

Seems like many people are working on making the 2H damage bonus better lately for some reason lol. Here are some other examples:

http://www.eqemulator.net/forums/showthread.php?t=26200

http://www.eqemulator.net/forums/showthread.php?t=26127

And some other combat related ones:

http://www.eqemulator.net/forums/showthread.php?t=26099

http://www.eqemulator.net/forums/showthread.php?t=26213

I wonder why the sudden flood of code for this lol. Not complaining, but it is a little weird to see 3 different posts with fixes for 2H bonuses in the past week or 2.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #4  
Old 09-22-2008, 12:28 AM
renoofturks1
Sarnak
 
Join Date: Jan 2008
Posts: 60
Default

One of them was my attempt at it. It wasn't working as accurately as I had hoped and Cantus offered to take a look at it. After much discussion on our guild forum, this is where we ended up. It came out very well in the end. My biggest concern was time to parse that much code. The look up table's actually ended up parsing far faster than some of the formula's I was attempting to use. It is a very good solution to our problem.
Reply With Quote
  #5  
Old 09-22-2008, 12:42 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

So, where does Calculate2HDamageBonus function go? I can't figure out where to put it and it errors as shown in my previous post if I put it directly in my attack.cpp.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #6  
Old 09-22-2008, 08:43 AM
Cantus
Fire Beetle
 
Join Date: Sep 2008
Location: New York
Posts: 18
Default

ChaosSlayer, you're right... it is great to see people getting more involved with the project! I'm glad that our contributions seem to be well received by the established community and senior developers. I hope that I'll have more opportunities to help in the future!



Trevius, I did see that others were working on this particular problem, as well. I did work along with several of them (such as Reno) to develop what we believe to be the final solution to the problem, as posted above. Unlike the other threads, we're confident saying "it's done; it's fixed" with the code in this thread.

Please do review and test, and if you agree, please feel free to throw it into the next build!


Quote:
Originally Posted by trevius View Post
So, where does Calculate2HDamageBonus function go? I can't figure out where to put it and it errors as shown in my previous post if I put it directly in my attack.cpp.
Trevius, you have several options.

The GetWeaponDamageBonus() is a member of the Mob class, so it's trying to call a Calculate2HDamageBonus() that's also a member of that class. There is none, as Calculate2HDamageBonus() is declared as a global function.

The quick fix is to, when Calculate2HDamageBonus() is called, add two colons (the C++ Scope Resolution Operator) before its name to indicate that it's a function that resides in the global namespace, like this:

Code:
return ::Calculate2HDamageBonus( GetLevel(), Weapon->Delay );

A better long-term choice would probably be to make the Calculate2HDamageBonus() a member of the Mob class. As this is my first contribution and I'm therefore a very junior contributor, I didn't want to presume to add a new function to someone else's class. But if you want to do it, here's a rough description of how:

Sorry that I can't give precise line numbers, as I'm at work, and do not have a copy of the Emu source available. Find the declaration of the Mob class, and add a prototype for the Calculate2HDamageBonus() function. Then add "Mob" and the scope resolution operator before the definition of the function.


A third possibility is: You could also rip out the guts of the function and plug it directly into GetWeaponDamageBonus(), but that'll make the GetWeaponDamageBonus() function huge and ugly. I'd recommend keeping Calculate2HDamageBonus() as a function.


I'll be happy to post more detail on these changes when I get home from work tonight!

Take care,

-Eric
Reply With Quote
  #7  
Old 09-22-2008, 08:53 AM
Cantus
Fire Beetle
 
Join Date: Sep 2008
Location: New York
Posts: 18
Default

Quote:
Originally Posted by ChaosSlayer View Post
Just one minor note - does your code can handle things for levels BEYOND 80?
Some of runing servers with max level of 100+ or even higher - would be nice if these things would keep scaling up and don't just become broken at 70 or 80 =)
Hi, ChaosSlayer!

I apologize. I've played only on The Grand Creation (level cap 65), so I didn't have an idea of how many other servers there were out there with a higher level cap.

Currently, in most cases, this function stops increasing damage bonuses for 2H weapons beyond their value at level 80. That is not ideal for servers with a level cap of 100+. However, it is still FAR better than the way things are currently, so I would recommend not waiting to get these changes added to the next build.

That does not prevent us from adding in support for toons level 81+ in the future! I will work on that for you.

Just so you know: in this function, I, and the folks that helped me, focused on returning damage bonuses that were exactly what they should be on Live. I can confidently say that it does this for levels 28-65, and that it's very close for 66-80 (it will be exact once Romai finishes verifying the data he gave me).

Because Live only goes as high as 80, I only know, for sure, what damage bonuses are up to that level.

Sony has proven to us that they often muck around with the formula used to calculate damage bonuses each time they release a new expansion. So there is no guarantee that future expansions will continue to ramp up 2H damage bonuses at the same rate as bonuses ramped up from level 75 to 80.

I will add in support for toons levels 81+, but it'll just be a "best guess" at what the damage bonuses really will be once Sony increases the level cap on Live. When they do increase the level cap, we may have to adjust the formula to better track the real servers.

Does that sound acceptable? If so, I'll work on it.
Reply With Quote
  #8  
Old 09-22-2008, 10:25 AM
renoofturks1
Sarnak
 
Join Date: Jan 2008
Posts: 60
Default

Quote:
Just one minor note - does your code can handle things for levels BEYOND 80?
Some of running servers with max level of 100+ or even higher - would be nice if these things would keep scaling up and don't just become broken at 70 or 80 =)
Chaos, while this is a great idea. We tried to stay within the realm of live at the moment. In the future thing's may change, but as of right now, we have no idea whatsoever what those damage bonus's should be. It would be a waste of time to scale them up from 80-100 to only have to go back to it and change it when Sony raises the cap. We built it from available information.

On a side note, my previous formula, posted in this forum, should provide what you seek. It will scale up with level beyond level 80. It should be within 1 or 2 damage from levels 50 on up to 100ish, assuming Sony follows a set scale in the future. Under level 50 you will find it becomes less and less accurate as level decreases. We decided on this method as it was 100% accurate whereas every formula I was able to devise was prone to error's due to rounding and other factors. So, you do have another option if you so wish. (Please note, this is NOT tested beyond level 80 so I have no idea how it will turn out, but it should scale well from 50 on up. It isn't 100% but it is close.)
Reply With Quote
  #9  
Old 09-22-2008, 10:50 AM
ChaosSlayer
Demi-God
 
Join Date: May 2007
Posts: 1,032
Default

thank you for replying renoofturks1!

I just want to point out that you should not realy try to keep up with live, since we simply do not have any access to future/curent content anyway , specialy since Aniversary edition will not be supported by eqemu due to its unavalability on market.

So a simple scaling feature will work fine.

Also, could I request that you also include a RULE to TURN OFF damage bonus complitly? A kind of fail safe if it starts behave badly past lev 80, or 100 or 150 or whatever. At least this way weapons gona stay vanila.

thank you =)

PS: As i staed before damage bonus was a complitly useless feature to begin with, the soe should have simply upped the ratios on all 2handers compared to 1handers and be done with it, and this is the kind of balancing I am using on my server
Reply With Quote
  #10  
Old 09-22-2008, 01:28 PM
Cantus
Fire Beetle
 
Join Date: Sep 2008
Location: New York
Posts: 18
Default

Quote:
Originally Posted by ChaosSlayer View Post
I just want to point out that you should not realy try to keep up with live, since we simply do not have any access to future/curent content anyway , specialy since Aniversary edition will not be supported by eqemu due to its unavalability on market.
Hi, Chaos!

What Reno's saying, I believe, is that if future expansions on Live increase the level cap, we can then figure out exactly what 2H weapon damage bonuses will be on Live for higher levels.

That has nothing to do with upgrading the server and requiring EQEmu players to purchase a newer client. Rather, it has to do with figuring out whether Sony will change the formulas they use to calculate damage bonuses for levels 81+, as they've done in the past.


Quote:
Originally Posted by ChaosSlayer View Post
So a simple scaling feature will work fine.

Also, could I request that you also include a RULE to TURN OFF damage bonus complitly? A kind of fail safe if it starts behave badly past lev 80, or 100 or 150 or whatever. At least this way weapons gona stay vanila.
I get what you're saying, but there's no need for a flag to turn off damage bonuses.

Servers with a level cap of 81+ will not break the damage bonus calculation function that I posted above. For most weapons, the damage bonus will simply stop increasing beyond its value at 80.

Reno and I will work together on including a formula that takes a "best guess" as to what damage bonuses for levels 81+ may look like. When Sony eventually increases the level cap, we may find that our guess was off. But that's not a problem! When that happens, we'll simply come back and modify the code.

The formula for 81+ will assume that damage bonuses will keep increasing in line with how they increased from level 70 - 80. I think that should be a good, fair solution for servers with a high level cap! Agreed?

By the way, I agree with your points about Damage Bonus. But not much we can do about it now .

Have a good one,

-Eric (Cantus)
Reply With Quote
  #11  
Old 09-22-2008, 01:31 PM
cavedude's Avatar
cavedude
The PEQ Dude
 
Join Date: Apr 2003
Location: -
Posts: 1,988
Default

This is without a doubt going into PEQ when it comes back up, along with a slew of other things!
Reply With Quote
  #12  
Old 09-22-2008, 02:03 PM
renoofturks1
Sarnak
 
Join Date: Jan 2008
Posts: 60
Default

Quote:
thank you for replying renoofturks1!

I just want to point out that you should not realy try to keep up with live, since we simply do not have any access to future/curent content anyway , specialy since Aniversary edition will not be supported by eqemu due to its unavalability on market.

So a simple scaling feature will work fine.

Also, could I request that you also include a RULE to TURN OFF damage bonus complitly? A kind of fail safe if it starts behave badly past lev 80, or 100 or 150 or whatever. At least this way weapons gona stay vanila.

thank you =)

PS: As i staed before damage bonus was a complitly useless feature to begin with, the soe should have simply upped the ratios on all 2handers compared to 1handers and be done with it, and this is the kind of balancing I am using on my server
Sorry, the keep to live thing is a side effect of working on PEQ a few years

As for the proper scaling, I have never had a toon over 65 on EQEmu, Does the weapon show the damage bonus as continuing to scale beyond level 80? If so, all the information we would need to extend it into the higher levels is right in front of us.

As for my previous formula, it won't break anything beyond level 80, it is only in-accurate under level 50. I can't say if it is scaling improperly above level 80 because I have no idea what properly scaling would be
Reply With Quote
  #13  
Old 09-22-2008, 03:34 PM
ChaosSlayer
Demi-God
 
Join Date: May 2007
Posts: 1,032
Default

Cantus, renoofturks1 - Thank you guys for replying =)

My only concern to avoid an issue when weapons till 80 would have a dmg bonus and past 80 it sudenly becomes zero (or starts going backwords or become negative or whatever +) resulting in pre 80 players doing more dps than past 80 with same weapons.

If dmg bonus gona scale up using same formula or even stay the same - all fine by me , as long as it does not become chaotic from level to level =)

Thanks again!
Reply With Quote
  #14  
Old 09-22-2008, 04:19 PM
renoofturks1
Sarnak
 
Join Date: Jan 2008
Posts: 60
Default

Quote:
If dmg bonus gona scale up using same formula or even stay the same - all fine by me , as long as it does not become chaotic from level to level =)
This system, using the look-up table's, attains exactly that, post 80, it just stops going up, it doesn't decrease, it merely stays constant from 80+
Reply With Quote
  #15  
Old 09-22-2008, 04:36 PM
ChaosSlayer
Demi-God
 
Join Date: May 2007
Posts: 1,032
Default

Quote:
Originally Posted by renoofturks1 View Post
This system, using the look-up table's, attains exactly that, post 80, it just stops going up, it doesn't decrease, it merely stays constant from 80+
good =)

The only thing I could ask if you would add Rule: Damage Bonus on/off - so we can have an option to play with DPS only governed by natural weapon stats.

Thanks =)
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 05:57 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3