fix(ui): night-round review — F11/F13/F14/F15 one-liners
F11: logs when a Map tab town-marker's template resolves to something other than a UiButton — that path previously silently skipped the TooltipText write with no diagnostic, leaving a mounted-but-empty tooltip popup indistinguishable from "no template configured". F13: RetailSkillFormula.FormatFormula now reads Attribute1Multiplier/ Attribute2Multiplier/AdditiveBonus/Divisor through the SAME unsigned reinterpretation TryCalculate already uses (this class's own doc comment already stated the invariant; FormatFormula just didn't follow it). A high-bit-set value would previously both mis-gate hasAttr1/ hasAttr2 and print a negative number, out of sync with what TryCalculate actually computes with for the same formula. Added regression tests, empirically verified to fail without the fix. F14: documented the RefreshHouseMarker gap rather than guessing at the byte-decode — Position::get_outside_cell_id @0x004527b0 is itself BN-mangled (its `(eax_2 - eax_2) & objcell_id` return is the same decompiler-obscures-a-real-conditional artifact class this round hit elsewhere) and depends on LandDefs::adjust_to_outside, a genuinely larger port than this round's other findings. HousePosition is wired () => null in production today (ISSUES #413's remaining scope), so this method is currently unreachable; left a TODO citing the retail call chain for whenever that lands. F15: fixed RefreshCoordinatesAndPlayerMarker's gate to AND-on-both- present, matching gmMapUI::Update @0x004a2078's exact `if (m_pCoordinateText != 0 && m_pPlayerLocationIcon != 0)` condition. The prior `_coordinateText is null && _playerIcon is null` check only skipped when BOTH were absent (proceeding whenever EITHER was present), letting coordinate text and the player marker update independently instead of as the single gated unit retail treats them as. Added a regression test (player-icon template resolution failure must also skip the coordinate-text write), empirically verified to fail without the fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
c403f57815
commit
0b0c7aa485
4 changed files with 172 additions and 18 deletions
|
|
@ -130,10 +130,24 @@ internal static class RetailSkillFormula
|
|||
{
|
||||
ArgumentNullException.ThrowIfNull(formula);
|
||||
|
||||
bool hasAttr1 = formula.Attribute1Multiplier >= 1
|
||||
&& formula.Attribute1 != 0;
|
||||
bool hasAttr2 = formula.Attribute2Multiplier >= 1
|
||||
&& formula.Attribute2 != 0;
|
||||
// F13 (night-round review): read the SAME unsigned reinterpretation
|
||||
// TryCalculate above uses — this class's own doc comment already
|
||||
// states the invariant ("DAT reader fields are signed storage
|
||||
// views... deliberately reinterpreted as retail's unsigned W/X/Y/Z
|
||||
// words") but this method previously read the raw signed int
|
||||
// fields directly. A high-bit-set multiplier/divisor/bonus would
|
||||
// both mis-gate hasAttr1/hasAttr2 (reads negative, failing the
|
||||
// >= 1 check TryCalculate's unsigned reinterpretation would have
|
||||
// passed) and print the wrong (negative) number — out of sync with
|
||||
// the value TryCalculate actually computes with for the SAME
|
||||
// formula.
|
||||
uint x = unchecked((uint)formula.Attribute1Multiplier);
|
||||
uint y = unchecked((uint)formula.Attribute2Multiplier);
|
||||
uint w = unchecked((uint)formula.AdditiveBonus);
|
||||
uint divisor = unchecked((uint)formula.Divisor);
|
||||
|
||||
bool hasAttr1 = x >= 1 && formula.Attribute1 != 0;
|
||||
bool hasAttr2 = y >= 1 && formula.Attribute2 != 0;
|
||||
if (!hasAttr1 && !hasAttr2)
|
||||
return null;
|
||||
|
||||
|
|
@ -144,9 +158,9 @@ internal static class RetailSkillFormula
|
|||
if (hasAttr1)
|
||||
{
|
||||
string name1 = AttributeName(formula.Attribute1);
|
||||
text.Append(formula.Attribute1Multiplier <= 1
|
||||
text.Append(x <= 1
|
||||
? name1
|
||||
: $"({formula.Attribute1Multiplier} x {name1})");
|
||||
: $"({x} x {name1})");
|
||||
if (hasAttr2)
|
||||
text.Append(" + ");
|
||||
}
|
||||
|
|
@ -154,17 +168,17 @@ internal static class RetailSkillFormula
|
|||
if (hasAttr2)
|
||||
{
|
||||
string name2 = AttributeName(formula.Attribute2);
|
||||
text.Append(formula.Attribute2Multiplier <= 1
|
||||
text.Append(y <= 1
|
||||
? name2
|
||||
: $"({formula.Attribute2Multiplier} x {name2})");
|
||||
: $"({y} x {name2})");
|
||||
}
|
||||
|
||||
if (hasAttr1 && hasAttr2)
|
||||
text.Append(')');
|
||||
if (formula.Divisor != 1)
|
||||
text.Append($" / {formula.Divisor}");
|
||||
if (formula.AdditiveBonus != 0)
|
||||
text.Append($"+{formula.AdditiveBonus}");
|
||||
if (divisor != 1)
|
||||
text.Append($" / {divisor}");
|
||||
if (w != 0)
|
||||
text.Append($"+{w}");
|
||||
text.Append(" )");
|
||||
return text.ToString();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue