Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -770,8 +770,12 @@ public static StPacket GenerateStatInfo(this PlayerComponentBundle player)
VisualId = player.VisualId,
Level = player.Level,
HeroLvl = player.HeroLevel,
HpPercentage = (int)(player.Hp / (float)player.MaxHp * 100),
MpPercentage = (int)(player.Mp / (float)player.MaxMp * 100),
// Guarded the way the rest of the file guards it. A maximum of zero is not a
// state the game reaches today, but the division is on floats: it does not
// throw, it yields NaN, and the cast then puts a meaningless number in the two
// fields the client draws as the health and mana bars.
HpPercentage = player.MaxHp > 0 ? (int)(player.Hp / (float)player.MaxHp * 100) : 100,
MpPercentage = player.MaxMp > 0 ? (int)(player.Mp / (float)player.MaxMp * 100) : 100,
CurrentHp = player.Hp,
CurrentMp = player.Mp,
MaxHp = player.MaxHp,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// __ _ __ __ ___ __ ___ ___
// | \| |/__\ /' _/ / _//__\| _ \ __|
// | | ' | \/ |`._`.| \_| \/ | v / _|
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
//

using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NosCore.GameObject.Ecs.Extensions;
using NosCore.GameObject.Networking.ClientSession;
using NosCore.Tests.Shared;

namespace NosCore.GameObject.Tests.Ecs.Extensions
{
// The two percentages in `st` are the health and mana bars the client draws.
//
// Every other place that computes them guards the maximum first; GenerateStatInfo was the one
// that did not. It never threw and never would: the division is on floats, so a maximum of
// zero yields NaN and the cast puts a meaningless number in the packet. Nothing in a log, and
// a bar that reads as whatever that number happened to be.
[TestClass]
public class StatInfoPercentageTests
{
private ClientSession _session = null!;

[TestInitialize]
public async Task SetupAsync()
{
await TestHelpers.ResetAsync();
_session = await TestHelpers.Instance.GenerateSessionAsync();
}

[TestMethod]
public void WithARealMaximumThePercentagesAreTheOrdinaryOnes()
{
_session.Character.MaxHp = 1000;
_session.Character.Hp = 250;
_session.Character.MaxMp = 400;
_session.Character.Mp = 400;

var packet = _session.Character.GenerateStatInfo();

Assert.AreEqual(25, packet.HpPercentage);
Assert.AreEqual(100, packet.MpPercentage);
}

[TestMethod]
public void AZeroMaximumDoesNotPutNonsenseInTheBar()
{
_session.Character.MaxHp = 0;
_session.Character.Hp = 0;
_session.Character.MaxMp = 0;
_session.Character.Mp = 0;

var packet = _session.Character.GenerateStatInfo();

// The value matters less than the fact that it is a value: unguarded, the cast of a
// NaN gives whatever the platform gives, and the assertion below would be a coin toss.
Assert.AreEqual(100, packet.HpPercentage);
Assert.AreEqual(100, packet.MpPercentage);
}

// The same packet built by the same call for the same character has to agree with the
// guarded computation the rest of the file uses.
[TestMethod]
public void ItAgreesWithTheGuardedComputationElsewhere()
{
_session.Character.MaxHp = 777;
_session.Character.Hp = 111;

var packet = _session.Character.GenerateStatInfo();

Assert.AreEqual((int)(111 / 777f * 100), packet.HpPercentage);
}
}
}
Loading