View on GitHub

FOnline Engine

Flexible cross-platform isometric game engine

Maps, Movement, and Geometry

This document explains the reusable map-coordinate, movement, path-finding, line-tracing, and map-loading primitives used by client/server runtime and tools.

Use it when changing Source/Common/Geometry.*, LineTracer.*, Movement.*, PathFinding.*, MapLoader.*, map baker behavior, or map/movement tests.

Ownership model

The engine owns coordinate types, path algorithms, movement interpolation, and map-file loading mechanics. An embedding game project owns concrete maps, blocker layout, encounter rules, and gameplay decisions around movement.

Keep project-specific map content and quest/navigation rules outside this document.

Coordinate and direction types

Source/Common/Geometry.h defines the exported value types used across runtime, generated API, and scripts:

msize provides checked/clamped helpers:

Do not replace these types with generic ipos/isize in public map APIs without checking generated metadata and script-visible value layouts.

Geometry modes

hdir is compiled differently depending on FO_GEOMETRY:

GameSettings::MAP_DIR_COUNT participates in direction normalization. When changing geometry, inspect compile-time geometry settings, generated value types, path-finding tests, and any rendering code that projects map positions.

Geometry helper responsibilities

GeometryHelper is a static utility class. It owns coordinate projection and directional math such as:

Safe helpers check msize bounds; unsafe helpers are for internal algorithms that already proved bounds.

Path finding

Source/Common/PathFinding.h exposes the core path-finding API:

FindPathInput is deliberately callback-driven. Runtime code supplies CheckHex(mpos) so map ownership, blockers, critters, gag items, and game-specific blocking policy stay outside the generic algorithm.

Important FindPathInput fields:

FindPathOutput returns a result, direction steps, control steps, and possibly adjusted NewToHex.

Blocking model

HexBlockResult expresses path-finding priority:

For multihex actors, CheckHexWithMultihex() checks the directional front arc and returns the worst blocker result across checked hexes.

When gameplay code changes blocker semantics, update the callback provider and tests; do not bake game-specific blocking rules into the generic path algorithm.

Line tracing

TraceLineInput describes a trace from StartHex toward TargetHex:

TraceLineOutput reports whether the trace was full, whether a last movable hex exists, the pre-block hex, block hex, and last movable hex.

Line tracing is used by movement/path logic and by gameplay systems that need visibility, shooting, or straight-line movement checks.

Movement contexts

Source/Common/Movement.h defines movement state and interpolation:

MovingContext stores:

Key operations:

Movement is therefore a reusable time-based plan, not just a list of positions. Client prediction, server correction, and script-visible movement data should all preserve that distinction.

Map loading

Source/Common/MapLoader.h exposes MapLoader::Load():

static void Load(
    string_view name,
    const string& buf,
    const EngineMetadata& meta,
    HashResolver& hash_resolver,
    const CrLoadFunc& cr_load,
    const ItemLoadFunc& item_load);

The loader parses a map buffer and calls engine/runtime-provided callbacks for critters and items:

This keeps file parsing generic while letting server/tools decide how loaded critters/items become live entities or editor objects.

Map resource production is adjacent to baking. For MapBaker, see BakingPipeline.md.

Tests to inspect

Relevant tests include:

Change routing

Validation checklist

  1. Run movement/path/map-loader tests relevant to the changed algorithm.
  2. Test both direct and multihex movement if blocker logic changes.
  3. Validate FO_GEOMETRY assumptions when changing directions/projection.
  4. Validate map loading with real baked map resources from an embedding project when parser behavior changes.
  5. If movement state is replicated, validate network and client/server behavior; update Networking.md if packet/property flow changes.
  6. If script-visible movement APIs change, update GeneratedApiAndMetadata.md and Nullability.md if signatures/nullability changed.