using NeonSprawl.Server.Game.Quests;
namespace NeonSprawl.Server.Game.Factions;
///
/// Evaluates minimum-standing gates (NEO-137).
/// Quest accept wiring: .
/// NEO-141 telemetry hook site: deny return paths below.
///
public static class FactionGateOperations
{
///
/// All rules must pass (AND). Empty rules succeed immediately.
/// Compares player standing vs with standing >= minStanding.
///
public static FactionGateEvaluateOutcome TryEvaluate(
string playerId,
IReadOnlyList rules,
IFactionStandingStore standingStore)
{
var normalizedPlayerId = FactionStandingIds.NormalizePlayerId(playerId);
if (rules.Count == 0)
{
return Success();
}
foreach (var rule in rules)
{
var factionId = FactionStandingIds.NormalizeFactionId(rule.FactionId);
var read = standingStore.TryGetStanding(normalizedPlayerId, factionId);
if (!read.Success)
{
// --- Telemetry hook site (NEO-141): future E9.M1 catalog event `faction_gate_blocked` ---
// TODO(E9.M1): catalog emit — ops reasonCode (e.g. unknown_faction), playerId, factionId, minStanding, currentStanding (null).
// No ingest or ILogger here (comments-only).
return Deny(read.ReasonCode, factionId, rule.MinStanding, null);
}
if (read.Standing < rule.MinStanding)
{
// --- Telemetry hook site (NEO-141): future E9.M1 catalog event `faction_gate_blocked` ---
// TODO(E9.M1): catalog emit — ops reasonCode (gate_blocked), playerId, factionId, minStanding, currentStanding.
// No ingest or ILogger here (comments-only).
return Deny(
FactionGateEvaluateReasonCodes.GateBlocked,
factionId,
rule.MinStanding,
read.Standing);
}
}
return Success();
}
private static FactionGateEvaluateOutcome Success() =>
new(true, null, null, null, null);
private static FactionGateEvaluateOutcome Deny(
string? reasonCode,
string factionId,
int minStanding,
int? currentStanding) =>
new(false, reasonCode, factionId, minStanding, currentStanding);
}