yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
zscream_custom_layout.h
Go to the documentation of this file.
1#ifndef YAZE_ZELDA3_OVERWORLD_ZSCREAM_CUSTOM_LAYOUT_H_
2#define YAZE_ZELDA3_OVERWORLD_ZSCREAM_CUSTOM_LAYOUT_H_
3
4#include <algorithm>
5#include <array>
6#include <cstddef>
7#include <cstdint>
8
9#include "absl/status/status.h"
10#include "absl/status/statusor.h"
11#include "rom/rom.h"
12
14
15inline constexpr size_t kVersionMarkerPc = 0x140145;
16inline constexpr uint8_t kPerSheetCollisionMarker = 0x05;
17inline constexpr size_t kSheetCollisionTablePc = 0x141938;
18inline constexpr size_t kSheetCollisionTableSize = 0x2000;
19inline constexpr size_t kCollisionSheetCount = 128;
20inline constexpr size_t kCollisionsPerSheet = 64;
21inline constexpr size_t kResolvedSheetCount = 8;
22inline constexpr size_t kTile8CollisionCount = 512;
23
24using SheetCollisions = std::array<uint8_t, kCollisionsPerSheet>;
25using ResolvedSheetIds = std::array<uint8_t, kResolvedSheetCount>;
26using Tile8Collisions = std::array<uint8_t, kTile8CollisionCount>;
27
28// A raw layout marker is not a game identity, a complete compatibility profile,
29// or permission to save. Keep this independent of legacy GetVersion() semantics.
39
40inline LayoutDialect DetectLayout(const Rom& rom) {
41 const auto& bytes = rom.vector();
42 if (bytes.size() <= kVersionMarkerPc) {
44 }
45 switch (bytes[kVersionMarkerPc]) {
46 case 0x00:
47 case 0xFF:
49 case 0x01:
51 case 0x02:
53 case 0x03:
57 default:
59 }
60}
61
62inline const char* LayoutName(LayoutDialect dialect) {
63 switch (dialect) {
65 return "Unmarked layout";
67 return "Vanilla layout marker";
69 return "ZSCustomOverworld V1";
71 return "ZSCustomOverworld V2";
73 return "ZSCustomOverworld V3";
75 return "ZScream V5 per-sheet collisions";
77 return "Unknown ZScream layout marker";
78 }
79 return "Unknown ZScream layout marker";
80}
81
82// Necessary marker check only, not proof of free space. V5 places collision
83// data in the old tail/function-space region; unknown newer layouts must not
84// inherit V3's allocator. Missing markers fail closed in this narrow helper.
85inline bool CanUseTailExpansion(const Rom& rom) {
86 switch (DetectLayout(rom)) {
91 return true;
95 return false;
96 }
97 return false;
98}
99
100inline absl::Status ValidateSheetCollisionTable(const Rom& rom) {
102 return absl::FailedPreconditionError(
103 "Per-sheet collisions require raw ZScream marker 0x05");
104 }
106 return absl::OutOfRangeError(
107 "Incomplete ZScream V5 per-sheet collision table");
108 }
109 return absl::OkStatus();
110}
111
112// PC offsets address Rom's header-stripped bytes. Require the complete declared
113// table even when the requested early sheet would fit in a truncated image.
114inline absl::StatusOr<SheetCollisions> LoadSheetCollisions(const Rom& rom,
115 int sheet_id) {
116 if (sheet_id < 0 || sheet_id >= static_cast<int>(kCollisionSheetCount)) {
117 return absl::InvalidArgumentError("Collision sheet ID must be in [0, 128)");
118 }
119 const auto status = ValidateSheetCollisionTable(rom);
120 if (!status.ok()) {
121 return status;
122 }
123 const size_t offset = kSheetCollisionTablePc +
124 static_cast<size_t>(sheet_id) * kCollisionsPerSheet;
125 SheetCollisions collisions{};
126 std::copy_n(rom.vector().begin() + offset, kCollisionsPerSheet,
127 collisions.begin());
128 return collisions;
129}
130
131// NewCollisionLoad/.nextSheet reads eight already-resolved PriorSheets IDs.
132// (id XBA >> 2) is id*64; 32 words per sheet fill the next 64 output bytes.
133// Resolve main/aux/animated sheet selection at the caller; this function neither
134// guesses those IDs from a map nor substitutes a vanilla collision table.
135inline absl::StatusOr<Tile8Collisions> ComposeTile8Collisions(
136 const Rom& rom, const ResolvedSheetIds& sheet_ids) {
137 const auto status = ValidateSheetCollisionTable(rom);
138 if (!status.ok()) {
139 return status;
140 }
141 Tile8Collisions collisions{};
142 for (size_t slot = 0; slot < sheet_ids.size(); ++slot) {
143 const auto sheet = LoadSheetCollisions(rom, sheet_ids[slot]);
144 if (!sheet.ok()) {
145 return sheet.status();
146 }
147 std::copy(sheet->begin(), sheet->end(),
148 collisions.begin() + slot * kCollisionsPerSheet);
149 }
150 return collisions;
151}
152
157
158} // namespace yaze::zelda3::zscream
159
160#endif // YAZE_ZELDA3_OVERWORLD_ZSCREAM_CUSTOM_LAYOUT_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
const auto & vector() const
Definition rom.h:217
constexpr size_t kSheetCollisionTableSize
std::array< uint8_t, kCollisionsPerSheet > SheetCollisions
constexpr size_t kVersionMarkerPc
constexpr size_t kCollisionSheetCount
constexpr size_t kSheetCollisionTablePc
constexpr size_t kResolvedSheetCount
LayoutDialect DetectLayout(const Rom &rom)
std::array< uint8_t, kTile8CollisionCount > Tile8Collisions
std::array< uint8_t, kResolvedSheetCount > ResolvedSheetIds
bool CanUseTailExpansion(const Rom &rom)
constexpr uint8_t kPerSheetCollisionMarker
absl::StatusOr< SheetCollisions > LoadSheetCollisions(const Rom &rom, int sheet_id)
absl::Status ValidateSheetCollisionTable(const Rom &rom)
absl::StatusOr< Tile8Collisions > ComposeTile8Collisions(const Rom &rom, const ResolvedSheetIds &sheet_ids)
constexpr size_t kCollisionsPerSheet
constexpr size_t kTile8CollisionCount
const char * LayoutName(LayoutDialect dialect)