using Theriapolis.Core.Data;
using Theriapolis.Core.Entities;
using Theriapolis.Core.Items;
using Theriapolis.Core.Rules.Reputation;
using Theriapolis.Core.Time;
using Theriapolis.Core.World;
using Theriapolis.Core.World.Settlements;
namespace Theriapolis.Core.Rules.Quests;
///
/// Phase 6 M4 — read/write window the QuestEngine uses to evaluate
/// conditions and apply effects. Deliberately holds references rather
/// than copies so engine ticks see live state.
///
public sealed class QuestContext
{
public ContentResolver Content { get; }
public ActorManager Actors { get; }
public PlayerReputation Reputation { get; }
public Dictionary Flags { get; }
public AnchorRegistry Anchors { get; }
public WorldClock Clock { get; }
public WorldState World { get; }
public Rules.Character.Character? PlayerCharacter { get; set; }
/// Most recent dialogue node id reached, surfaced by InteractionScreen for the dialogue_choice condition.
public string LastDialogueNodeReached { get; set; } = "";
public QuestContext(ContentResolver content, ActorManager actors,
PlayerReputation rep, Dictionary flags,
AnchorRegistry anchors, WorldClock clock, WorldState world)
{
Content = content;
Actors = actors;
Reputation = rep;
Flags = flags;
Anchors = anchors;
Clock = clock;
World = world;
}
public bool HasItem(string itemId)
{
if (PlayerCharacter is null) return false;
foreach (var inst in PlayerCharacter.Inventory.Items)
if (string.Equals(inst.Def.Id, itemId, System.StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
///
/// Position of the live player actor in tactical-tile (= world-pixel)
/// space, or null if the actor isn't yet spawned.
///
public (int x, int y)? PlayerTacticalPos()
{
if (Actors.Player is null) return null;
return ((int)Actors.Player.Position.X, (int)Actors.Player.Position.Y);
}
///
/// World-tile Chebyshev distance from the player to the settlement
/// with the given id, or null if the player or settlement isn't
/// resolvable.
///
public int? PlayerDistanceToSettlement(int settlementId)
{
if (Actors.Player is null) return null;
Settlement? s = null;
foreach (var sx in World.Settlements)
if (sx.Id == settlementId) { s = sx; break; }
if (s is null) return null;
int playerWX = (int)Actors.Player.Position.X / C.WORLD_TILE_PIXELS;
int playerWY = (int)Actors.Player.Position.Y / C.WORLD_TILE_PIXELS;
int dx = System.Math.Abs(playerWX - s.TileX);
int dy = System.Math.Abs(playerWY - s.TileY);
return System.Math.Max(dx, dy);
}
}