feat(player): port retail augmentation stat chain
This commit is contained in:
parent
0cb60d98a0
commit
461a1fb7b4
22 changed files with 953 additions and 138 deletions
|
|
@ -110,7 +110,11 @@ public static class CharacterStatController
|
|||
/// <summary>Row highlight color — semi-translucent gold, matches retail
|
||||
/// UIStateId.Highlight (0x06) sprite 0x06001397 visual intent.</summary>
|
||||
private static readonly Vector4 HighlightBg = new(1f, 0.75f, 0.2f, 0.25f);
|
||||
private static readonly Vector4 BuffedSkillGreen = new(0.55f, 1f, 0.55f, 1f);
|
||||
// LayoutDesc 0x2100002E, FooterTitle 0x1000024E property 0x1B:
|
||||
// [0]=white, [1]=green, [2]=red, [3]=light blue (#7FFFFF).
|
||||
private static readonly Vector4 RetailBuffGreen = new(0f, 1f, 0f, 1f);
|
||||
private static readonly Vector4 RetailDebuffRed = new(1f, 0f, 0f, 1f);
|
||||
private static readonly Vector4 RetailVitaeBlue = new(127f / 255f, 1f, 1f, 1f);
|
||||
|
||||
// ── Row layout constants ─────────────────────────────────────────────────
|
||||
// RowHeight 22px + IconSize 16px: retail spec (2026-06-26) says icons ~icon-height
|
||||
|
|
@ -688,7 +692,8 @@ public static class CharacterStatController
|
|||
_ => 0,
|
||||
};
|
||||
return v.ToString();
|
||||
});
|
||||
},
|
||||
valueColorProvider: () => AttributeValueColor(data(), rowIndex));
|
||||
|
||||
row.OnClick = () =>
|
||||
{
|
||||
|
|
@ -719,7 +724,8 @@ public static class CharacterStatController
|
|||
2 => $"{s.ManaCurrent}/{s.ManaMax}",
|
||||
_ => string.Empty,
|
||||
};
|
||||
});
|
||||
},
|
||||
valueColorProvider: () => VitalValueColor(data(), rowIndex));
|
||||
|
||||
row.OnClick = () =>
|
||||
{
|
||||
|
|
@ -872,10 +878,48 @@ public static class CharacterStatController
|
|||
return null;
|
||||
}
|
||||
|
||||
private static Vector4 SkillValueColor(CharacterSkill skill)
|
||||
=> skill.CurrentLevel > skill.BaseLevel ? BuffedSkillGreen
|
||||
: skill.CurrentLevel < skill.BaseLevel ? new Vector4(1f, 0.45f, 0.45f, 1f)
|
||||
internal static Vector4 SkillValueColor(CharacterSkill skill)
|
||||
{
|
||||
int withoutVitae = skill.CurrentLevel - skill.VitaeModifier;
|
||||
return withoutVitae > skill.BaseLevel ? RetailBuffGreen
|
||||
: withoutVitae < skill.BaseLevel ? RetailDebuffRed
|
||||
: Vector4.One;
|
||||
}
|
||||
|
||||
internal static Vector4 AttributeValueColor(
|
||||
CharacterSheet sheet,
|
||||
int rowIndex)
|
||||
{
|
||||
int delta = GetAttributeDelta(sheet, rowIndex);
|
||||
return delta > 0 ? RetailBuffGreen
|
||||
: delta < 0 ? RetailDebuffRed
|
||||
: Vector4.One;
|
||||
}
|
||||
|
||||
internal static Vector4 VitalValueColor(
|
||||
CharacterSheet sheet,
|
||||
int vitalIndex)
|
||||
{
|
||||
if ((uint)vitalIndex >= 3u
|
||||
|| vitalIndex >= sheet.VitalBaseMaxValues.Length
|
||||
|| vitalIndex >= sheet.VitalVitaeModifiers.Length)
|
||||
{
|
||||
return Vector4.One;
|
||||
}
|
||||
|
||||
int effective = vitalIndex switch
|
||||
{
|
||||
0 => sheet.HealthMax,
|
||||
1 => sheet.StaminaMax,
|
||||
2 => sheet.ManaMax,
|
||||
_ => 0,
|
||||
};
|
||||
int withoutVitae = effective - sheet.VitalVitaeModifiers[vitalIndex];
|
||||
int baseline = sheet.VitalBaseMaxValues[vitalIndex];
|
||||
return withoutVitae > baseline ? RetailBuffGreen
|
||||
: withoutVitae < baseline ? RetailDebuffRed
|
||||
: Vector4.One;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles a row click: toggle (same row → deselect), else select new row.
|
||||
|
|
@ -1315,6 +1359,64 @@ public static class CharacterStatController
|
|||
return $"{name}: {value}{delta}";
|
||||
}
|
||||
|
||||
private static IReadOnlyList<UiText.TextRun> BuildSelectedTitleRuns(
|
||||
UiText target,
|
||||
CharacterStatTab tab,
|
||||
Func<CharacterSheet> data,
|
||||
int[] attrSel,
|
||||
int[] skillSel)
|
||||
{
|
||||
Vector4 Color(int index) =>
|
||||
index >= 0 && index < target.FontColorPalette.Count
|
||||
? target.FontColorPalette[index]
|
||||
: index switch
|
||||
{
|
||||
1 => RetailBuffGreen,
|
||||
2 => RetailDebuffRed,
|
||||
3 => RetailVitaeBlue,
|
||||
_ => Vector4.One,
|
||||
};
|
||||
|
||||
if (tab == CharacterStatTab.Skills)
|
||||
{
|
||||
CharacterSkill? skill = SkillAtDisplayIndex(data(), skillSel[0]);
|
||||
if (skill is null)
|
||||
return [new("Select a Skill to Improve", Body)];
|
||||
if (skill.AdvancementClass < CharacterSkillAdvancementClass.Trained)
|
||||
return [new(skill.Name, Color(0))];
|
||||
|
||||
var runs = new List<UiText.TextRun>
|
||||
{
|
||||
new($"{skill.Name}: {skill.CurrentLevel}", Color(0)),
|
||||
};
|
||||
if (skill.VitaeModifier < 0)
|
||||
runs.Add(new(FormatVitaeDelta(skill.VitaeModifier), Color(3)));
|
||||
int buffDelta = GetSkillBuffOnlyDelta(skill);
|
||||
if (buffDelta != 0)
|
||||
runs.Add(new(
|
||||
FormatBuffDelta(buffDelta),
|
||||
Color(buffDelta > 0 ? 1 : 2)));
|
||||
return runs;
|
||||
}
|
||||
|
||||
if (attrSel[0] < 0)
|
||||
return [new("Select an Attribute to Improve", Body)];
|
||||
|
||||
CharacterSheet sheet = data();
|
||||
var attributeRuns = new List<UiText.TextRun>
|
||||
{
|
||||
new(
|
||||
$"{GetRowName(attrSel[0])}: {GetRowValueString(sheet, attrSel[0])}",
|
||||
Color(0)),
|
||||
};
|
||||
int delta = GetAttributeDelta(sheet, attrSel[0]);
|
||||
if (delta != 0)
|
||||
attributeRuns.Add(new(
|
||||
FormatBuffDelta(delta),
|
||||
Color(delta > 0 ? 1 : 2)));
|
||||
return attributeRuns;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a single attribute/vital row to <paramref name="list"/> as a
|
||||
/// <see cref="UiClickablePanel"/> containing icon + name + value children.
|
||||
|
|
@ -1512,6 +1614,12 @@ public static class CharacterStatController
|
|||
// Centered=true comes from the dat (HJustify=Center) via BuildText — not overridden here.
|
||||
// RightAligned stays false (BuildText default for a Center element).
|
||||
titleEl.ClickThrough = true;
|
||||
titleEl.RunsProvider = () => BuildSelectedTitleRuns(
|
||||
titleEl,
|
||||
activeTab[0],
|
||||
data,
|
||||
attrSel,
|
||||
skillSel);
|
||||
titleEl.LinesProvider = () =>
|
||||
{
|
||||
string title = BuildSelectedTitleText(activeTab[0], data, attrSel, skillSel);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue