yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
room_collision.h
Go to the documentation of this file.
1#ifndef YAZE_ZELDA3_DUNGEON_ROOM_COLLISION_H
2#define YAZE_ZELDA3_DUNGEON_ROOM_COLLISION_H
3
4#include <array>
5#include <cstddef>
6#include <cstdint>
7#include <optional>
8#include <vector>
9
11#include "zelda3/dungeon/room.h"
13
14namespace yaze {
15
16class Rom;
17
18namespace zelda3 {
19
20// Vanilla underworld collision ("tile attribute") maps.
21//
22// After a room is drawn, Underworld_LoadAttributeTable (usdasm bank_01
23// #_01B8BF) builds one attribute byte per tilemap tile:
24// COLMAPA $7F2000 (64x64) from TILEMAPA $7E2000 (BG1, the upper layer)
25// COLMAPB $7F3000 (64x64) from TILEMAPB $7E4000 (BG2, the lower layer)
26// in four passes:
27// 1. Underworld_LoadBasicAttribute_full: TILEATTR[tile number], plus the
28// tile's flip bits for attributes 0x10-0x1B.
29// 2. Underworld_LoadObjectAttribute: stars, stairs, layer stairs, water
30// stairs, pots/blocks/pegs, torches, chests and big key locks, from lists
31// the object draw routines recorded while the room was drawn.
32// 3. Underworld_LoadDoorAttribute: doorways, locked doors, layer and
33// dungeon toggle doors, the door switch, from the door slot tables.
34// 4. Underworld_FlipCrystalPegAttribute when $7EC172 != 0.
35// yaze reproduces the recorded lists by replaying the list bookkeeping of
36// each RoomDraw_* routine over the room's own objects, doors, pushable blocks
37// and torches, in the game's draw order.
38
39inline constexpr size_t kTileAttributeTableSize = 0x200; // $7EFE00
40inline constexpr size_t kCollisionMapTiles = 64 * 64;
41// COLMAPA then COLMAPB, indexed like the game: tile = y * 64 + x, plus
42// 0x1000 for the lower (BG2) map.
43inline constexpr size_t kRoomCollisionBytes = 2 * kCollisionMapTiles;
44
45// Which pass last wrote a collision byte.
46enum class CollisionSource : uint8_t {
47 kTilemap = 0, // basic pass (tile attribute table)
48 kStar, // star tiles
49 kStairs, // in-room, spiral and straight stairs
50 kLayerStairs, // auto multi-layer / merged stairs
51 kWater, // water hop stairs, water overlay stairs, water ladders
52 kManipulable, // pots, pegs, blocks, big gray rocks
53 kTorch, // lightable torches
54 kChest, // chests and big chests
55 kBigKeyLock, // big key locks
56 kDoor, // doorway properties
57 kLockedDoor, // closed doors (F0 | slot)
58 kDoorLayerToggle, // layer / dungeon toggle doors (OR 0x10 / 0x20)
59 kDoorSwitch, // the door switcher object
60 kCrystalPeg, // crystal peg swap
61};
62
63const char* CollisionSourceName(CollisionSource source);
64
66 std::array<uint8_t, kRoomCollisionBytes> attributes{};
67 std::array<CollisionSource, kRoomCollisionBytes> sources{};
68
69 uint8_t upper(int x, int y) const { return attributes[y * 64 + x]; }
70 uint8_t lower(int x, int y) const {
71 return attributes[kCollisionMapTiles + y * 64 + x];
72 }
73};
74
75// Save-file and runtime state that changes the maps. The default is a room
76// entered for the first time on a new file: no room flags, pegs not swapped.
78 // The room's save word ($7EF000 + room * 2). Underworld_LoadHeader derives
79 // $0400 (= word & 0xF000), $068C (= $0400 | 0x0F00) and
80 // $0402 (= (word & 0x0FF0) << 4) from it.
81 uint16_t room_save_flags = 0;
82 // $068C, the open-door mask, when it differs from the one LoadHeader
83 // derives (a room whose shutters opened after it loaded).
84 std::optional<uint16_t> door_open_mask;
85 // $0468: shutter doors stay closed while it is nonzero. LoadHeader sets 1.
86 uint16_t shutter_controller = 1;
87 // $7EC172 != 0: Underworld_FlipCrystalPegAttribute swaps 0x66 and 0x67.
89};
90
91// Where Underworld_LoadCustomTileTypes (#_0E942A) reads the per-blockset
92// types for TILEATTR 0x140-0x1BF (VRAM chars of sheet slots 5-6).
93enum class CustomTileTypeSource : uint8_t {
94 kVanilla, // the routine at $0E:942A (or vanilla addresses)
95 kHook, // $0E:942A is a JSL to a copy of the routine with its
96 // own tables (Oracle of Secrets: 24 groups in bank $2C)
97 kUnrecognizedHook, // $0E:942A is a JSL yaze cannot decode; vanilla tables
98};
99
101
104 int offsets_pc = 0x071000; // CustomTileTypesOffset, one word per blockset
105 int data_pc = 0x07102A; // CustomUnderworldTileTypes; offsets add to it
106 uint32_t hook_target = 0; // SNES address of the JSL target, if any
107};
108
109// Decodes the routine at $0E:942A, following a JSL there, and returns the two
110// table operands it reads. Falls back to the vanilla addresses when the code
111// does not match the routine's shape.
113
114// TILEATTR ($7EFE00, 512 bytes): LoadDefaultTileTypes (#_0E97D9) copies
115// UnderworldTileTypes ($0E:9659) entries 0x000-0x13F to 0x000 and
116// 0x140-0x17F to 0x1C0; Underworld_LoadCustomTileTypes (#_0E942A) copies 0x80
117// bytes from CustomUnderworldTileTypes ($0E:902A) +
118// CustomTileTypesOffset[blockset] ($0E:9000) to 0x140, or from the tables of
119// a hooked copy (ResolveCustomTileTypeTable). `blockset` is room header byte 2
120// (Room::blockset()); vanilla has 21 entries, Oracle of Secrets 24.
121std::array<uint8_t, kTileAttributeTableSize> LoadUnderworldTileAttributeTable(
122 const Rom& rom, uint8_t blockset);
123std::array<uint8_t, kTileAttributeTableSize> LoadUnderworldTileAttributeTable(
124 const Rom& rom, uint8_t blockset, const CustomTileTypeTable& custom);
125
126// Pass 1 only: the attribute of each tile word in `tilemaps`.
128 const std::array<uint8_t, kTileAttributeTableSize>& table,
129 const RoomTilemaps& tilemaps);
130
131// Everything the passes read from a room.
133 int room_id = 0;
134 uint8_t blockset = 0;
135 uint8_t tag1 = 0; // $AE
136 uint8_t tag2 = 0; // $AF
137 // Room objects as Room holds them: stream objects (list = GetLayerValue())
138 // plus pushable blocks and torches (ObjectOption::Block / ::Torch).
139 std::vector<RoomObject> objects;
140 std::vector<Room::Door> doors; // stream order
141 RoomTilemaps tilemaps; // BG1 / BG2 words after drawing
142};
143
144// All four passes. Tables (tile types, door positions, doorway properties)
145// are read from `rom`.
147 const Rom& rom, const RoomCollisionInput& input,
148 const UnderworldRoomLoadState& state = {});
149
157
163
164// Resolves room-stream stairs from the shared vanilla collision replay, not
165// vector order. Results are a model preview, not custom-engine/runtime proof.
166// Ambiguous triggers and more than four stairs never produce editable slots.
167std::vector<StaircaseSlotResolution> ResolveVanillaStaircaseSlots(
168 const Rom& rom, const RoomCollisionInput& input,
169 const UnderworldRoomLoadState& state = {});
170
171// Convenience for a loaded, rendered room: its objects, doors and header, and
172// the tilemaps yaze composed (ComposeYazeRoomTilemaps) unless `tilemaps` is
173// given.
174RoomCollisionInput MakeRoomCollisionInput(const Room& room);
175RoomCollisionInput MakeRoomCollisionInput(const Room& room,
176 const RoomTilemaps& tilemaps);
177
178} // namespace zelda3
179} // namespace yaze
180
181#endif // YAZE_ZELDA3_DUNGEON_ROOM_COLLISION_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:52
constexpr size_t kRoomCollisionBytes
constexpr size_t kTileAttributeTableSize
std::array< uint8_t, kTileAttributeTableSize > LoadUnderworldTileAttributeTable(const Rom &rom, uint8_t blockset)
constexpr size_t kCollisionMapTiles
RoomCollisionMaps ComputeBasicCollisionMaps(const std::array< uint8_t, kTileAttributeTableSize > &table, const RoomTilemaps &tilemaps)
RoomCollisionMaps ComputeRoomCollisionMaps(const Rom &rom, const RoomCollisionInput &input, const UnderworldRoomLoadState &state)
const char * CustomTileTypeSourceName(CustomTileTypeSource source)
CustomTileTypeTable ResolveCustomTileTypeTable(const Rom &rom)
RoomCollisionInput MakeRoomCollisionInput(const Room &room, const RoomTilemaps &tilemaps)
std::vector< StaircaseSlotResolution > ResolveVanillaStaircaseSlots(const Rom &rom, const RoomCollisionInput &input, const UnderworldRoomLoadState &state)
const char * CollisionSourceName(CollisionSource source)
std::vector< RoomObject > objects
std::vector< Room::Door > doors
uint8_t lower(int x, int y) const
std::array< CollisionSource, kRoomCollisionBytes > sources
uint8_t upper(int x, int y) const
std::array< uint8_t, kRoomCollisionBytes > attributes
std::optional< uint16_t > door_open_mask