namespace IdleSpectator;
public enum ActivityTerrain
{
Unknown,
Land,
Liquid
}
///
/// Snapshot of live actor facts for activity prose. Only observed fields - never invent events.
/// Species / taxonomy / flags come from for every unit in the game.
///
public sealed class ActivityContext
{
public string ActorName = "";
/// Raw actor asset id (frog, human, beetle, ...).
public string SpeciesId = "";
/// Recovered living/body source for meaningful transformed variants.
public string BaseSpeciesId = "";
/// Readable species word for prose (locale / asset id).
public string SpeciesLabel = "";
public string Family = ActivityVoiceFamilies.Default;
public string ModifierTag = "";
public ProseVoice Voice;
public string TaxonomicKingdom = "";
public string TaxonomicPhylum = "";
public string TaxonomicClass = "";
public string TaxonomicOrder = "";
public string TaxonomicFamily = "";
public string TaxonomicGenus = "";
public string TaxonomicSpecies = "";
public bool IsHumanoid;
public bool IsCiv;
/// From - animal tone when not civ humanoid.
public bool IsAnimal;
public int Age;
public bool IsChild;
public string JobId = "";
public string CityName = "";
public string KingdomName = "";
public bool IsKing;
public bool IsLeader;
public bool IsWarrior;
/// Observed role noun: king / leader / warrior when flags are true.
public string RoleLabel = "";
public string TargetName = "";
public bool TargetIsActor;
/// Building, city, kingdom, or soft place label for clauses.
public string PlaceLabel = "";
///
/// True when is a concrete building/object (bonfire, house, …).
/// False for settlements, realms, and soft places like "the wilds".
///
public bool PlaceIsObject;
/// Observed terrain under the actor when this snapshot was captured.
public ActivityTerrain Terrain;
public string CarryingLabel = "";
public bool InCombat;
public bool HasAttackTarget;
/// Observed trait id - salts prose variety only; never spelled in the activity line.
public string TopTraitId = "";
/// Humanized trait label for salt/debug - dossier chips show the trait to the player.
public string TopTraitLabel = "";
/// Locomotion / body manner from live taxonomy/flags (insect, amphibian, flying, ...).
public string MannerTag = "default";
public string TaskKey = "";
public static ActivityContext Empty { get; } = new ActivityContext();
/// Harness / ForceNote: minimal context; species resolved from live library when present.
public static ActivityContext ForHarness(
string actorName,
string targetName,
string speciesId = "",
string place = "",
string carrying = "",
string jobId = "",
string taskKey = "",
string traitId = "",
bool isChild = false,
bool inCombat = false,
bool isKing = false,
bool isLeader = false,
bool isWarrior = false,
ActivityTerrain terrain = ActivityTerrain.Unknown,
bool placeIsObject = false)
{
ActivityContext ctx = new ActivityContext
{
ActorName = actorName ?? "",
TargetName = targetName ?? "",
TargetIsActor = !string.IsNullOrEmpty(targetName),
SpeciesId = speciesId ?? "",
PlaceLabel = place ?? "",
PlaceIsObject = placeIsObject,
CarryingLabel = carrying ?? "",
JobId = jobId ?? "",
TaskKey = taskKey ?? "",
TopTraitId = traitId ?? "",
Terrain = terrain,
IsChild = isChild,
InCombat = inCombat,
HasAttackTarget = inCombat && !string.IsNullOrEmpty(targetName),
IsKing = isKing,
IsLeader = isLeader,
IsWarrior = isWarrior
};
ActorAsset asset = ActivityAssetCatalog.TryGetActorAsset(ctx.SpeciesId);
if (asset != null)
{
ActivityVoiceResolver.ApplyToContext(ctx, asset);
ctx.SpeciesLabel = ActivityAssetCatalog.SpeciesDisplayLabel(asset);
}
else
{
ctx.SpeciesLabel = ActivityAssetCatalog.SpeciesDisplayLabel(ctx.SpeciesId);
ctx.Voice = ActivityVoiceResolver.Resolve(ctx.SpeciesId);
ctx.BaseSpeciesId = ctx.Voice.BaseSpeciesId;
ctx.Family = ctx.Voice.BaseFamily;
ctx.MannerTag = ActivityVoiceResolver.TagName(ctx.Voice.EffectiveActionTag);
ctx.ModifierTag = ActivityVoiceResolver.ModifierName(ctx.Voice.Modifier);
ctx.IsCiv = ctx.Voice.BaseIsCiv;
ctx.IsHumanoid = ctx.Voice.BaseIsHumanoid;
ctx.IsAnimal = ctx.Voice.BaseIsAnimal;
}
if (!string.IsNullOrEmpty(taskKey)
&& taskKey.StartsWith("child_", System.StringComparison.OrdinalIgnoreCase))
{
ctx.IsChild = true;
}
// Strip species-like place labels the same way live BuildContext does.
if (!string.IsNullOrEmpty(ctx.PlaceLabel)
&& ActivityInterestTable.LooksLikeSpeciesPublic(ctx.PlaceLabel, ctx.SpeciesId))
{
ctx.PlaceLabel = "";
ctx.PlaceIsObject = false;
}
ctx.RoleLabel = ActivityInterestTable.DeriveRoleLabel(ctx.IsKing, ctx.IsLeader, ctx.IsWarrior);
ctx.TopTraitLabel = ActivityInterestTable.TraitLabelFromId(ctx.TopTraitId);
return ctx;
}
}