Extract reset, selection, entered-world, and route construction behind LiveSessionHost while preserving the sole LiveSessionController authority. Retain partial route and subscription cleanup for retry, and replace the embedded ACE-only shortcut with the exact named-retail unsigned skill formula. Co-authored-by: Codex <codex@openai.com>
72 lines
2.2 KiB
C#
72 lines
2.2 KiB
C#
using DatReaderWriter.DBObjs;
|
|
using DatReaderWriter.Types;
|
|
|
|
namespace AcDream.App.Net;
|
|
|
|
/// <summary>
|
|
/// Exact unsigned formula used by retail <c>SkillFormula::Calculate @
|
|
/// 0x00591960</c>. DAT reader fields are signed storage views, so their bits
|
|
/// are deliberately reinterpreted as retail's unsigned W/X/Y/Z words.
|
|
/// </summary>
|
|
internal static class RetailSkillFormula
|
|
{
|
|
public static bool TryCalculate(
|
|
SkillFormula formula,
|
|
uint attribute1,
|
|
uint attribute2,
|
|
out uint result)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(formula);
|
|
|
|
uint divisor = unchecked((uint)formula.Divisor);
|
|
if (divisor == 0u)
|
|
{
|
|
result = 0u;
|
|
return false;
|
|
}
|
|
|
|
uint x = unchecked((uint)formula.Attribute1Multiplier);
|
|
uint y = unchecked((uint)formula.Attribute2Multiplier);
|
|
uint w = unchecked((uint)formula.AdditiveBonus);
|
|
uint numerator = unchecked(x * attribute1 + y * attribute2 + w);
|
|
result = (uint)Math.Floor((double)numerator / divisor + 0.5d);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Named live-session resolver for the attribute contribution to one skill.
|
|
/// Table lookup and missing-property policy stay separate from retail math.
|
|
/// </summary>
|
|
internal sealed class LiveSkillCreditResolver(SkillTable? skillTable)
|
|
{
|
|
public uint Resolve(
|
|
uint skillId,
|
|
IReadOnlyDictionary<uint, uint> attributeCurrents)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(attributeCurrents);
|
|
|
|
if (skillTable?.Skills is null
|
|
|| !skillTable.Skills.TryGetValue(
|
|
(DatReaderWriter.Enums.SkillId)skillId,
|
|
out var skillBase))
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
SkillFormula formula = skillBase.Formula;
|
|
attributeCurrents.TryGetValue(
|
|
(uint)formula.Attribute1,
|
|
out uint attribute1);
|
|
attributeCurrents.TryGetValue(
|
|
(uint)formula.Attribute2,
|
|
out uint attribute2);
|
|
return RetailSkillFormula.TryCalculate(
|
|
formula,
|
|
attribute1,
|
|
attribute2,
|
|
out uint result)
|
|
? result
|
|
: 0u;
|
|
}
|
|
}
|