75 lines
2.5 KiB
C#
75 lines
2.5 KiB
C#
|
|
namespace Theriapolis.Core.Rules.Reputation;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Phase 6 M2 — append-only event log surfaced by the reputation screen
|
||
|
|
/// ("why does so-and-so hate me?"). Bounded to a reasonable tail so the
|
||
|
|
/// save file stays small even after a 100-hour playthrough.
|
||
|
|
///
|
||
|
|
/// Phase 6 M5 layers propagation on top: each entry will be re-walked
|
||
|
|
/// per game-day to fan out into other settlements with distance/time
|
||
|
|
/// decay.
|
||
|
|
/// </summary>
|
||
|
|
public sealed class RepLedger
|
||
|
|
{
|
||
|
|
public const int MaxEntries = 256;
|
||
|
|
|
||
|
|
private readonly List<RepEvent> _entries = new();
|
||
|
|
private int _nextSeq = 1;
|
||
|
|
|
||
|
|
public IReadOnlyList<RepEvent> Entries => _entries;
|
||
|
|
public int Count => _entries.Count;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Append <paramref name="ev"/> to the ledger. If <see cref="RepEvent.SequenceId"/>
|
||
|
|
/// is 0, a fresh monotone id is assigned; otherwise the supplied id
|
||
|
|
/// is preserved (used by the save-restore path).
|
||
|
|
/// </summary>
|
||
|
|
public RepEvent Append(RepEvent ev)
|
||
|
|
{
|
||
|
|
if (ev.SequenceId == 0)
|
||
|
|
ev = ev with { SequenceId = _nextSeq++ };
|
||
|
|
else if (ev.SequenceId >= _nextSeq)
|
||
|
|
_nextSeq = ev.SequenceId + 1;
|
||
|
|
_entries.Add(ev);
|
||
|
|
if (_entries.Count > MaxEntries) _entries.RemoveAt(0);
|
||
|
|
return ev;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Clear()
|
||
|
|
{
|
||
|
|
_entries.Clear();
|
||
|
|
_nextSeq = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>Largest <see cref="RepEvent.SequenceId"/> issued so far. 0 = empty ledger.</summary>
|
||
|
|
public int HighestSequenceId => _nextSeq - 1;
|
||
|
|
|
||
|
|
/// <summary>Most recent N events affecting <paramref name="factionId"/>.</summary>
|
||
|
|
public IEnumerable<RepEvent> ForFaction(string factionId, int count = 8)
|
||
|
|
{
|
||
|
|
int yielded = 0;
|
||
|
|
for (int i = _entries.Count - 1; i >= 0 && yielded < count; i--)
|
||
|
|
{
|
||
|
|
if (string.Equals(_entries[i].FactionId, factionId, System.StringComparison.OrdinalIgnoreCase))
|
||
|
|
{
|
||
|
|
yielded++;
|
||
|
|
yield return _entries[i];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>Most recent N events affecting <paramref name="roleTag"/>.</summary>
|
||
|
|
public IEnumerable<RepEvent> ForRole(string roleTag, int count = 8)
|
||
|
|
{
|
||
|
|
int yielded = 0;
|
||
|
|
for (int i = _entries.Count - 1; i >= 0 && yielded < count; i--)
|
||
|
|
{
|
||
|
|
if (string.Equals(_entries[i].RoleTag, roleTag, System.StringComparison.OrdinalIgnoreCase))
|
||
|
|
{
|
||
|
|
yielded++;
|
||
|
|
yield return _entries[i];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|