fix(combat): restore retail combat bar controls
Resolve authored StringInfo labels from local.dat, port gmCombatUI's runtime option captions and checkbox widgets, and bind horizontal scrollbar media by retail structural roles so the green power jewel is a thumb instead of a tiled track. Persist the three combat options and make Auto Target govern target acquisition. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
2215c76c7e
commit
927fa7881a
19 changed files with 24591 additions and 48 deletions
65
src/AcDream.App/UI/Layout/DatStringResolver.cs
Normal file
65
src/AcDream.App/UI/Layout/DatStringResolver.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
using DatReaderWriter;
|
||||
using DatReaderWriter.DBObjs;
|
||||
|
||||
namespace AcDream.App.UI.Layout;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves retail <c>StringInfo</c> values through local.dat string tables.
|
||||
/// The caller owns synchronization around <see cref="DatCollection"/> reads.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Retail reference: <c>StringInfo::GetString</c> and
|
||||
/// <c>compute_str_hash @ 0x00413110</c>. A StringInfo's token selects one
|
||||
/// localized string variant; ordinary UI labels use token zero.
|
||||
/// </remarks>
|
||||
public sealed class DatStringResolver
|
||||
{
|
||||
private readonly DatCollection _dats;
|
||||
private readonly Dictionary<uint, StringTable?> _tables = new();
|
||||
|
||||
public DatStringResolver(DatCollection dats)
|
||||
=> _dats = dats ?? throw new ArgumentNullException(nameof(dats));
|
||||
|
||||
public string? Resolve(UiStringInfoValue info)
|
||||
=> Resolve(info.TableId, info.StringId, info.Token);
|
||||
|
||||
public string? Resolve(uint tableId, uint stringId, int token = 0)
|
||||
{
|
||||
if (tableId == 0u || stringId == 0u)
|
||||
return null;
|
||||
|
||||
if (!_tables.TryGetValue(tableId, out StringTable? table))
|
||||
{
|
||||
table = _dats.Get<StringTable>(tableId);
|
||||
_tables[tableId] = table;
|
||||
}
|
||||
|
||||
if (table is null
|
||||
|| !table.Strings.TryGetValue(stringId, out var entry)
|
||||
|| entry.Strings.Count == 0)
|
||||
return null;
|
||||
|
||||
int index = token >= 0 && token < entry.Strings.Count ? token : 0;
|
||||
return entry.Strings[index].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exact retail ELF-style string hash used for StringInfo keys.
|
||||
/// Ported line-for-line from <c>compute_str_hash @ 0x00413110</c>.
|
||||
/// </summary>
|
||||
public static uint ComputeHash(string value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
uint result = 0u;
|
||||
foreach (char c in value)
|
||||
{
|
||||
result = unchecked((result << 4) + (byte)c);
|
||||
uint high = result & 0xF0000000u;
|
||||
if (high != 0u)
|
||||
result = ((high >> 24) ^ result) & 0x0FFFFFFFu;
|
||||
}
|
||||
|
||||
return result == uint.MaxValue ? uint.MaxValue - 1u : result;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue