- Requirements
- ServUO 57.3
No other file dependencies
MyStats is a modernized Quality of Life (QoL) dashboard built off older statistic gumps, redesigned to give players a clean, easy-to-read overview of their character's true capabilities.
Players can access the dashboard at any time by typing [mystats in-game.
Core Features & Sections:
Installation:Simply drop the code below into a new .cs file in your custom scripts folder, or copy and paste it directly.
Players can access the dashboard at any time by typing [mystats in-game.
Core Features & Sections:
- Attributes & Vitals: Displays Str, Dex, Int, alongside current and max HP, Stamina, and Mana.
- Color-Coded Resistances: Shows Physical, Fire, Cold, Poison, and Energy resistances with matching color highlights.
- Combat & Magic Ratings: Fully utilizes AOS Attributes to pull accurate combat stats (HCI, DCI, DI, SSI, Luck) and magic stats (SDI, LRC, FC, FCR, LMC).
- Regeneration & Misc: Tracks HP/Stam/Mana regen rates, alongside Fame, Karma, and Weight limits.
- Live Syncing: Includes a refresh button in the top right corner to instantly update stats without needing to close and reopen the gump.
Installation:Simply drop the code below into a new .cs file in your custom scripts folder, or copy and paste it directly.
C#:
using System;
using System.Collections.Generic;
using Server;
using Server.Commands;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Gumps
{
public class MyStatsCommand
{
public static void Initialize()
{
CommandSystem.Register("mystats", AccessLevel.Player, new CommandEventHandler(MyStats_OnCommand));
}
[Usage("mystats")]
[Description("Opens the Player Statistics dashboard.")]
public static void MyStats_OnCommand(CommandEventArgs e)
{
Mobile from = e.Mobile;
if (from == null || from.Deleted) return;
from.CloseGump(typeof(PlayerStatsGump));
from.SendGump(new PlayerStatsGump(from));
}
}
public class PlayerStatsGump : Gump
{
private Mobile m_From;
// Color Constants
private const int C_YELLOW = 2213;
private const int C_WHITE = 2036;
private const int C_RED = 1258;
private const int C_BLUE = 1264;
private const int C_GREEN = 1270;
private const int C_PURPLE = 1276;
private const int C_GREY = 2401;
public PlayerStatsGump(Mobile from) : base(50, 50)
{
m_From = from;
AddGumpLayout();
}
public void AddGumpLayout()
{
int width = 640;
int height = 850;
AddPage(0);
AddBackground(0, 0, width, height, 9200);
AddImageTiled(10, 10, width - 20, height - 20, 2624);
AddAlphaRegion(10, 10, width - 20, height - 20);
// --- HEADER ---
// Name (Centered Top)
AddHtml(0, 25, width, 25, ColorAndCenter("#FFCC00", m_From.Name), false, false);
// Top Right Buttons
AddButton(width - 75, 21, 4005, 4007, 1, GumpButtonType.Reply, 0); // Sync Button
AddButton(width - 40, 20, 0xFB1, 0xFB3, 0, GumpButtonType.Reply, 0); // Close Button
// --- ATTRIBUTES ---
// Aligned Left (30) and Right (340)
int attrY = 55;
AddLabel(30, attrY, C_YELLOW, "Attributes");
DrawStat(30, attrY + 25, "Strength", m_From.Str.ToString());
DrawStat(340, attrY + 25, "Hit Points", m_From.Hits + " / " + m_From.HitsMax);
DrawStat(30, attrY + 50, "Dexterity", m_From.Dex.ToString());
DrawStat(340, attrY + 50, "Stamina", m_From.Stam + " / " + m_From.StamMax);
DrawStat(30, attrY + 75, "Intelligence", m_From.Int.ToString());
DrawStat(340, attrY + 75, "Mana", m_From.Mana + " / " + m_From.ManaMax);
// --- RESISTANCES ---
int resY = 175;
DrawDivider(20, resY - 5, width - 40);
AddLabel(30, resY + 5, C_YELLOW, "Resistances");
DrawResistBox(130, resY + 5, "Physical", m_From.PhysicalResistance, C_GREY);
DrawResistBox(230, resY + 5, "Fire", m_From.FireResistance, C_RED);
DrawResistBox(330, resY + 5, "Cold", m_From.ColdResistance, C_BLUE);
DrawResistBox(430, resY + 5, "Poison", m_From.PoisonResistance, C_GREEN);
DrawResistBox(530, resY + 5, "Energy", m_From.EnergyResistance, C_PURPLE);
// --- RATINGS (Combat & Magic) ---
int colY = 220;
DrawDivider(20, colY - 5, width - 40);
AddLabel(30, colY + 5, C_YELLOW, "Combat Ratings");
AddLabel(340, colY + 5, C_YELLOW, "Magic Ratings");
// AOS Fetches
int hci = AosAttributes.GetValue(m_From, AosAttribute.AttackChance);
int dci = AosAttributes.GetValue(m_From, AosAttribute.DefendChance);
int di = AosAttributes.GetValue(m_From, AosAttribute.WeaponDamage);
int ssi = AosAttributes.GetValue(m_From, AosAttribute.WeaponSpeed);
int sdi = AosAttributes.GetValue(m_From, AosAttribute.SpellDamage);
int lmc = AosAttributes.GetValue(m_From, AosAttribute.LowerManaCost);
int lrc = AosAttributes.GetValue(m_From, AosAttribute.LowerRegCost);
int fc = AosAttributes.GetValue(m_From, AosAttribute.CastSpeed);
int fcr = AosAttributes.GetValue(m_From, AosAttribute.CastRecovery);
// Left Side: Combat
DrawStat(30, colY + 30, "HCI", hci + "%");
DrawStat(30, colY + 50, "DCI", dci + "%");
DrawStat(30, colY + 70, "DI", di + "%");
DrawStat(30, colY + 90, "SSI", ssi + "%");
DrawStat(30, colY + 110, "LUCK", AosAttributes.GetValue(m_From, AosAttribute.Luck).ToString());
// Right Side: Magic
DrawStat(340, colY + 30, "SDI", sdi + "%");
DrawStat(340, colY + 50, "LRC", lrc + "%");
DrawStat(340, colY + 70, "FC", fc.ToString());
DrawStat(340, colY + 90, "FCR", fcr.ToString());
DrawStat(340, colY + 110, "LMC", lmc + "%");
// --- REGENERATION & MISC ---
int regenY = colY + 160;
AddLabel(30, regenY + 5, C_YELLOW, "Regenerations");
DrawStat(30, regenY + 30, "HP Regen", AosAttributes.GetValue(m_From, AosAttribute.RegenHits).ToString());
DrawStat(30, regenY + 50, "Stam Regen", AosAttributes.GetValue(m_From, AosAttribute.RegenStam).ToString());
DrawStat(30, regenY + 70, "Mana Regen", AosAttributes.GetValue(m_From, AosAttribute.RegenMana).ToString());
// Miscellaneous Section
AddLabel(340, regenY + 5, C_YELLOW, "Miscellaneous");
DrawStat(340, regenY + 30, "Fame", m_From.Fame.ToString());
DrawStat(340, regenY + 50, "Karma", m_From.Karma.ToString());
DrawStat(340, regenY + 70, "Weight", m_From.TotalWeight + " / " + m_From.MaxWeight);
// --- SKILL LIST ---
int skillY = regenY + 110;
DrawDivider(20, skillY - 5, width - 40);
AddLabel(30, skillY + 5, C_YELLOW, "Skills");
// 2-Column Logic
int count = 0;
int startX = 30;
int startY = skillY + 30;
int rowSpacing = 25;
int maxPerCol = 12;
for (int i = 0; i < m_From.Skills.Length; i++)
{
Skill sk = m_From.Skills[i];
// FIX: Only show if Base > 0 (Ignores Human 20.0 Passive)
if (sk.Base > 0)
{
int col = count / maxPerCol;
int row = count % maxPerCol;
if (col >= 2) break;
int xPos = (col == 0) ? startX : 340;
int yPos = startY + (row * rowSpacing);
string val = sk.Value.ToString("F1") + "/" + sk.Cap.ToString("F1");
AddLabel(xPos, yPos, C_WHITE, sk.Name);
AddLabel(xPos + 130, yPos, C_WHITE, val);
count++;
}
}
}
// --- HELPERS ---
private string ColorAndCenter(string color, string text)
{
return String.Format("<BASEFONT COLOR={0}><CENTER>{1}</CENTER></BASEFONT>", color, text);
}
private void DrawResistBox(int x, int y, string name, int val, int color)
{
AddLabel(x, y, C_WHITE, name);
AddLabel(x + 55, y, color, val + "%");
}
private void DrawStat(int x, int y, string name, string val)
{
AddLabel(x, y, C_WHITE, name);
AddLabel(x + 130, y, C_WHITE, val);
}
private void DrawDivider(int x, int y, int width)
{
AddImageTiled(x, y, width, 2, 9264);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (info.ButtonID == 1) // Refresh
{
m_From.SendGump(new PlayerStatsGump(m_From));
}
}
}
}