Vorspire
Knight
>> World of Warcraft Level System Utility/SDK Implementation Guide
>> Pastebin - View this script with highlighting.
>> Pastebin - View this script with highlighting.
Rich (BB 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.
*/
Rich (BB 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;
}
}
}