View Single Post
Old 05-02-2009, 11:52 AM   #1 (permalink)
Vorspire
Forum Expert
 
Vorspire's Avatar
 
Join Date: Jan 2005
Location: Newcastle, United Kingdom
Age: 23
Posts: 3,173
Send a message via ICQ to Vorspire Send a message via MSN to Vorspire Send a message via Skype™ to Vorspire
Cool [RUO X] World of Warcraft Level System Utility/SDK


[RUO X] World of Warcraft Level System Utility/SDK Implimentation Guide


Pastebin - View this script with highlighting.

Code:
/*
 * Name:		World of Warcraft Level System Utility (Pre-LK with LK estimations)
 * Version:		1.0.0.0
 * License:		GNU/GPL
 * Support:	RunUO x
 * Author:		Vorspire
 * Date:		02-05-09 (2nd May, 2009)
 * Server:		Rhovanion-PK: CORE
 * Website:	http://www.rpk-uo.com
 * Research:	Based on algorithms provided at http://www.wowwiki.com/Formulas:XP_To_Level
 * Summary:
 * 
 * A simple library of simple utilities using algorithms designed to emulate aspects
 * of the level system used in World of Warcraft.
 * 
 * This utility package (SDK) is *NOT* a level system. It was designed to provide a means
 * for developers to develop a WoW-based level system without having to decipher all
 * of the formulae and equations associated with WoW's level system.
 * 
 * As of now, this SDK provides accuracy up to level 70, anything above level 70 is
 * found by educated estimation.
 * 
 * Everything you need to know about each function has been decribed using documentation
 * nodes for easy-reading and to enhance your understanding by providing correct IDE
 * tooltips when using professional development software(s).
 * 
 * Feel free to redistribute/update/edit as you like.
 * Some tweaks may be required for full LK support.
*/
Code:
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Network;

namespace Server.WoW
{
	/// <summary>
	/// The 'Grey to Skull' Level Color scale as used in World of Warcraft
	/// Key values represent the UO hue relevant to the Key names
	/// 'Skull' is represented by a dark-red
	/// </summary>
	public enum LevelColor
	{
		Grey = 946,
		Green = 243,
		Yellow = 53,
		Orange = 58,
		Red = 34,
		Skull = 144
	}

	/// <summary>
	/// Experience bases for NPCs' of levels that would be found in these zones
	/// Azeroth (1->58->63~),
	/// Outland (57->68->73~),
	/// Northrend (67->83)
	/// </summary>
	public enum ZoneXPBase
	{
		Azeroth = 45,
		Outland = 235,
		Northrend = 580
	}

	public class LevelUtility
	{
		/// <summary>
		/// Factors provided for experience gain calculation
		/// EliteXPFactor default: 2 (effectively doubles base XP)
		/// RestedXPFactor default: 2 (effectively doubles base XP)
		/// </summary>
		public const double
			EliteXPFactor = 2,
			RestedXPFactor = 2;

		/// <summary>
		/// Computes the amount of Experience required to reach the next level
		/// </summary>
		/// <param name="playerLevel">(int) The current level of the player</param>
		/// <param name="xpZone">(ZoneXPBase) The zone XP base to use during calculation</param>
		/// <returns>(int) The total amount of experience required to reach the next level</returns>
		public static int ComputeExperienceReq(int playerLevel, ZoneXPBase xpZone)
		{
			return (int)Round((double)(((8 * playerLevel) + XPDiffReduction(playerLevel)) * XPFromNPC(playerLevel, playerLevel, xpZone) * XPReductionFactor(playerLevel)), -2);
		}

		/// <summary>
		/// Recursively computes the total amount of experience required to reach endLevel from startLevel
		/// endLevel can not be less than, or equal to startLevel, if this occurs, endLevel will be corrected to equal startLevel + 1
		/// </summary>
		/// <param name="startLevel">(int) The level from which to compute from</param>
		/// <param name="endLevel">(int) The level from which to compute to</param>
		/// <param name="xpZone">(ZoneXPBase) The zone XP base to use during calculation</param>
		/// <returns>(int) The total amount of experience required to reach endLevel from startLevel</returns>
		public static int ComputeExperienceReq(int startLevel, int endLevel, ZoneXPBase xpZone)
		{
			int xpReq = 0;

			if (startLevel < 1)
				startLevel = 1;

			if (endLevel <= startLevel)
				endLevel = startLevel + 1;

			for (int i = startLevel; i < endLevel; i++)
			{
				xpReq += ComputeExperienceReq(i, xpZone);
			}

			return xpReq;
		}

		/// <summary>
		/// Computes the experience gain potential
		/// Example: Killing an NPC
		/// </summary>
		/// <param name="playerLevel">(int) The current level of the player that is gaining the experience</param>
		/// <param name="npcLevel">(int) The current level of the NPC that is providing the experience</param>
		/// <param name="rested">(bool) If the player is 'rested', the experience will be factored according to (double)WowLevelUtility.RestedXPFactor</param>
		/// <param name="elite">(bool) If the NPC is 'elite', the experience will be factored according to (double)WoWLevelUtility.EliteXPFactor</param>
		/// <param name="xpZone">(ZoneXPBase) The zone XP base to use during calculation</param>
		/// <returns>(double) The total amount of experience that can potentially be gained from an NPC accroding to player & NPC level matching.</returns>
		public static double ComputeExperienceGain(int playerLevel, int npcLevel, bool rested, bool elite, ZoneXPBase xpZone)
		{
			double baseXP = XPFromNPC(playerLevel, npcLevel, xpZone);

			if (elite)
				baseXP *= EliteXPFactor;

			if (rested)
				baseXP *= RestedXPFactor;

			return baseXP;
		}

		/// <summary>
		/// Gets the level 'color' associated with World of Warcrafts' "Grey to Skull" scale.
		/// Obligatory He-man citation needed.
		/// </summary>
		/// <param name="playerLevel">(int) The current level of the player 'targeting' the NPC.</param>
		/// <param name="npcLevel">(int) The current level of the NPC that is being 'targeted' by the player.</param>
		/// <returns>(WowLevelColor) The level 'color' associated with World of Warcrafts' 'Grey to Skull' scale.
		/// Incidentally, the value name returned also translates into the correct hue id number for use with text.</returns>
		public static LevelColor GetLevelColor(int playerLevel, int npcLevel)
		{
			if (playerLevel + 5 <= npcLevel)
			{
				if (playerLevel + 10 <= npcLevel)
				{
					return LevelColor.Skull;
				}
				else
				{
					return LevelColor.Red;
				}
			}
			else
			{
				switch (npcLevel - playerLevel)
				{
					case 4: { return LevelColor.Orange; }
					case 3: { return LevelColor.Orange; }
					case 2: { return LevelColor.Yellow; }
					case 1: { return LevelColor.Yellow; }
					case 0: { return LevelColor.Yellow; }
					case -1: { return LevelColor.Yellow; }
					case -2: { return LevelColor.Yellow; }
					default:
						if (playerLevel <= 5)
						{
							return LevelColor.Green;
						}
						else
						{
							if (playerLevel <= 39)
							{
								if (npcLevel <= (playerLevel - 5 - Math.Floor((double)(playerLevel / 10))))
								{
									return LevelColor.Grey;
								}
								else
								{
									return LevelColor.Green;
								}
							}
							else
							{
								if (npcLevel <= (playerLevel - 1 - Math.Floor((double)(playerLevel / 5))))
								{
									return LevelColor.Grey;
								}
								else
								{
									return LevelColor.Green;
								}
							}
						}
				}
			}
		}

		/// <summary>
		/// Computes the amount of experience that an NPC may supply
		/// </summary>
		/// <param name="playerLevel">(int) The current level of the player</param>
		/// <param name="npcLevel">(int) The current level of the NPC</param>
		/// <param name="xpZone">(ZoneXPBase) The zone XP base to use during calculation</param>
		/// <returns>(double) The amount of experience that an NPC may supply</returns>
		public static double XPFromNPC(int playerLevel, int npcLevel, ZoneXPBase xpZone)
		{
			double baseXP = 0.0;

			if (GetLevelColor(playerLevel, npcLevel) == LevelColor.Grey)
				return baseXP;

			baseXP = (int)xpZone + (5 * playerLevel);

			if (npcLevel < playerLevel && npcLevel > ZeroXPLevel(playerLevel))
			{
				return baseXP * (1 - (playerLevel - npcLevel) / XPZeroDiff(playerLevel));
			}
			else if (npcLevel > playerLevel)
			{
				return baseXP * (1 + 0.05 * (npcLevel - playerLevel));
			}

			return baseXP;
		}

		/// <summary>
		/// Calculates the level difference threshold for gaining zero XP
		/// </summary>
		/// <param name="playerLevel">(int) The current level of the player</param>
		/// <returns>(int) The level difference threshold for gaining zero XP</returns>
		public static int XPZeroDiff(int playerLevel)
		{
			if (playerLevel <= 7)
			{
				return 5;
			}
			else if (playerLevel >= 8 && playerLevel <= 9)
			{
				return 6;
			}
			else if (playerLevel >= 10 && playerLevel <= 11)
			{
				return 7;
			}
			else if (playerLevel >= 12 && playerLevel <= 15)
			{
				return 8;
			}
			else if (playerLevel >= 16 && playerLevel <= 19)
			{
				return 9;
			}
			else if (playerLevel >= 20 && playerLevel <= 29)
			{
				return 11;
			}
			else if (playerLevel >= 30 && playerLevel <= 39)
			{
				return 12;
			}
			else if (playerLevel >= 40 && playerLevel <= 44)
			{
				return 13;
			}
			else if (playerLevel >= 45 && playerLevel <= 49)
			{
				return 14;
			}
			else if (playerLevel >= 50 && playerLevel <= 54)
			{
				return 15;
			}
			else if (playerLevel >= 55 && playerLevel <= 59)
			{
				return 16;
			}
			else if (playerLevel >= 60 && playerLevel <= 79)
			{
				return 17;
			}
			else if (playerLevel >= 80)
			{
				return 18;
			}

			return 0;
		}

		/// <summary>
		/// Calculates the 'Grey Level'
		/// The 'Grey Level' is the highest level at which an NPC may not grant experience
		/// </summary>
		/// <param name="playerLevel">(int) The current level of the player</param>
		/// <returns>(int) The highest level at which experience will not be granted</returns>
		public static int ZeroXPLevel(int playerLevel)
		{
			if (playerLevel <= 5)
			{
				return 0;
			}
			else if (playerLevel >= 6 && playerLevel <= 39)
			{
				return (int)(playerLevel - Math.Floor((double)(playerLevel / 10)) - 5);
			}
			else if (playerLevel >= 40 && playerLevel <= 59)
			{
				return (int)(playerLevel - Math.Floor((double)(playerLevel / 5)) - 1);
			}
			else if (playerLevel >= 60)
			{
				return (int)(playerLevel - 9);
			}

			return 0;
		}

		/// <summary>
		/// Calculates the factor of XP reduction to implement difficulty scaling
		/// Effective from level 28 to 59
		/// </summary>
		/// <param name="playerLevel">(int) The current level of the player</param>
		/// <returns>(double) The factor of XP reduction to implement difficulty scaling (Effective for level 28 to 59 only)</returns>
		public static double XPDiffReduction(int playerLevel)
		{
			if (playerLevel <= 28)
			{
				return 0;
			}
			else if (playerLevel == 29)
			{
				return 1;
			}
			else if (playerLevel == 30)
			{
				return 3;
			}
			else if (playerLevel == 31)
			{
				return 6;
			}
			else if (playerLevel >= 32 && playerLevel <= 59)
			{
				return 5 * (playerLevel - 30);
			}

			return 0;
		}

		/// <summary>
		/// Calculates the factor of XP reduction to implement advanced difficulty scaling
		/// Effective for all levels
		/// </summary>
		/// <param name="playerLevel">(int) The current level of the player</param>
		/// <returns>(double) The factor of XP reduction to implement advanced difficulty scaling (Effective for all levels)</returns>
		public static double XPReductionFactor(int playerLevel)
		{
			if (playerLevel <= 10)
			{
				return 1;
			}
			else if (playerLevel >= 11 && playerLevel <= 27)
			{
				return (1 - (playerLevel - 10) / 100);
			}
			else if (playerLevel >= 28 && playerLevel <= 59)
			{
				return 0.82;
			}
			else if (playerLevel >= 60)
			{
				return 1;
			}

			return 1;
		}

		/// <summary>
		/// Provides a means to round (double) values to X amount of digits
		/// All experience requirements are scaled to the nearest 100
		/// Example: Round( 1584.82, -2 ); would return (double) 1600.00
		/// </summary>
		/// <param name="value">(double) The value to round</param>
		/// <param name="digits">(int) Digits must be between -15 and 15</param>
		/// <returns>(double) The rounded value</returns>
		public static double Round(double value, int digits)
		{
			if ((digits < -15) || (digits > 15))
				return value;

			if (digits >= 0)
				return Math.Round(value, digits);

			double n = Math.Pow(10, -digits);

			return Math.Round(value / n, 0) * n;
		}
	}
}
Attached Files
File Type: cs WoWLevelUtility.cs (12.1 KB, 84 views)
__________________
Criticism should not be the cause of anger. -Dominik Seifert

Last edited by Vorspire; 05-04-2009 at 11:24 PM.
Vorspire is online now   Reply With Quote