yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
downwards_routines.cc
Go to the documentation of this file.
2
5
6namespace yaze {
7namespace zelda3 {
8namespace draw_routines {
9
11 // Pattern: Draws 2x2 tiles downward (object 0x60)
12 // Size byte determines how many times to repeat (1-15 or 32)
13 int size = ctx.object.size_;
14 if (size == 0) size = 32; // Special case for object 0x60
15
16 for (int s = 0; s < size; s++) {
17 if (ctx.tiles.size() >= 4) {
18 // Draw 2x2 pattern in COLUMN-MAJOR order (matching assembly)
19 // Assembly uses indirect pointers: $BF, $CB, $C2, $CE
20 // tiles[0] → $BF → (col 0, row 0) = top-left
21 // tiles[1] → $CB → (col 0, row 1) = bottom-left
22 // tiles[2] → $C2 → (col 1, row 0) = top-right
23 // tiles[3] → $CE → (col 1, row 1) = bottom-right
25 ctx.object.y_ + (s * 2),
26 ctx.tiles[0]); // col 0, row 0
28 ctx.object.y_ + (s * 2) + 1,
29 ctx.tiles[1]); // col 0, row 1
31 ctx.object.y_ + (s * 2),
32 ctx.tiles[2]); // col 1, row 0
34 ctx.object.y_ + (s * 2) + 1,
35 ctx.tiles[3]); // col 1, row 1
36 }
37 }
38}
39
41 // Pattern: Draws 4x2 tiles downward (objects 0x61-0x62)
42 // This is 4 columns × 2 rows = 8 tiles in ROW-MAJOR order (per ZScream)
43 int size = ctx.object.size_;
44 if (size == 0) size = 26; // Special case
45
46 for (int s = 0; s < size; s++) {
47 if (ctx.tiles.size() >= 8) {
48 // Draw 4x2 pattern in ROW-MAJOR order (matching ZScream)
49 // Row 0: tiles 0, 1, 2, 3 at x+0, x+1, x+2, x+3
51 ctx.object.y_ + (s * 2), ctx.tiles[0]);
53 ctx.object.y_ + (s * 2), ctx.tiles[1]);
55 ctx.object.y_ + (s * 2), ctx.tiles[2]);
57 ctx.object.y_ + (s * 2), ctx.tiles[3]);
58 // Row 1: tiles 4, 5, 6, 7 at x+0, x+1, x+2, x+3
60 ctx.object.y_ + (s * 2) + 1, ctx.tiles[4]);
62 ctx.object.y_ + (s * 2) + 1, ctx.tiles[5]);
64 ctx.object.y_ + (s * 2) + 1, ctx.tiles[6]);
66 ctx.object.y_ + (s * 2) + 1, ctx.tiles[7]);
67 } else if (ctx.tiles.size() >= 4) {
68 // Fallback: with 4 tiles draw 4x1 row pattern
70 ctx.object.y_ + (s * 2), ctx.tiles[0]);
72 ctx.object.y_ + (s * 2), ctx.tiles[1]);
74 ctx.object.y_ + (s * 2), ctx.tiles[2]);
76 ctx.object.y_ + (s * 2), ctx.tiles[3]);
77 }
78 }
79}
80
82 // Pattern: Same as above but draws to both BG1 and BG2 (objects 0x63-0x64)
84 // Note: BothBG would require access to both buffers - simplified for now
85}
86
88 // Pattern: Draws 4x2 decoration downward with spacing (objects 0x65-0x66)
89 // This is 4 columns × 2 rows = 8 tiles in ROW-MAJOR order with 6-tile Y
90 // spacing.
91 int size = ctx.object.size_ & 0x0F;
92
93 // Assembly: GetSize_1to16, so count = size + 1
94 int count = size + 1;
95
96 for (int s = 0; s < count; s++) {
97 if (ctx.tiles.size() >= 8) {
98 // Draw 4x2 pattern in ROW-MAJOR order:
99 // Row 0: tiles[0..3], Row 1: tiles[4..7].
100 const int base_y = ctx.object.y_ + (s * 6);
102 ctx.tiles[0]);
103 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 1, base_y,
104 ctx.tiles[1]);
105 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 2, base_y,
106 ctx.tiles[2]);
107 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_ + 3, base_y,
108 ctx.tiles[3]);
109 DrawRoutineUtils::WriteTile8(ctx.target_bg, ctx.object.x_, base_y + 1,
110 ctx.tiles[4]);
112 base_y + 1, ctx.tiles[5]);
114 base_y + 1, ctx.tiles[6]);
116 base_y + 1, ctx.tiles[7]);
117 }
118 }
119}
120
122 // Pattern: Draws 2x2 tiles downward (objects 0x67-0x68)
123 int size = ctx.object.size_ & 0x0F;
124
125 // Assembly: GetSize_1to16, so count = size + 1
126 int count = size + 1;
127
128 for (int s = 0; s < count; s++) {
129 if (ctx.tiles.size() >= 4) {
130 // Draw 2x2 pattern in COLUMN-MAJOR order (matching assembly)
131 // tiles[0] → col 0, row 0 = top-left
132 // tiles[1] → col 0, row 1 = bottom-left
133 // tiles[2] → col 1, row 0 = top-right
134 // tiles[3] → col 1, row 1 = bottom-right
136 ctx.object.y_ + (s * 2),
137 ctx.tiles[0]); // col 0, row 0
139 ctx.object.y_ + (s * 2) + 1,
140 ctx.tiles[1]); // col 0, row 1
142 ctx.object.y_ + (s * 2),
143 ctx.tiles[2]); // col 1, row 0
145 ctx.object.y_ + (s * 2) + 1,
146 ctx.tiles[3]); // col 1, row 1
147 }
148 }
149}
150
152 // Pattern: Vertical rail with corner/middle/end (object 0x69)
153 int size = ctx.object.size_ & 0x0F;
154 int count = size + 1;
155
156 if (ctx.tiles.size() < 3) return;
157
158 int y = ctx.object.y_;
160 y++;
161 for (int s = 0; s < count; s++) {
163 y++;
164 }
166}
167
169 // Pattern: 1x1 edge tiles downward (objects 0x6A-0x6B)
170 int size = ctx.object.size_ & 0x0F;
171
172 // Assembly: GetSize_1to16, so count = size + 1
173 int count = size + 1;
174
175 for (int s = 0; s < count; s++) {
176 if (ctx.tiles.size() >= 1) {
177 // Use first 8x8 tile from span
179 ctx.object.y_ + s, ctx.tiles[0]);
180 }
181 }
182}
183
185 // Pattern: Left corner 2x1 tiles with +12 offset downward (object 0x6C)
186 int size = ctx.object.size_ & 0x0F;
187
188 // Assembly: GetSize_1to16_timesA(0x0A), so count = size + 10
189 int count = size + 10;
190
191 for (int s = 0; s < count; s++) {
192 if (ctx.tiles.size() >= 2) {
193 // Use first tile span for 2x1 pattern
195 ctx.object.y_ + s, ctx.tiles[0]);
197 ctx.object.y_ + s, ctx.tiles[1]);
198 }
199 }
200}
201
203 // Pattern: Right corner 2x1 tiles with +12 offset downward (object 0x6D)
204 int size = ctx.object.size_ & 0x0F;
205
206 // Assembly: GetSize_1to16_timesA(0x0A), so count = size + 10
207 int count = size + 10;
208
209 for (int s = 0; s < count; s++) {
210 if (ctx.tiles.size() >= 2) {
211 // Use first tile span for 2x1 pattern
213 ctx.object.y_ + s, ctx.tiles[0]);
215 ctx.object.y_ + s, ctx.tiles[1]);
216 }
217 }
218}
219
220void RegisterDownwardsRoutines(std::vector<DrawRoutineInfo>& registry) {
221 using Category = DrawRoutineInfo::Category;
222
223 registry.push_back(DrawRoutineInfo{
224 .id = 7, // RoomDraw_Downwards2x2_1to15or32
225 .name = "Downwards2x2_1to15or32",
226 .function = DrawDownwards2x2_1to15or32,
227 .draws_to_both_bgs = false,
228 .base_width = 2,
229 .base_height = 2,
230 .min_tiles = 4, // 2x2 block
231 .category = Category::Downwards});
232
233 registry.push_back(DrawRoutineInfo{
234 .id = 8, // RoomDraw_Downwards4x2_1to15or26
235 .name = "Downwards4x2_1to15or26",
236 .function = DrawDownwards4x2_1to15or26,
237 // USDASM: RoomDraw_Downwards4x2_1to15or26 ($01:8A89) jumps to
238 // RoomDraw_Downwards4x2VariableSpacing ($01:B220) which writes through
239 // the current tilemap pointers (single-layer).
240 .draws_to_both_bgs = false,
241 .base_width = 4,
242 .base_height = 2,
243 .min_tiles = 8, // 4x2 block
244 .category = Category::Downwards});
245
246 registry.push_back(DrawRoutineInfo{
247 .id = 9, // RoomDraw_Downwards4x2_1to16_BothBG
248 .name = "Downwards4x2_1to16_BothBG",
250 .draws_to_both_bgs = true,
251 .base_width = 4,
252 .base_height = 2,
253 .min_tiles = 8, // 4x2 block
254 .category = Category::Downwards});
255
256 registry.push_back(DrawRoutineInfo{
257 .id = 10, // RoomDraw_DownwardsDecor4x2spaced4_1to16
258 .name = "DownwardsDecor4x2spaced4_1to16",
260 .draws_to_both_bgs = false,
261 .base_width = 4,
262 .base_height = 2,
263 .min_tiles = 8, // 4x2 block
264 .category = Category::Downwards});
265
266 registry.push_back(DrawRoutineInfo{
267 .id = 11, // RoomDraw_Downwards2x2_1to16
268 .name = "Downwards2x2_1to16",
269 .function = DrawDownwards2x2_1to16,
270 .draws_to_both_bgs = false,
271 .base_width = 2,
272 .base_height = 2,
273 .min_tiles = 4, // 2x2 block
274 .category = Category::Downwards});
275
276 registry.push_back(DrawRoutineInfo{
277 .id = 12, // RoomDraw_DownwardsHasEdge1x1_1to16_plus3
278 .name = "DownwardsHasEdge1x1_1to16_plus3",
280 .draws_to_both_bgs = false,
281 .base_width = 1,
282 .base_height = 3,
283 .min_tiles = 3, // top edge + middle + bottom edge
284 .category = Category::Downwards});
285
286 registry.push_back(DrawRoutineInfo{
287 .id = 13, // RoomDraw_DownwardsEdge1x1_1to16
288 .name = "DownwardsEdge1x1_1to16",
289 .function = DrawDownwardsEdge1x1_1to16,
290 .draws_to_both_bgs = false,
291 .base_width = 1,
292 .base_height = 1,
293 .min_tiles = 1, // single repeated tile
294 .category = Category::Downwards});
295
296 registry.push_back(DrawRoutineInfo{
297 .id = 14, // RoomDraw_DownwardsLeftCorners2x1_1to16_plus12
298 .name = "DownwardsLeftCorners2x1_1to16_plus12",
300 .draws_to_both_bgs = false,
301 .base_width = 2,
302 .base_height = 1,
303 .min_tiles = 2, // 2x1 block
304 .category = Category::Downwards});
305
306 registry.push_back(DrawRoutineInfo{
307 .id = 15, // RoomDraw_DownwardsRightCorners2x1_1to16_plus12
308 .name = "DownwardsRightCorners2x1_1to16_plus12",
310 .draws_to_both_bgs = false,
311 .base_width = 2,
312 .base_height = 1,
313 .min_tiles = 2, // 2x1 block
314 .category = Category::Downwards});
315}
316
317} // namespace draw_routines
318} // namespace zelda3
319} // namespace yaze
void WriteTile8(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info)
Write an 8x8 tile to the background buffer.
void DrawDownwards4x2_1to15or26(const DrawContext &ctx)
Draw 4x2 tiles downward pattern (1-15 or 26 iterations)
void DrawDownwardsEdge1x1_1to16(const DrawContext &ctx)
Draw 1x1 edge tiles downward (1-16 iterations)
void DrawDownwards2x2_1to15or32(const DrawContext &ctx)
Draw 2x2 tiles downward pattern (1-15 or 32 iterations)
void DrawDownwards2x2_1to16(const DrawContext &ctx)
Draw 2x2 tiles downward pattern (1-16 iterations)
void RegisterDownwardsRoutines(std::vector< DrawRoutineInfo > &registry)
Register all downwards draw routines to the registry.
void DrawDownwardsHasEdge1x1_1to16_plus3(const DrawContext &ctx)
Draw 1x1 tiles with edge detection +3 downward.
void DrawDownwardsLeftCorners2x1_1to16_plus12(const DrawContext &ctx)
Draw left corner 2x1 tiles with +12 offset downward.
void DrawDownwardsRightCorners2x1_1to16_plus12(const DrawContext &ctx)
Draw right corner 2x1 tiles with +12 offset downward.
void DrawDownwardsDecor4x2spaced4_1to16(const DrawContext &ctx)
Draw 4x2 decoration downward with spacing (1-16 iterations)
void DrawDownwards4x2_1to16_BothBG(const DrawContext &ctx)
Draw 4x2 tiles downward pattern for both BG layers.
Context passed to draw routines containing all necessary state.
std::span< const gfx::TileInfo > tiles
gfx::BackgroundBuffer & target_bg
Metadata about a draw routine.