Skip to content

Graphical field in RPG Maker proportions, map kinds and NPC facing - #96

Open
amasiye wants to merge 113 commits into
mainfrom
develop
Open

amasiye wants to merge 113 commits into
mainfrom
develop

Conversation

@amasiye

@amasiye amasiye commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Brings main up to develop.

Graphical field in RPG Maker proportions

  • Maps draw from RPG Maker tilesets and tile layers; each terminal cell is one square 48 px tile, with autotiles composed per cell.
  • Tilesets define the pieces maps are built from, including connected pieces such as walls; tile layers can name the gameplay layer they move with, and a glyph is hidden only under tiles of its own layer.
  • Field characters use RPG Maker character sheets and are lifted 6 px above their cell as RPG Maker does (object ! sheets are not lifted).
  • Held walking with characters sliding between cells, for renderers that report key transitions.
  • Tilesets are grouped by the kind of setting they draw (World, Exterior, Interior, Dungeon); every map has a kind that names its tileset.

Field behaviour

  • A talked-to NPC turns to face the player and turns back when the conversation ends, unless it has a direction fix.
  • Saved positions migrate through declarative map shifts.
  • Console writes past the screen's side edges are clipped instead of clamped.
  • On the graphical field, what reaching a cell does (touch events, encounters, the save point notice, movement observers) waits until the step has slid into the cell, as RPG Maker does, so a modal never cuts the slide short. The terminal and reduced motion arrive at once, as before.

Plans

  • The effect animation plan now covers field effects: map-owned ambient effects (save point energy, torches, the planned graphical cues) and object effects, anchored to cells or objects, looping with the map and drawn behind or in front of characters, in the same unified timeline.

Earlier work on develop

  • Retained presentation replacing stateless native frames, field zoom and graphical NPC sprites.
  • Layered maps with per-layer collision; executable map grids refused.
  • The two-column cell conversion and its revert.
  • Voice-aware dialogue Auto, owned speech playback and independent voice volume.
  • Stable actor identity, and removal of display-name and filename aliases.
  • Many fixes to startup, storage, settings and battle presentation.

Breaking changes are marked ! in the commits: the field cell geometry, composed autotiles, square tiles, retained presentation, literal map nowdocs and getFromPng factories.

eb5e19e removed the automatic window_activation subscription for title animation and rolling credits while decoupling graphical presentation from startup requirements. These surfaces now continue playback on focus loss in normal launches. Scene/modal/suspension pause and explicit subscriptions remain.

Correct the roadmap and changelog, and require named removal reporting. Optional advertised-then-requested restoration is proposed only; no runtime behaviour is changed here. The earlier typo-bearing subject is clarified by this forward record, without rewriting history.
Remove CanvasNineSlice::fromPng and migrate Engine callers, tests and documentation to getFromPng, matching BattlerArtwork. Image loading behaviour is unchanged. Replace the G2 roadmap en dash with an ASCII hyphen.

BREAKING CHANGE: CanvasNineSlice::fromPng has been removed; use CanvasNineSlice::getFromPng with the same arguments.
Share static grid parsing with the Editor and validate both grid files before loading map data. Remove executable, interpolated and string-array grid support; preserve literal content without evaluating it.
Add optional animation IDs while retaining legacy defaults and old save compatibility. Rehydrate saved item bindings from current definitions.
Cache definitions and compiled summons until battle exit, retain live loading for authoring, and diagnose malformed optional assets without hiding valid neighbours.
Resolve summons once at authored cue, frame or end timing. Preserve cues and gameplay through reduced motion and presentation failures. Add terminal flash pulses, compiled draw ordering and clearing, battle-cached playback, and explicit animation selection.

Remove unconditional end-only resolution for cue/frame summons. Explicit missing IDs omit presentation rather than selecting name fallback; unset legacy skill references retain fallback. Reduced motion removes transient flash, shake and transition motion but retains every cue and the final frame.
Keep speech separate from sound effects, honour live mute, expose completion, and optionally duck music on seek-safe backends without restarting unsupported tracks.
Use semantic remappable input and per-page read timing while retaining manual confirmation and authored help. Wait for voice completion on the final page and stop owned speech on modal cleanup.
Resolve emotion and MP3 voice references softly and adopt shared dialogue Auto playback. Keep text progression when voice assets or playback fail, interrupt owned speech on advance, and cover speech, modal and skit lifecycles.

Remove marking unfinished skits seen when the game stops or playback is interrupted. Completed text-only skits still record seen. Graphical staging and Editor beat authoring remain later phases.
…fecycle

Scope animation and summon caches to the active battle so a later battle reads current assets. Hold reduced-motion final frames during the effect display phase. Share the end timing default and legacy animation fallback with authoring, and warn on unknown timing modes. Move terminal flash color encoding into the color model and document summon cue payloads.
Keep invalid destinations from mutating active field state and return failed starts to the title. Report offending grid tokens and lines, and generate collision-safe nowdoc delimiters.
Set destination identity before resolving map music during commit. Prepare NPCs before changing field state so invalid entries preserve the current map and NPC list.
Persist player-facing choices in private .data settings while keeping authored config.php as defaults. Remove the hard-coded space:continue hint so dialogue always shows live bindings.
Store only changed keyboard keys beside player preferences, overlay them over authored defaults at boot, and retain action/controller metadata. Convert local preference filesystem warnings before the Game fatal handler sees them, keeping failed choices live with diagnostics. Add read-only audio mute preflight for automated launches.
…gration

Limit provisional current-name identities to missing-id legacy files at load time with diagnostics and no project writes. Explicit ids alone resolve definitions, including duplicate names and name/id collisions. Remove inferred display-name lookup from legacy saves unless an authored compatibility alias exists. Preserve frozen-name saves and test rename identity through the save pipeline.

Use lifecycle-free Game doubles in voice tests so delayed destruction cannot reset Console after test teardown.
…hat is missing

A project without a recorded format may already have its metadata, so the
message no longer claims it predates it. It names both formats and points
to ichiloto upgrade, which lists the changes before making them.
…in a cell

An upper layer's cell replaced the cell below it whole, so a space in it
hid what lay beneath: Home's chest " m" erased the wall "| " beside it.
Layers compose per column again, as terminal layers always did; a
two-column glyph still replaces its whole cell. Collision resolves each
column through the layers as before and the cell is solid when either
column is, and the single-grid collision map now uses the same resolver.
A project tileset (Data/Tilesets/<id>.php) names RPG Maker sheets A1 to E
and the graphical flags RPG Maker keeps per tile (above characters, A2
tables); each sheet's tile size is read from its image and checked against
its layout. A map names its tileset and keeps literal tile layers in
graphics/, one RPG Maker tile identity per cell. The engine composes each
identity used, including autotile shapes from quarter tiles and animated A1
water, into generic pieces for the retained world, with tile layers in the
below and above character bands; the viewport carries RPG Maker's
animation counter. AutotileShape resolves shapes from neighbours for
authoring tools. Unusable graphics or sheets leave a map on its terminal
glyphs; none of this touches geometry, collision, events or saves.
… the graphical field

Two-column map cells changed how the terminal plays: a horizontal step
moved two columns. The terminal is the game, so they are withdrawn and the
graphical field corrects for its own pixels instead. A map cell is one
terminal character again in every renderer, and the graphical field draws
each one as a 24 x 48 box, the terminal's tall cell enlarged, so a step is
one cell in both and a map that looks right in the terminal looks right
graphically.

Removed (reverting 8535e06, f3fbff7, cc06f98, ab8d472 and their tests and
docs): MapCell and two-column parsing, composition and collision; the
camera's cell and console column split (getConsolePosition,
getConsoleColumns, resizeToConsole); NormalizedRow::fromCells;
TwoColumnCellsMigration; project format 2. ProjectFormat::CURRENT is 1
again, so a project recording format 2 is refused as newer.

Kept: tilesets and tile layers, the retired glyph-keyed crops (tiles2d
still loads with a warning), the project format chain and its refusal of
older projects, and the application icon. MapGridMetrics is not restored:
its widths only served the retired crops.

Graphical field geometry: FieldViewport::CELL_WIDTH and CELL_HEIGHT (24 x
48) size the camera and centring, TILE_SIZE (48) sizes character frames
and field images (now counted in character frames), and TILE_COLUMNS (2)
is how many cells a tile covers across. The retained world sends
cellWidth and cellHeight instead of cellSize and cellColumns. Tile layers
hold one identity per terminal cell; a tile covers its cell and the next,
and AutotileShape resolves neighbours one tile width apart.

BREAKING CHANGE: map coordinates count terminal columns again, the
retained world definition carries cellWidth and cellHeight instead of
cellSize and cellColumns, tile layer rows are as wide as the map in
columns, and a 1 x 1 field image is 48 x 48.
…es centred or halved

A field cell is 24 x 48, one column of RPG Maker's quarter tiles. Tiles
anchored to a cell's left edge and covering two cells made a wall on one
terminal column twice as thick as the column and put furniture half a
column off its footprint.

Autotiles are now composed per cell: every cell of an area holds its
autotile, shapes are resolved from neighbouring cells (AutotileShape no
longer steps two cells), and CellTiles chooses the quarter column the cell
shows: the left half at a west edge or inner corner, the right half at an
east one, the outer half of each when it borders both, and alternating
halves inside a run. A plain tile (A5, B to E) is drawn whole and centred on
its cell, or, with an L or R suffix in the tile layer (42L), only that half
fills the cell. TileSlice cuts composed pieces into those slices, and the
retained catalog sends each slice with its own width and left offset.
MapTileLayer reads the suffixes into halves and reports each cell's
authored entry.

Removed: FieldViewport::TILE_COLUMNS and AutotileShape::resolveLayer's
column step.

BREAKING CHANGE: tile layers paint an autotile area in every cell and a
plain tile is centred on its cell rather than anchored at its left edge;
catalog tiles may carry width and left.
…exture in phase

A map's data may shift a whole tile layer by half a field cell across or
down, like a Tiled layer offset: 'tileLayers' => ['lounge' => ['offset' =>
[0, -0.5]]]. Art can then sit between the cells its terminal footprint
allows, such as a coffee table centred between a sofa and a television.
Offsets are -0.5, 0 or 0.5 on each axis and never move collision or
events. MapGraphics::readLayerOffsets validates them for the Engine and
tools, and the retained catalog carries them as tile left and top.

An autotile cell away from an edge now shows the half matching its
column's parity instead of alternating from the start of its row's run.
Runs start in different columns on different rows, which put checkered
and planked floors out of phase between rows.
A tileset may list pieces: whole items such as a bed, keyed by id, each
with a name, the gameplay layer its terminal glyphs go on, rows of
one-cell glyphs, and optional tiles keyed by tile layer name over the same
footprint, using the entries a tile layer holds (42, 42L, 0). A space glyph
or a 0 tile leaves that cell alone. TilesetPiece validates a piece with the
tile layer's own rules, so editors can stamp a piece whole, writing glyphs
and tiles together, while collision still comes from the glyphs alone.
… pieces

The Terminal and editors bullet still said the TUI editor never edits a map's graphics, contradicting the Pieces bullet: stamping a piece writes its tiles.
A piece with 'connects' => 'lines' is drawn one cell at a time and joins
the cells of the same piece beside it. Its glyphs name one glyph for each
shape (horizontal, vertical, corner) and its tiles one entry per tile layer
or one per shape. TilesetPiece::getLineShape gives a cell's shape from its
neighbours (only across: horizontal; only down: vertical; otherwise a
corner, which covers junctions and lone posts), and isMember recognises the
piece's cells by their glyphs, so editors can reshape neighbours when a
cell is drawn or erased.
A map's tileLayers settings may give a tile layer 'movesWith', naming the
gameplay layer whose glyphs its tiles travel with when an editor moves
them. The runtime only checks it names a gameplay layer. A layer's
settings no longer need an offset.
A save compatibility step may now declare `mapShifts` instead of `class`
(exactly one of the two): a list of rows or columns inserted into a map,
each with map, axis (x or y), the 0-based insertion line and the count.
The engine applies them in order to the saved player position, following
map aliases, so projects need no generated PHP class for an insertion.
Entries are validated strictly when the manifest loads.

SaveCompatibilityManifest::migrationFrom(), which returned a class name,
is replaced by createMigrationFrom(), which returns the migration for
either kind. Its only caller, the save pipeline, is migrated; the
migration is now created inside the pipeline's failure handling.
…ansitions

Negotiate the key_transitions renderer event subscription. A subscribed
session's key events carry a stable control identity and a repeat flag;
key_release and input_reset report releases and focus loss. RendererClient
queues presses, releases and resets in a bounded FIFO beside the unchanged
key FIFO, and rejects transitions a session did not subscribe to.

RendererInputSource implements the new HeldInputSourceInterface. Each
InputManager::handleInput() applies that update's transitions to a bounded
KeyHoldState before gameplay: isButtonHeld(), wasButtonPressed() and
getButtonPressOrder() cover every binding of an action, keep quick taps as
press edges, and match releases by control so modifier changes never strand
a key. Held state clears on reset, source change, renderer restart and any
input failure. isButtonDown(), isKeyDown() and axes keep their event-only
meaning, so menus and navigation repeat are unchanged, and the terminal
source stays event-only.

The Game's GPUI session now requires key_transitions, so it needs the
updated renderer.
…ween cells

With input that reports held keys, the player walks as in RPG Maker MZ: the
most recently pressed held direction wins, releasing it falls back to the
next one still held, and each step is the ordinary validated tryMove(), so
collision, gates, triggers, encounters and events behave exactly as a single
step does. PlayerWalk paces steps with the one FieldMetric: RPG Maker's 180
field pixels per second over 24 x 48 cells, 8/60 s sideways and 16/60 s
vertically, independent of zoom, scaling and window size. A press from
standing steps at once; a direction change waits for the step in progress;
taps are kept but cannot outrun walking; blocked movement banks no time;
at most one step catches up after a stall; and any update the field did
not control (menu, dialogue, cinematic, battle, transfer) cancels walking
and makes earlier presses stale. Event-only input keeps stepping once per
key event, unchanged.

Every committed step now records a CharacterStep. With the field_motion
drawing feature, sprites carry the step's duration and the viewport names
the followed player, so the renderer slides characters and the camera
between cells. Routes present steps at their own secondsPerStep through
GameScene::moveAtPace(); wander steps walk at field speed. Renderers that
do not advertise field_motion receive neither field.

CharacterWalkAnimation now advances by distance travelled, one pattern per
30 field pixels, so both axes animate at one pace and continuous walking no
longer stands between steps.

BREAKING CHANGE: CharacterWalkAnimation::step() takes the CharacterStep it
presents and STRIDE_SECONDS is removed (STOP_SECONDS replaces it);
GraphicalSpriteProviderInterface gains getGraphicalSpriteMotion();
CinematicStageManager::subjectMoved() and StagedActor::beginGraphicalStep()
take the step. Npc::beginGraphicalStep() without a step still advances one
stride.

Removed behaviour: under reduced motion the player and staged actors no
longer animate their walking frames; they show the standing frame, as NPCs
already did.
…an and field docs

Update the controller-ready input plan in place: key transitions, held state and four-directional field walking are implemented; diagonal movement, physical controllers, analog input and enhanced terminal reporting stay planned. Document distance-based walking frames, route and wander pacing, slides, reduced motion and the renderer contract, and record the changes in the changelog.
A field cell was a 24 x 48 box, the terminal's own shape, so every RPG
Maker tile and character had half a tile of width: a character covered
one 24-pixel floor square across, a one-column bed overlapped the wall
beside it and neighbouring chairs overlapped each other. RPG Maker's
style fills 48 x 48 tiles, so the graphical field now draws each
terminal cell as one 48 x 48 tile. The terminal is unchanged: one column
is still one map cell and one step.

- FieldViewport sizes the camera, centring and zoom in TILE_SIZE squares,
  so the field shows fewer columns than before; the retained world sends
  cellWidth and cellHeight of 48.
- Each cell shows one whole tile: an autotile is composed for its cell
  from all four quarters by the shape its neighbours give it, and a plain
  tile (A5, B to E) is drawn whole in its cell. Layer offsets are in tiles
  (half a cell is 24 pixels on either axis); movesWith is unchanged.
- A 48 x 48 character frame, bottom-centred as before, fills its cell.
- FieldMetric takes one cell size, so every step, across or down, walks in
  16/60 s at RPG Maker's 180 pixels per second, and each step carries the
  walk cycle 1.6 patterns on.

Removed behaviour:
- Per-cell autotile slicing: CellTiles, TileSlice (LEFT, RIGHT, NARROW,
  WHOLE), column parity and the centring offset (a whole tile at left -12).
  The retained catalog no longer carries a tile width.
- The L and R half-tile suffix (42L). MapTileLayer::$halves is gone, and a
  tile layer or tileset piece entry naming half a tile is now refused with
  a message asking for whole tiles, not reinterpreted.
- FieldViewport::CELL_WIDTH and CELL_HEIGHT, and FieldMetric's separate
  cell width and height.
- Sideways steps no longer take 8/60 s; they take 16/60 s like vertical
  ones.

BREAKING CHANGE: tile layers and pieces accept only whole tile identities;
FieldViewport::CELL_WIDTH and CELL_HEIGHT are removed (use TILE_SIZE);
FieldMetric's constructor takes one cellSize; the retained world's cells
are 48 x 48 and maps look twice as wide graphically as in the terminal.
The graphical field plan, maps, tile batches, runtime, sprite sheets,
input sources and the layered tilemap history now say that a terminal
cell is drawn as one 48 x 48 RPG Maker tile: each cell shows one whole
tile, a character frame fills its cell and every step walks in 16/60 s.
The plan records that maps are laid out in tiles, so a map laid out only
for the terminal's proportions looks twice as wide graphically.

Removed: the descriptions of 24 x 48 cells, quarter-column autotile
slices, column parity, centred plain tiles and L/R half-tile entries,
which the engine no longer supports.
…t belongs to

A tile layer belongs to one gameplay layer: the one its map data names
(tileLayers.<name>.movesWith), and otherwise the gameplay layer whose
tileset pieces write it, when exactly one does. That resolution lived only
in the editor; MapGraphics::resolveLayerOwners() now owns it, returning
each tile layer's gameplay layer or null, and loadFromDirectory() keeps
the result in MapGraphics::$owners.

With the new tile_covers drawing feature, PresentationWorld names that
gameplay layer as coversLayerId on both draw bands of a tile layer, using
the same ids as ownerLayerId, so a renderer hides a world cell's glyph
only under tiles of the layer that owns the cell. A floor that belongs to
buildings no longer hides the glyph of a fixture with no tile yet, such as
Home's chest, sofa, coffee table and television. A tile layer that
belongs to no gameplay layer keeps hiding every glyph it paints.

RetainedPresentation sends the field only to a renderer that advertised
tile_covers, choosing it per session on every world upload and reset;
PresentationWorld::$operations stays the upload without it, so other
renderers receive exactly the previous world.
Console writes clamped their column into the screen, so text that
started left of it was drawn at column 0 and text past its right edge
at the last column. A field sprite that had scrolled off the side of
the view, such as an NPC shown by its glyph in GPUI, stayed pinned to
the view's edge. Writes are now clipped at the side edges as they
already were at the top and bottom: the visible part lands where it
belongs and a wide glyph the edge cuts is dropped whole.

Changed behaviour: text written at a negative column, or at or past
the screen's width, is no longer moved onto the screen.
A tileset belongs to a kind of setting, such as interiors, and every map of that kind names it, as RPG Maker groups its own. Its sheets are sorted by kind, and new art goes into free cells because a tile's identity is its place on its sheet. The examples now name an interior tileset.
RPG Maker MZ draws every character's frame 6 pixels above its tile
(Sprite_Character shiftY), except object sheets whose file name starts
with "!", so artists draw feet on the frame's bottom edge. Ichiloto drew
such art on the cell's bottom edge, 6 pixels low.

CharacterSheet now owns the rule. It reads the file name's leading run of
"$" and "!" marks as RPG Maker does and gives every frame a lift of
CharacterSheet::LIFT (6 field pixels, the sprite's own pixel space) or 0
for an object sheet. The lift is derived from the name alone, never from
the image. GraphicalSpriteDefinition and PresentationSprite carry it,
validated between 0 and the sprite's height, and GraphicalSpriteProjector
passes it through, so the player, NPCs and staged cinematic actors drawn
from a sheet are lifted. Single-image field art such as cinematic poses,
battle and interface sprites keep no lift. Cells, collision, events,
saves, row draw order and the terminal are unchanged.

With the new sprite_lift drawing feature, RetainedPresentation names a
nonzero lift on a sprite's value only for a renderer that negotiated it.
Other renderers receive byte for byte the previous upload.

Changed behaviour: a sheet named "!$Name" or "$!Name" is now read as a
single-character sheet, as in RPG Maker; before, only a name starting
with "$" was, so such a sheet was read as eight characters and an index
of 1 to 7 on it is now rejected.
…d a minimap

Records Andrew's direction: every glyph has graphical art, cues draw as bordered slanted exclamation marks in blue or yellow, story cues outside the view show at the screen edge in their direction, and a minimap overlay replaces the coordinate HUD. Planned only; nothing is implemented.
When the player talks to a field NPC, NpcManager::turnNpcToward() turns
it toward the player through the existing face() path before it speaks,
so its heading becomes the opposite of the player's, its terminal glyph
swaps to an authored directional sprite and its character sheet shows the
matching row. The NPC is not turned back afterwards; a wanderer stays
turned until its next step.

Map NPC entries accept an optional directionFix bool (RPG Maker's name,
default false). A direction-fixed NPC keeps its heading when talked to;
wander steps and move_route still turn it. NPCs a cinematic has staged
are never turned by talking.

Behaviour change: NPCs no longer keep their authored heading when the
player talks to them unless directionFix is true.
As RPG Maker's Game_Event.lock() and unlock() do, the talk turn now
remembers the NPC's heading and NpcManager::restoreNpcHeadingAfterTalk()
turns it back through the same turnNpc() and face() path when the
conversation ends: after the last plain dialogue page, when its script
or a variant script completes or fails, or when the script cannot start.
A restored wanderer keeps its wander schedule.

Restore rule: the heading is restored only if nothing else set the NPC's
heading or transform after the talk turn. Npc::face() (every route turn
or step, even one toward the player) and restoreFieldTransform()
(restored cinematic staging) forget the remembered heading. It is also
not restored while a cinematic still stages the NPC or once the NPC has
left the current map. RPG Maker restores unconditionally; this keeps
script-authored results.

A second talk while the NPC's conversation is active no longer turns it.
MovementHeading::getDirection() replaces the player's local heading to
tile match.

Behaviour change: a talked-to NPC no longer keeps facing the player after
the conversation; it turns back to its previous heading.
A map's kind is the setting it draws and names the tileset every map of that kind shares. It is chosen when the map is created, and the tiles a map can use change only when its kind does. The Editor asks it at creation, shows it as the Inspector's Kind and warns about a map without one; generate:map takes it as --kind.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T21:22:46.394349Z 2e32b6f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2e32b6f68b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

$definitions = isset($data['tiles2d']) ? GraphicalTileDefinition::getForLayers($data['tiles2d'], $layers, $map) : [];
$loadMs = (hrtime(true) - $started) / 1e6;
$started = hrtime(true);
$world = $retained ? PresentationWorld::getFromLayers($layers, $definitions) : null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the benchmark for the retained-world API

For every valid benchmark run, $retained is true and $definitions is an array, but PresentationWorld::getFromLayers() now expects a string world ID as its second argument, so this call throws a TypeError before any samples are collected. The same tool also references the deleted GraphicalTileDefinition and GraphicalTileCollector classes; it needs to construct the current MapGraphics/retained-world inputs instead of using the removed stateless tile API.

Useful? React with 👍 / 👎.

On a graphical field, stepping onto a save point opened its notice while the
step was still sliding; the modal froze the slide, and when it closed the
player jumped to the cell. Touch events (dialogues, transfers, battles) and
encounters had the same cut. As RPG Maker does, what reaching a cell does now
waits until the player is seen to arrive: the step is committed at once
(position, collision, facing), and its triggers, encounter step, save point
notice and movement observers run on the field frame its slide ends, never
under a menu opened while it slid. A new step completes any arrival still
pending first, so none is skipped or reordered. A step without a slide (the
terminal, reduced motion) arrives immediately, as before.
The effect animation plan covered battle, skill, item and summon effects but
not effects that live with a map. It now records the field as a consumer of
the same timelines: cell and object anchors, once and loop playback, map-owned
ambient effects declared at cells or by tileset pieces (a save point's
energy, torches, magic circles, the planned graphical cues) that start and
end with the map, object-attached effects that follow their owner, and image
tracks drawn behind or in front of characters. The terminal glyph an effect
decorates stays its terminal truth, reduced motion shows a rest frame, and
the single field animation slot gives way to many sessions. Per-tile terrain
animation stays on the tile counter and character sheets on the walk
animation. Phases 1 and 2 gain the field items, and the graphical cues entry
in the roadmap points at it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant