# World Source: `src/dusk/rpg/overworld/` --- ## Coordinate system Three nested coordinate spaces, each defined in `worldpos.h`: | Type | Description | Unit | |---|---|---| | `worldpos_t` | Tile-level absolute position `{x, y, z}` | `worldunit_t` (int16) | | `chunkpos_t` | Chunk-grid position `{x, y, z}` | `chunkunit_t` (int16) | | `fixed_t[3]` | Smooth sub-tile position used by entities | Q24.8 fixed-point | One chunk = `CHUNK_WIDTH × CHUNK_HEIGHT × CHUNK_DEPTH` tiles (16 × 16 × 8). The loaded world window = `MAP_CHUNK_WIDTH × MAP_CHUNK_HEIGHT × MAP_CHUNK_DEPTH` chunks (5 × 5 × 3). Conversion helpers (all in `worldpos.c`): ```c worldPosToChunkPos(&worldPos, &chunkPos); // tile → chunk grid chunkPosToWorldPos(&chunkPos, &worldPos); // chunk grid → tile origin worldPosToChunkTileIndex(&worldPos); // tile → index within its chunk chunkPosToIndex(&chunkPos); // chunk grid → linear index in MAP.chunks[] worldPosToFixed(&worldPos, fixedOut); // tile → entity fixed position fixedToWorldPos(fixedPos); // entity fixed → tile (truncates frac) ``` --- ## Tiles Defined in `tile.h` as a plain `tile_t` enum: ``` TILE_SHAPE_NULL — empty / unloaded TILE_SHAPE_GROUND — solid flat tile TILE_SHAPE_RAMP_* — directional ramps (N/S/E/W + diagonals NE/NW/SE/SW) ``` Key predicates: - `tileIsWalkable(tile)` — true for GROUND and all ramp shapes. - `tileIsRamp(tile)` — true only for ramp shapes. Entity walk code (`entity.c`) checks both the current tile and the target tile to decide whether the entity steps forward flat, raises one Z level (walking up a ramp), or falls one Z level (stepping onto a downward ramp from above). --- ## Chunks `chunk_t` (`chunk.h`) holds: - `position` — its `chunkpos_t` in the world grid - `tiles[CHUNK_TILE_COUNT]` — flat array of `tile_t`, indexed by `chunkGetTileIndex()` - `vertices[CHUNK_VERTEX_COUNT]` / `mesh` — pre-baked mesh uploaded to GPU on load - `entities[CHUNK_ENTITY_COUNT_MAX]` — indices into `ENTITIES[]` currently in this chunk (sentinel `0xFF`) - `testColor` — temporary debug color (checkerboard), will be replaced by real tileset data Tile layout within a chunk is `z * W*H + y * W + x` (Z-major, row-major in XY). --- ## Map `map_t MAP` (`map.h`) is the single global map instance. ```c chunk_t chunks[MAP_CHUNK_COUNT]; // flat storage — index is NOT world position chunk_t *chunkOrder[MAP_CHUNK_COUNT]; // draw-order sorted pointers into chunks[] chunkpos_t chunkPosition; // world-grid origin of the loaded window bool_t loaded; ``` ### Load / unload `mapInit()` allocates chunk meshes and performs the initial load of all chunks in the starting window. `mapPositionSet(newPos)` shifts the window: 1. Determines which of the `MAP_CHUNK_COUNT` slots remain within the new window vs. fall outside it. 2. Calls `mapChunkUnload()` on every chunk that falls outside (nulls its entity slots, zeroes `vertCount`). 3. Reuses freed slots for newly-in-range chunks; calls `mapChunkLoad()` on each. 4. Rebuilds `chunkOrder[]` in XYZ order for the new position. ### Chunk load (current stub) `mapChunkLoad()` currently: - Fills all tiles with `TILE_SHAPE_GROUND` - Assigns a checkerboard debug color based on chunk XY parity - Bakes a flat sprite-batch quad mesh for the z=0 layer and uploads it via `meshFlush()` - Skips mesh generation for z > 0 chunks (they're empty) ### Tile lookup ```c tile_t mapGetTile(const worldpos_t position); ``` Converts `position` to its chunk, looks up the chunk in `chunkOrder`, then indexes into `chunk->tiles[]`. Returns `TILE_SHAPE_NULL` for any out-of-bounds position or when the map is not loaded. --- ## Camera `rpgcamera_t RPG_CAMERA` (`rpgcamera.h`) has two modes: ```c RPG_CAMERA_MODE_FREE // free worldpos; camera.free holds the position RPG_CAMERA_MODE_FOLLOW_ENTITY // tracks ENTITIES[followEntityId] ``` `rpgCameraGetPosition()` returns the active world tile position in either mode. The scene renderer (`sceneoverworld.c`) uses `rpgCameraGetPosition()` to build the `glm_lookat` view matrix. When following an entity, it sub-tile interpolates between `entity->lastPosition` and `entity->position` using `entity->animTime / ENTITY_ANIM_WALK_DURATION` to smooth movement.