pqw: import and export web saves

A .pqw file is what Progress Quest web's roster page downloads: base64
of one character's JSON. pqcli.pqw converts between that and Player,
keeping the generator state, so a character carries on exactly as it
would have where it came from. Saves from before 2022, which were not
UTF-8, are read as Latin-1, and upstream's two spell renames are merged
the way its loader does. Online realm fields are dropped with a
warning.

The upstream tests check both directions against the real JS: a save
made by upstream, at a task boundary or mid-task, is imported and
played on for 3000 tasks next to upstream; then the same the other way.
This commit is contained in:
Dash committed 2026-10-17 15:56:02 +02:00
1 parent fced929d77
commit 0beb550548
5 files changed
+586 -4

No files matched your search

+12
View File
@@ -146,6 +146,10 @@ def play(
data: GameData, spec: dict[str, Any], ticks: int, tasks: int
) -> list[dict[str, Any]]:
"""Play pqcli the way the harness plays upstream: 100 ms ticks."""
return run(new_simulation(data, spec), ticks, tasks)
def new_simulation(data: GameData, spec: dict[str, Any]) -> Simulation:
race = next(race for race in data.races if race.name == spec["race"])
class_ = next(c for c in data.classes if c.name == spec["class"])
seed = cast(RngState, tuple(spec["seed"]))
@@ -159,6 +163,14 @@ def play(
)
simulation = Simulation(player, data)
simulation.tick(0) # sets up the Prologue, as upstream's sold() does
return simulation
def run(
simulation: Simulation, ticks: int, tasks: int
) -> list[dict[str, Any]]:
"""Keep playing in 100 ms ticks, snapshotting after each task."""
player = simulation.player
snapshots = []
for _ in range(ticks):
completing = player.task_bar.done