aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/src/Godosa.Core/Runs/Scripts/RunGame.cs
blob: a6222a65cff94a58218bda3f82c595e4eb36a065 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Provenance: own design — shared run scripts (spec §6; one hook shape for §4.2 capabilities, see Actions)
namespace Godosa.Core.Runs.Scripts;

/// <summary>A game's run-script adapter. <see cref="Actions"/> holds the lib's game-hooked verbs by their lib name
/// (<c>talk</c>, <c>walk-to</c>, <c>cheat</c>, …) and the game's own verbs. Player-kind actions return input plans only;
/// the lib injects them.</summary>
public interface IRunGame
{
    string Name { get; }
    string ContentVersion { get; }
    IInputRouter Input { get; }
    IReadOnlyDictionary<string, IProbe> Probes { get; }
    IReadOnlyDictionary<string, long> Constants { get; }
    IReadOnlyDictionary<string, ILocator> Locators { get; }
    IReadOnlyDictionary<string, IRunAction> Actions { get; }
    IRunRng? Rng { get; }
    bool SupportsSnapshot { get; }
    byte[] SnapshotSave();
    /// <summary>Why the current state can't be checkpointed faithfully (e.g. state the snapshot doesn't hold), or null.
    /// A refused checkpoint is not cached (warning); failure snapshots are still taken.</summary>
    string? SnapshotRefusal() => null;
    void SnapshotRestore(byte[] data);
    /// <summary>The restore completes after this frame (a window rebuilds its game view): the runner pauses one frame
    /// (<see cref="ScriptRunner.Restoring"/>), in which the host advances no game frame.</summary>
    bool RestoreDeferred => false;
    ulong Digest();
    string Dump();
    void Advance();
}

public interface IProbe
{
    int MinArgs { get; }
    int MaxArgs { get; }
    RunValue Eval(IReadOnlyList<string> args);
}

public readonly record struct LocatorResult(int X, int Y, string? Error)
{
    public static LocatorResult Ok(int x, int y) => new(x, y, null);
    public static LocatorResult Fail(string message) => new(0, 0, message);
    public bool IsOk => Error == null;
}

/// <summary>Finds where to aim (virtual-screen position) from game state, as a player reads the screen.</summary>
public interface ILocator
{
    LocatorResult Locate(IReadOnlyList<string> args);
}

/// <summary>Begin returns an input plan to inject (player) and/or an immediate status (debug: usually Done); after the
/// plan is sent, Poll runs each frame until Done or Fault.</summary>
public interface IRunAction
{
    VerbKind Kind { get; }
    int MinArgs { get; }
    int MaxArgs { get; }
    ActionStart Begin(IReadOnlyList<string> args);
    StepStatus Poll();
}

public sealed record ActionStart(InputPlan? Plan = null, StepStatus? Status = null);

public interface IRunRng
{
    void Seed(long seed);
    void ForceNext(string kind, long value);
}