yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
room_links.h
Go to the documentation of this file.
1#ifndef YAZE_ZELDA3_DUNGEON_ROOM_LINKS_H_
2#define YAZE_ZELDA3_DUNGEON_ROOM_LINKS_H_
3
4// Room links: the ways the game moves Link from one underworld room to
5// another. The room census (room_census.h) and the z3ed graph commands
6// (dungeon-graph, dungeon-discover, dungeon-room-graph) build their edges
7// here, so they agree on:
8// - Entrances: the game reads ZScream's bank $0F tables when $02:D99F is
9// hooked (ReadDungeonEntranceTarget).
10// - Header destinations: a stair or holewarp byte keeps the source room's
11// high byte ($A1). Byte 0 is room $x00 when a stair, hole or warp uses it;
12// an unused byte 0 is no reference. Results past 0x127 are not rooms.
13// - Grid neighbors: edge doors lead to +-1 / +-16 on the same $A1 page, with
14// no wrap across a row or page edge (DungeonNeighborRoom).
15// - Teleport doors (door type 0x46 on an east or west wall): the edge
16// transition loads stair slot 4 (east, $02:B670 LDA $7EC004) or slot 3
17// (west, $02:B711 LDA $7EC003) instead of the grid neighbor.
18// - Key-stair doors (0x20-0x26) lock a stair object; the stair object is the
19// link, not the door.
20// - Holes: every fall runs DetermineConsequencesOfFalling, which costs a
21// heart in rooms listed in RoomsWithPitDamage ($07:94AA) and otherwise
22// loads the header holewarp ($07:94BA). A room's holewarp is live when it
23// has pit objects, pit tiles, tag-driven holes (RoomTag_TriggerHoles),
24// falling-floor overlords (0x0A-0x0F) or Ganon (0xD6, whose phase 3 spawns
25// overlords 0x0C-0x0F). Warp tiles ($07:D146) use the holewarp in any room.
26// Pit tiles include the bowls of large braziers (0x11C), entered by landing
27// from the room above: vanilla 0x31 drops into 0x77, whose braziers drop
28// into the Hera fairy room 0xA7 (Module07_07_0F_FallingFadeIn, $02:8EC3).
29
30#include <array>
31#include <cstdint>
32#include <functional>
33#include <memory>
34#include <optional>
35#include <set>
36#include <string>
37#include <vector>
38
39#include "absl/status/status.h"
40#include "absl/status/statusor.h"
41#include "util/stop_token.h"
42
43namespace yaze {
44class Rom;
45namespace zelda3 {
46
47class CustomObjectRenderSnapshot;
48class PitDamageTable;
49class Room;
50
51inline constexpr int kDungeonRoomCount = 0x128;
52// Entrance table rows 0x00-0x84 (vanilla and ZScream's bank $0F copy).
53inline constexpr int kDungeonEntranceCount = 0x85;
54// Door type 0x46: tile attribute 0x89 on east and west walls.
55inline constexpr uint8_t kTeleportDoorType = 0x46;
56
57enum class RoomReferenceKind : uint8_t {
58 kEntrance, // Overworld entrance placed on a map.
59 kHole, // Overworld hole placed on a map.
60 kSpawn, // Spawn point (save/start location).
61 kUnplacedEntrance, // Entrance table row with no overworld placement.
62 kDoor, // Door from an adjacent room.
63 kStair, // Stair object resolved to a header slot.
64 kHolewarp, // Pits, holes or warp tiles using the header holewarp.
65 kWarpTag, // Project warp tag using header stair slots.
66 kHeaderOnly, // Header byte points here but nothing uses it.
67 kProjectListing, // Listed in the project's dungeon registry.
68 kDungeonMap, // Drawn on a dungeon's pause map (bank $0A room grids).
69 kTeleportDoor, // Door type 0x46 using header stair slot 3 or 4.
70};
71
73
74// What a door does when Link walks through it.
75enum class RoomDoorRole : uint8_t {
76 kNeighbor, // Edge transition to the grid neighbor.
77 kTeleport, // Type 0x46 on an east or west wall: stair slot 4 or 3.
78 kExit, // Leaves the dungeon (IsExitDoorType).
79 kKeyStairs, // Locks a stair object; the stair object is the link.
80};
81const char* RoomDoorRoleName(RoomDoorRole role);
82
83// Per-room facts that decide the room's outgoing links. Plain data so tests
84// can build them.
86 int room_id = 0;
87 uint8_t blockset = 0;
88 uint8_t tag1 = 0;
89 uint8_t tag2 = 0;
90 // Pit objects (room stream or layout), pit tiles in the drawn tilemaps or
91 // custom collision.
92 bool has_pits = false;
93 // The only pit tiles are the bowls of large braziers (object 0x11C), which
94 // Link enters only by landing there from the room above.
96 // Warp tile objects (including 0xFCF, drawn disabled and enabled at run
97 // time), warp tiles in the drawn tilemaps or custom collision.
98 bool has_warp_tiles = false;
99 // Tag 1 or tag 2 is a vanilla "Holes" tag. CollectRoomLinks ignores a
100 // hole tag that the project redefines as a warp tag.
101 bool has_hole_tag = false;
102 // Falling-floor overlord or Ganon; empty when none. Names the sprite.
103 std::string hole_sprite;
105 uint8_t holewarp_byte = 0;
106 std::array<uint8_t, 4> stair_bytes{};
107 // Header slots used by stair objects in this room.
108 std::array<bool, 4> stair_slot_used{};
109 std::array<bool, 4> stair_slot_estimated{}; // Placement order, not replay.
110 struct Door {
111 int direction = 0; // zelda3::DoorDirection value.
112 int along = 0; // Tile coordinate along the wall.
113 bool outer = false;
115 uint8_t type = 0; // zelda3::DoorType value.
116 int tile_x = 0;
117 int tile_y = 0;
118 };
119 std::vector<Door> doors; // Every door except layer/dungeon swap markers.
120};
121
122// Cause chosen by the shared holewarp rules; presentation must not infer it
123// again from raw tags (a project may redefine a vanilla hole tag).
124enum class RoomHolewarpCause : uint8_t {
125 kNone,
126 kPits,
128 kTag,
129 kSprite,
130};
131
132struct RoomLink {
133 int from = -1;
134 int to = -1; // 0x000-0x127, or -1 when the destination is not a room.
135 int raw_to = -1; // Destination before the range check.
137 int slot = -1; // Header stair slot 0-3, or -1.
138 int direction = -1; // Door wall for door links, or -1.
139 int door = -1; // Index into RoomLinkFacts::doors for door links.
140 bool strong = false; // The game can take it.
141 bool owner_ok = false; // Same area: may carry dungeon ownership.
142 std::string detail;
144};
145
146// Facts of a room, or nullptr when `room_id` is not a room or not known.
147using RoomLinkFactsLookup = std::function<const RoomLinkFacts*(int room_id)>;
148
149// Every outgoing link of `room_id`: doors (mutual or one-sided), teleport
150// doors, stairs, warp tags, the holewarp, and header bytes nothing uses.
151// Links whose destination is not a room keep `raw_to` and have `to` = -1.
152std::vector<RoomLink> CollectRoomLinks(
153 int room_id, const RoomLinkFactsLookup& facts,
154 const std::set<uint8_t>& warp_tag_ids = {});
155
156bool IsDungeonRoomId(int room_id);
157
158// Grid neighbor for an edge transition, or -1 when it would leave the row or
159// the $A1 page, or is not a room.
160int DungeonNeighborRoom(int room_id, int direction);
161
162// ResolveHeaderDestinationRoom, or -1 when the result is not a room.
163int CheckedHeaderDestinationRoom(int source_room_id, uint8_t header_byte);
164
165// True only for a validated supported ZScream expanded entrance layout.
166// ReadDungeonEntranceTarget rejects malformed layouts instead of falling back.
167bool UsesExpandedEntranceTables(const Rom& rom);
168
170 int room_id = -1; // Raw 16-bit room word; check IsDungeonRoomId.
171 int dungeon_id = -1;
172 bool expanded = false; // Read from ZScream's bank $0F tables.
173};
174
175// Room and dungeon ID of entrance `entrance_id`, from the table the game
176// reads.
177std::optional<DungeonEntranceTarget> ReadDungeonEntranceTarget(const Rom& rom,
178 int entrance_id);
179
180// True for objects whose tiles are pits (vanilla object IDs).
181bool IsPitObjectId(int object_id);
182// Warp tile 0xFCA and its disabled form 0xFCF.
183bool IsWarpTileObjectId(int object_id);
184// Vanilla "Holes" room tags (RoomTag_TriggerHoles and the chest holes).
185bool IsHoleRoomTag(uint8_t tag);
186// Pit (0x20, 0xB0-0xBD) and warp (0x4B) tile attributes, per the
187// underworld TileBehavior table at $07:D7D8.
188bool IsPitTileAttribute(uint8_t attribute);
189bool IsWarpTileAttribute(uint8_t attribute);
190
191// Reads the link facts of `room`, which must be loaded with its objects and
192// sprites (LoadRoomFromRom + LoadSprites). Draws the room's layout and
193// objects without graphics to find pit and warp tiles. `pit_table` may be
194// null (no room counts as a pit-damage room).
195absl::StatusOr<RoomLinkFacts> CollectRoomLinkFacts(
196 Rom* rom, const Room& room, const PitDamageTable* pit_table,
197 const CustomObjectRenderSnapshot* custom_objects = nullptr,
198 util::StopToken stop_token = {});
199
200// Loads rooms on demand and keeps their link facts.
202 public:
203 explicit RoomLinkFactsCache(Rom* rom);
207
208 // nullptr when `room_id` is not a room.
209 const RoomLinkFacts* Get(int room_id);
211 // First load/scan failure, including a room reached indirectly by AsLookup.
212 // Callers must check this before publishing a graph built with the lookup.
213 const absl::Status& status() const { return status_; }
214
215 private:
217 std::unique_ptr<PitDamageTable> pit_table_; // null when unreadable
218 std::vector<std::optional<RoomLinkFacts>> facts_;
219 absl::Status status_;
220};
221
222} // namespace zelda3
223} // namespace yaze
224
225#endif // YAZE_ZELDA3_DUNGEON_ROOM_LINKS_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:49
std::unique_ptr< PitDamageTable > pit_table_
Definition room_links.h:217
const RoomLinkFacts * Get(int room_id)
RoomLinkFactsCache & operator=(const RoomLinkFactsCache &)=delete
const absl::Status & status() const
Definition room_links.h:213
RoomLinkFactsLookup AsLookup()
std::vector< std::optional< RoomLinkFacts > > facts_
Definition room_links.h:218
RoomLinkFactsCache(const RoomLinkFactsCache &)=delete
bool IsWarpTileObjectId(int id)
const char * RoomReferenceKindName(RoomReferenceKind kind)
bool UsesExpandedEntranceTables(const Rom &rom)
std::optional< DungeonEntranceTarget > ReadDungeonEntranceTarget(const Rom &rom, int entrance_id)
bool IsDungeonRoomId(int room_id)
bool IsPitObjectId(int id)
int CheckedHeaderDestinationRoom(int source_room_id, uint8_t header_byte)
std::vector< RoomLink > CollectRoomLinks(int room_id, const RoomLinkFactsLookup &lookup, const std::set< uint8_t > &warp_tag_ids)
int DungeonNeighborRoom(int room_id, int direction)
constexpr int kDungeonRoomCount
Definition room_links.h:51
absl::StatusOr< RoomLinkFacts > CollectRoomLinkFacts(Rom *rom, const Room &room, const PitDamageTable *pit_table, const CustomObjectRenderSnapshot *custom_objects, util::StopToken stop_token)
bool IsWarpTileAttribute(uint8_t attribute)
bool IsHoleRoomTag(uint8_t tag)
const char * RoomDoorRoleName(RoomDoorRole role)
constexpr int kDungeonEntranceCount
Definition room_links.h:53
bool IsPitTileAttribute(uint8_t attribute)
std::function< const RoomLinkFacts *(int room_id)> RoomLinkFactsLookup
Definition room_links.h:147
constexpr uint8_t kTeleportDoorType
Definition room_links.h:55
std::array< bool, 4 > stair_slot_used
Definition room_links.h:108
std::array< bool, 4 > stair_slot_estimated
Definition room_links.h:109
std::vector< Door > doors
Definition room_links.h:119
std::array< uint8_t, 4 > stair_bytes
Definition room_links.h:106