yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
sprite.cc
Go to the documentation of this file.
1#include "sprite.h"
2#include "sprite_names.h"
3
4#include <algorithm>
5#include <cstdint>
6#include <iostream>
7
11
12namespace yaze {
13namespace zelda3 {
14
15// Define sprite names in a single translation unit to avoid SIOF
16const std::string kSpriteDefaultNames[256] = {
17 "00 Raven",
18 "01 Vulture",
19 "02 Flying Stalfos Head",
20 "03 No Pointer (Empty",
21 "04 Pull Switch (good",
22 "05 Pull Switch (unused",
23 "06 Pull Switch (bad",
24 "07 Pull Switch (unused",
25 "08 Octorock (one way",
26 "09 Moldorm (Boss",
27 "0A Octorock (four way",
28 "0B Chicken",
29 "0C Octorock (?",
30 "0D Buzzblock",
31 "0E Snapdragon",
32 "0F Octoballoon",
33 "10 Octoballon Hatchlings",
34 "11 Hinox",
35 "12 Moblin",
36 "13 Mini Helmasaure",
37 "14 Gargoyle's Domain Gate",
38 "15 Antifairy",
39 "16 Sahasrahla / Aginah",
40 "17 Bush Hoarder",
41 "18 Mini Moldorm",
42 "19 Poe",
43 "1A Dwarves",
44 "1B Arrow in wall",
45 "1C Statue",
46 "1D Weathervane",
47 "1E Crystal Switch",
48 "1F Bug-Catching Kid",
49 "20 Sluggula",
50 "21 Push Switch",
51 "22 Ropa",
52 "23 Red Bari",
53 "24 Blue Bari",
54 "25 Talking Tree",
55 "26 Hardhat Beetle",
56 "27 Deadrock",
57 "28 Storytellers",
58 "29 Blind Hideout attendant",
59 "2A Sweeping Lady",
60 "2B Storytellers",
61 "2C Lumberjacks",
62 "2D Telepathic Stones",
63 "2E Multipurpose Sprite",
64 "2F Race Npc",
65 "30 Person?",
66 "31 Fortune Teller",
67 "32 Angry Brothers",
68 "33 Pull for items",
69 "34 Scared Girl",
70 "35 Innkeeper",
71 "36 Witch",
72 "37 Waterfall",
73 "38 Arrow Target",
74 "39 Average Middle",
75 "3A Half Magic Bat",
76 "3B Dash Item",
77 "3C Village Kid",
78 "3D Signs? Chicken lady also showed up / Scared ladies outside houses.",
79 "3E Rock Hoarder",
80 "3F Tutorial Soldier",
81 "40 Lightning Lock",
82 "41 Blue Sword Soldier / Used by guards to detect player",
83 "42 Green Sword Soldier",
84 "43 Red Spear Soldier",
85 "44 Assault Sword Soldier",
86 "45 Green Spear Soldier",
87 "46 Blue Archer",
88 "47 Green Archer",
89 "48 Red Javelin Soldier",
90 "49 Red Javelin Soldier 2",
91 "4A Red Bomb Soldiers",
92 "4B Green Soldier Recruits",
93 "4C Geldman",
94 "4D Rabbit",
95 "4E Popo",
96 "4F Popo 2",
97 "50 Cannon Balls",
98 "51 Armos",
99 "52 Giant Zora",
100 "53 Armos Knights (Boss",
101 "54 Lanmolas (Boss",
102 "55 Fireball Zora",
103 "56 Walking Zora",
104 "57 Desert Palace Barriers",
105 "58 Crab",
106 "59 Bird",
107 "5A Squirrel",
108 "5B Spark (Left to Right",
109 "5C Spark (Right to Left",
110 "5D Roller (vertical moving",
111 "5E Roller (vertical moving",
112 "5F Roller",
113 "60 Roller (horizontal moving",
114 "61 Beamos",
115 "62 Master Sword",
116 "63 Devalant (Non",
117 "64 Devalant (Shooter",
118 "65 Shooting Gallery Proprietor",
119 "66 Moving Cannon Ball Shooters (Right",
120 "67 Moving Cannon Ball Shooters (Left",
121 "68 Moving Cannon Ball Shooters (Down",
122 "69 Moving Cannon Ball Shooters (Up",
123 "6A Ball N' Chain Trooper",
124 "6B Cannon Soldier",
125 "6C Mirror Portal",
126 "6D Rat",
127 "6E Rope",
128 "6F Keese",
129 "70 Helmasaur King Fireball",
130 "71 Leever",
131 "72 Activator for the ponds (where you throw in items",
132 "73 Uncle / Priest",
133 "74 Running Man",
134 "75 Bottle Salesman",
135 "76 Princess Zelda",
136 "77 Antifairy (Alternate",
137 "78 Village Elder",
138 "79 Bee",
139 "7A Agahnim",
140 "7B Agahnim Energy Ball",
141 "7C Hyu",
142 "7D Big Spike Trap",
143 "7E Guruguru Bar (Clockwise",
144 "7F Guruguru Bar (Counter Clockwise",
145 "80 Winder",
146 "81 Water Tektite",
147 "82 Antifairy Circle",
148 "83 Green Eyegore",
149 "84 Red Eyegore",
150 "85 Yellow Stalfos",
151 "86 Kodongos",
152 "87 Flames",
153 "88 Mothula (Boss",
154 "89 Mothula's Beam",
155 "8A Spike Trap",
156 "8B Gibdo",
157 "8C Arrghus (Boss",
158 "8D Arrghus spawn",
159 "8E Terrorpin",
160 "8F Slime",
161 "90 Wallmaster",
162 "91 Stalfos Knight",
163 "92 Helmasaur King",
164 "93 Bumper",
165 "94 Swimmers",
166 "95 Eye Laser (Right",
167 "96 Eye Laser (Left",
168 "97 Eye Laser (Down",
169 "98 Eye Laser (Up",
170 "99 Pengator",
171 "9A Kyameron",
172 "9B Wizzrobe",
173 "9C Tadpoles",
174 "9D Tadpoles",
175 "9E Ostrich (Haunted Grove",
176 "9F Flute",
177 "A0 Birds (Haunted Grove",
178 "A1 Freezor",
179 "A2 Kholdstare (Boss",
180 "A3 Kholdstare's Shell",
181 "A4 Falling Ice",
182 "A5 Zazak Fireball",
183 "A6 Red Zazak",
184 "A7 Stalfos",
185 "A8 Bomber Flying Creatures from Darkworld",
186 "A9 Bomber Flying Creatures from Darkworld",
187 "AA Pikit",
188 "AB Maiden",
189 "AC Apple",
190 "AD Lost Old Man",
191 "AE Down Pipe",
192 "AF Up Pipe",
193 "B0 Right Pip",
194 "B1 Left Pipe",
195 "B2 Good bee again?",
196 "B3 Hylian Inscription",
197 "B4 Thief?s chest (not the one that follows you",
198 "B5 Bomb Salesman",
199 "B6 Kiki",
200 "B7 Maiden following you in Blind Dungeon",
201 "B8 Monologue Testing Sprite",
202 "B9 Feuding Friends on Death Mountain",
203 "BA Whirlpool",
204 "BB Salesman / chestgame guy / 300 rupee giver guy / Chest game thief",
205 "BC Drunk in the inn",
206 "BD Vitreous (Large Eyeball",
207 "BE Vitreous (Small Eyeball",
208 "BF Vitreous' Lightning",
209 "C0 Monster in Lake of Ill Omen / Quake Medallion",
210 "C1 Agahnim teleporting Zelda to dark world",
211 "C2 Boulders",
212 "C3 Gibo",
213 "C4 Thief",
214 "C5 Medusa",
215 "C6 Four Way Fireball Spitters (spit when you use your sword",
216 "C7 Hokku",
217 "C8 Big Fairy who heals you",
218 "C9 Tektite",
219 "CA Chain Chomp",
220 "CB Trinexx",
221 "CC Another part of trinexx",
222 "CD Yet another part of trinexx",
223 "CE Blind The Thief (Boss)",
224 "CF Swamola",
225 "D0 Lynel",
226 "D1 Bunny Beam",
227 "D2 Flopping fish",
228 "D3 Stal",
229 "D4 Landmine",
230 "D5 Digging Game Proprietor",
231 "D6 Ganon",
232 "D7 Copy of Ganon",
233 "D8 Heart",
234 "D9 Green Rupee",
235 "DA Blue Rupee",
236 "DB Red Rupee",
237 "DC Bomb Refill (1)",
238 "DD Bomb Refill (4)",
239 "DE Bomb Refill (8)",
240 "DF Small Magic Refill",
241 "E0 Full Magic Refill",
242 "E1 Arrow Refill (5)",
243 "E2 Arrow Refill (10)",
244 "E3 Fairy",
245 "E4 Key",
246 "E5 Big Key",
247 "E6 Shield",
248 "E7 Mushroom",
249 "E8 Fake Master Sword",
250 "E9 Magic Shop dude / His items",
251 "EA Heart Container",
252 "EB Heart Piece",
253 "EC Bushes",
254 "ED Cane Of Somaria Platform",
255 "EE Mantle",
256 "EF Cane of Somaria Platform (Unused)",
257 "F0 Cane of Somaria Platform (Unused)",
258 "F1 Cane of Somaria Platform (Unused)",
259 "F2 Medallion Tablet",
260 "F3",
261 "F4 Falling Rocks",
262 "F5",
263 "F6",
264 "F7",
265 "F8",
266 "F9",
267 "FA",
268 "FB",
269 "FC",
270 "FD",
271 "FE",
272 "FF",
273};
274
275// Legacy global state - now delegates to ResourceLabelProvider
279
283
284// Thread-local storage for the resolved name (for C-string return compatibility)
285static thread_local std::string g_resolved_sprite_name;
286
287const char* ResolveSpriteName(uint16_t id) {
288 // Use the unified ResourceLabelProvider for resolution
289 g_resolved_sprite_name =
291 return g_resolved_sprite_name.c_str();
292}
293
294// hmagic-derived expanded names (0x11c entries), see tools/decode_sprname.py.
295extern const char* const kSpriteNames[];
296extern const size_t kSpriteNameCount;
297
298// Define overlord names in a single translation unit to avoid SIOF
299const std::string kOverlordNames[26] = {
300 "Overlord_SpritePositionTarget",
301 "Overlord_AllDirectionMetalBallFactory",
302 "Overlord_CascadeMetalBallFactory",
303 "Overlord_StalfosFactory",
304 "Overlord_StalfosTrap",
305 "Overlord_SnakeTrap",
306 "Overlord_MovingFloor",
307 "Overlord_ZolFactory",
308 "Overlord_WallMasterFactory",
309 "Overlord_CrumbleTilePath 1",
310 "Overlord_CrumbleTilePath 2",
311 "Overlord_CrumbleTilePath 3",
312 "Overlord_CrumbleTilePath 4",
313 "Overlord_CrumbleTilePath 5",
314 "Overlord_CrumbleTilePath 6",
315 "Overlord_PirogusuFactory 1",
316 "Overlord_PirogusuFactory 2",
317 "Overlord_PirogusuFactory 3",
318 "Overlord_PirogusuFactory 4",
319 "Overlord_FlyingTileFactory",
320 "Overlord_WizzrobeFactory",
321 "Overlord_ZoroFactory",
322 "Overlord_StalfosTrapTriggerWindow",
323 "Overlord_RedStalfosTrap",
324 "Overlord_ArmosCoordinator",
325 "Overlord_BombTrap",
326};
327
328void Sprite::UpdateMapProperties(uint16_t map_id, const void* context) {
329 (void)context; // Not used by sprites currently
330 map_x_ = x_;
331 map_y_ = y_;
333}
334
335void Sprite::UpdateCoordinates(int map_x, int map_y) {
336 map_x_ = map_x;
337 map_y_ = map_y;
338}
339
341 uint8_t x = nx_;
342 uint8_t y = ny_;
343
344 if (overlord_ == 0x07) {
345 if (id_ == 0x1A) {
346 DrawSpriteTile((x * 16), (y * 16), 14, 6, 11); // bomb
347 } else if (id_ == 0x05) {
348 DrawSpriteTile((x * 16), (y * 16) - 12, 12, 16, 12, false, true);
349 DrawSpriteTile((x * 16), (y * 16), 0, 16, 12, false, true);
350 } else if (id_ == 0x06) {
351 DrawSpriteTile((x * 16), (y * 16), 10, 26, 14, true, true, 2,
352 2); // snek
353 } else if (id_ == 0x09) {
354 DrawSpriteTile((x * 16), (y * 16), 6, 26, 14);
355 DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 8, 26, 14);
356 DrawSpriteTile((x * 16), (y * 16) + 16, 10, 27, 14, false, false, 1, 1);
357 } else if (id_ == 0x14) {
358 DrawSpriteTile((x * 16), (y * 16) + 8, 12, 06, 12, false, false, 2,
359 1); // shadow tile
360 DrawSpriteTile((x * 16), (y * 16) - 8, 3, 29, 8, false, false, 1,
361 1); // tile
362 DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 3, 29, 8, true, false, 1,
363 1); // tile
364 DrawSpriteTile((x * 16), (y * 16), 3, 29, 8, false, true, 1,
365 1); // tile
366 DrawSpriteTile((x * 16) + 8, (y * 16), 3, 29, 8, true, true, 1,
367 1); // tile
368 } else {
369 DrawSpriteTile((x * 16), (y * 16), 4, 4, 5);
370 }
371
372 if (nx_ != x || ny_ != y) {
373 bounding_box_.x = (lower_x_ + (nx_ * 16));
374 bounding_box_.y = (lower_y_ + (ny_ * 16));
377 } else {
378 bounding_box_.x = (lower_x_ + (x * 16));
379 bounding_box_.y = (lower_y_ + (y * 16));
382 }
383
384 return;
385 }
386
387 if (id_ == 0x00) {
388 DrawSpriteTile((x * 16), (y * 16), 4, 28, 10);
389 } else if (id_ == 0x01) {
390 DrawSpriteTile((x * 16) - 8, (y * 16), 6, 24, 12, false, false, 2, 2);
391 DrawSpriteTile((x * 16) + 8, (y * 16), 6, 24, 12, true, false, 2, 2);
392 } else if (id_ == 0x02) {
393 DrawSpriteTile((x * 16), (y * 16), 0, 16, 10);
394 } else if (id_ == 0x04) {
395 uint8_t p = 3;
396
397 DrawSpriteTile((x * 16), (y * 16), 14, 28, p);
398 DrawSpriteTile((x * 16), (y * 16), 14, 30, p);
399 } else if (id_ == 0x05) {
400 uint8_t p = 3;
401
402 DrawSpriteTile((x * 16), (y * 16), 14, 28, p);
403 DrawSpriteTile((x * 16), (y * 16), 14, 30, p);
404 } else if (id_ == 0x06) {
405 uint8_t p = 3;
406
407 DrawSpriteTile((x * 16), (y * 16), 14, 28, p);
408 DrawSpriteTile((x * 16), (y * 16), 14, 30, p);
409 } else if (id_ == 0x07) {
410 uint8_t p = 3;
411
412 DrawSpriteTile((x * 16), (y * 16), 14, 28, p);
413 DrawSpriteTile((x * 16), (y * 16), 14, 30, p);
414 } else if (id_ == 0x08) {
415 DrawSpriteTile((x * 16), (y * 16), 0, 24, 6);
416 DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 6, false, false, 1, 1);
417 } else if (id_ == 0x09) {
418 DrawSpriteTile((x * 16) - 22, (y * 16) - 24, 12, 24, 12, false, false, 2,
419 2); // Moldorm tail
420 DrawSpriteTile((x * 16) - 16, (y * 16) - 20, 8, 24, 12, false, false, 2,
421 2); // Moldorm b2
422 DrawSpriteTile((x * 16) - 12, (y * 16) - 16, 4, 24, 12, false, false, 4,
423 4); // Moldorm b
424 DrawSpriteTile((x * 16), (y * 16), 0, 24, 12, false, false, 4,
425 4); // Moldorm head
426
427 DrawSpriteTile((x * 16) + 20, (y * 16) + 12, 8, 26, 14, false, false, 2,
428 2); // Moldorm eye
429 DrawSpriteTile((x * 16) + 12, (y * 16) + 20, 8, 26, 14, false, false, 2,
430 2); // Moldorm eye
431 } else if (id_ == 0x0A) {
432 DrawSpriteTile((x * 16), (y * 16), 0, 24, 8);
433 DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 8, false, false, 1, 1);
434 } else if (id_ == 0x0B) {
435 DrawSpriteTile((x * 16), (y * 16), 10, 30, 10);
436 } else if (id_ == 0x0C) {
437 DrawSpriteTile((x * 16), (y * 16), 0, 24, 8);
438 DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 8, false, false, 1, 1);
439 } else if (id_ == 0x0D) {
440 DrawSpriteTile((x * 16), (y * 16), 14, 28, 12);
441 } else if (id_ == 0x0E) {
442 DrawSpriteTile((x * 16), (y * 16), 8, 18, 10, false, false, 3, 2);
443 } else if (id_ == 0x0F) {
444 DrawSpriteTile((x * 16), (y * 16), 14, 24, 8, false, false, 2, 3);
445 DrawSpriteTile((x * 16) + 16, (y * 16), 30, 8, 8, true, false, 1, 3);
446 } else if (id_ == 0x10) {
447 DrawSpriteTile((x * 16), (y * 16), 12, 31, 8, false, false, 1, 1);
448 } else if (id_ == 0x11) {
449 DrawSpriteTile((x * 16), (y * 16) + 16, 6, 16, 8, false, false, 2,
450 2); // Feet
451 DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 4, 18, 8, false, false, 2,
452 2); // Body1
453 DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 4, 18, 8, true, false, 2,
454 2); // Body2
455 DrawSpriteTile((x * 16), (y * 16), 0, 16, 8, false, false, 2,
456 2); // Head
457 } else if (id_ == 0x12) {
458 DrawSpriteTile((x * 16), (y * 16) + 8, 8, 26, 8);
459 DrawSpriteTile((x * 16), (y * 16), 6, 24, 8);
460 } else if (id_ == 0x13) {
461 DrawSpriteTile((x * 16), (y * 16), 4, 22, 2);
462 } else if (id_ == 0x15) {
463 // Antifairy
464 DrawSpriteTile((x * 16) + 2, (y * 16) + 8, 3, 30, 5, false, false, 1, 1);
465 DrawSpriteTile((x * 16) + 8, (y * 16) + 2, 3, 30, 5, false, false, 1, 1);
466 DrawSpriteTile((x * 16) + 14, (y * 16) + 8, 3, 30, 5, false, false, 1, 1);
467 DrawSpriteTile((x * 16) + 8, (y * 16) + 14, 3, 30, 5, false, false, 1, 1);
468 DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 1, 30, 5, false, false, 1,
469 1); // Middle
470 } else if (id_ == 0x16) {
471 DrawSpriteTile((x * 16), (y * 16) + 8, 2, 26, 2);
472 DrawSpriteTile((x * 16), (y * 16), 0, 26, 2);
473 } else if (id_ == 0x17) // Bush hoarder
474 {
475 DrawSpriteTile((x * 16), (y * 16), 8, 30, 10);
476 } else if (id_ == 0x18) // Mini moldorm
477 {
478 DrawSpriteTile((x * 16) + 13, (y * 16) + 17, 13, 21, 8, false, false, 1,
479 1); // Tail
480 DrawSpriteTile((x * 16) + 5, (y * 16) + 8, 2, 22, 8); // Body
481 DrawSpriteTile((x * 16), (y * 16), 0, 22, 8); // Head
482 DrawSpriteTile((x * 16), (y * 16) - 4, 13, 20, 8, false, false, 1,
483 1); // Eyes
484 DrawSpriteTile((x * 16) - 4, (y * 16), 13, 20, 8, false, false, 1,
485 1); // Eyes
486 } else if (id_ == 0x19) // Poe - ghost
487 {
488 DrawSpriteTile((x * 16), (y * 16), 6, 31, 2); //
489 } else if (id_ == 0x1A) // Smith
490 {
491 // DrawSpriteTile((x*16), (y *16), 2, 4, 10,true); // Smitty
492 // DrawSpriteTile((x*16)+12, (y *16) - 7, 0, 6, 10); // Hammer
493 DrawSpriteTile((x * 16), (y * 16), 4, 22, 10);
494 } else if (id_ == 0x1C) // Statue
495 {
496 DrawSpriteTile((x * 16), (y * 16) + 8, 0, 28, 15);
497 DrawSpriteTile((x * 16), (y * 16), 2, 28, 15, false, false, 1, 1);
498 DrawSpriteTile((x * 16) + 8, (y * 16), 2, 28, 15, true, false, 1, 1);
499 } else if (id_ == 0x1E) // Crystal switch
500 {
501 DrawSpriteTile((x * 16), (y * 16), 4, 30, 5);
502 } else if (id_ == 0x1F) // Sick kid
503 {
504 DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 10, 16, 14);
505 DrawSpriteTile((x * 16) + 16 - 8, (y * 16) + 8, 10, 16, 14, true);
506 DrawSpriteTile((x * 16) - 8, (y * 16) + 16, 10, 16, 14, false, true, 2, 2);
507 DrawSpriteTile((x * 16) + 16 - 8, (y * 16) + 16, 10, 16, 14, true, true, 2,
508 2);
509 DrawSpriteTile((x * 16), (y * 16) - 4, 14, 16, 10);
510 } else if (id_ == 0x20) {
511 DrawSpriteTile((x * 16), (y * 16), 2, 24, 7);
512 } else if (id_ == 0x21) // Push switch
513 {
514 DrawSpriteTile((x * 16) + 4, (y * 16) + 20, 13, 29, 3, false, false, 1, 1);
515 DrawSpriteTile((x * 16) + 4, (y * 16) + 28, 12, 29, 3, false, false, 1, 1);
516 DrawSpriteTile((x * 16), (y * 16) + 8, 10, 28, 3);
517 } else if (id_ == 0x22) // Rope
518 {
519 DrawSpriteTile((x * 16), (y * 16), 8, 26, 5);
520 } else if (id_ == 0x23) // Red bari
521 {
522 DrawSpriteTile((x * 16), (y * 16), 2, 18, 4, false, false, 1, 2);
523 DrawSpriteTile((x * 16) + 8, (y * 16), 2, 18, 4, true, false, 1, 2);
524 } else if (id_ == 0x24) // Blue bari
525 {
526 DrawSpriteTile((x * 16), (y * 16), 2, 18, 6, false, false, 1, 2);
527 DrawSpriteTile((x * 16) + 8, (y * 16), 2, 18, 6, true, false, 1, 2);
528 } else if (id_ == 0x25) // Talking tree?
529 {
530 // TODO: Add something here?
531 } else if (id_ == 0x26) // Hardhat beetle
532 {
533 if ((x & 0x01) == 0x00) {
534 DrawSpriteTile((x * 16), (y * 16), 4, 20, 8);
535 DrawSpriteTile((x * 16), (y * 16) - 6, 0, 20, 8);
536 } else {
537 DrawSpriteTile((x * 16), (y * 16), 4, 20, 10);
538 DrawSpriteTile((x * 16), (y * 16) - 6, 0, 20, 10);
539 }
540 } else if (id_ == 0x27) // Deadrock
541 {
542 DrawSpriteTile((x * 16), (y * 16), 2, 30, 10);
543 } else if (id_ == 0x28) // Npcs
544 {
545 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
546 } else if (id_ == 0x29) // Npcs
547 {
548 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
549 } else if (id_ == 0x2A) // Npcs
550 {
551 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
552 } else if (id_ == 0x2B) // ???
553 {
554 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
555 } else if (id_ == 0x2C) // Lumberjack
556 {
557 DrawSpriteTile((x * 16) - 24, (y * 16) + 12, 6, 26, 12, true); // Body
558 DrawSpriteTile((x * 16) - 24, (y * 16), 8, 26, 12, true); // Head
559
560 DrawSpriteTile((x * 16) - 14, (y * 16) + 12, 14, 27, 10, false, false, 1,
561 1); // Saw left edge
562 DrawSpriteTile((x * 16) - 6, (y * 16) + 12, 15, 27, 10, false, false, 1,
563 1); // Saw left edge
564 DrawSpriteTile((x * 16) + 2, (y * 16) + 12, 15, 27, 10, false, false, 1,
565 1); // Saw left edge
566 DrawSpriteTile((x * 16) + 10, (y * 16) + 12, 15, 27, 10, false, false, 1,
567 1); // Saw left edge
568 DrawSpriteTile((x * 16) + 18, (y * 16) + 12, 15, 27, 10, false, false, 1,
569 1); // Saw left edge
570 DrawSpriteTile((x * 16) + 26, (y * 16) + 12, 15, 27, 10, false, false, 1,
571 1); // Saw left edge
572 DrawSpriteTile((x * 16) + 34, (y * 16) + 12, 14, 27, 10, true, false, 1,
573 1); // Saw left edge
574
575 DrawSpriteTile((x * 16) + 40, (y * 16) + 12, 4, 26, 12); // Body
576 DrawSpriteTile((x * 16) + 40, (y * 16), 8, 26, 12); // Head
577 } else if (id_ == 0x2D) // Npcs
578 {
579 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
580 } else if (id_ == 0x2E) // Npcs
581 {
582 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
583 } else if (id_ == 0x2F) // Npcs
584 {
585 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
586 } else if (id_ == 0x30) // Npcs
587 {
588 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
589 } else if (id_ == 0x31) // Npcs
590 {
591 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
592 } else if (id_ == 0x32) // Npcs
593 {
594 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
595 }
596 /*
597 else if (id_== 0x33) // Pull for rupees
598 {
599
600 }
601 */
602 else if (id_ == 0x34) // Npcs
603 {
604 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
605 } else if (id_ == 0x35) // Npcs
606 {
607 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
608 } else if (id_ == 0x36) // Npcs
609 {
610 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
611 }
612 /*
613 else if (id_== 0x37) // Waterfall
614 {
615 DrawSpriteTile((x*16), (y *16), 14, 6, 10);
616 }
617 */
618 else if (id_ == 0x38) // Arrowtarget
619 {
620 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
621 } else if (id_ == 0x39) // Npcs
622 {
623 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
624 } else if (id_ == 0x3A) // Npcs
625 {
626 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
627 } else if (id_ == 0x3B) // Dash item
628 {
629 } else if (id_ == 0x3C) // Npcs
630 {
631 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
632 } else if (id_ == 0x3D) // Npcs
633 {
634 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
635 } else if (id_ == 0x3E) // Npcs
636 {
637 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
638 } else if (id_ == 0x3F) // Npcs
639 {
640 DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
641 } else if (id_ == 0x40) // Lightning lock (agah tower)
642 {
643 DrawSpriteTile((x * 16) - 24, (y * 16), 10, 28, 2, false, false, 1, 2);
644 DrawSpriteTile((x * 16) - 16, (y * 16), 6, 30, 2);
645 DrawSpriteTile((x * 16), (y * 16), 8, 30, 2);
646 DrawSpriteTile((x * 16) + 16, (y * 16), 6, 30, 2);
647 DrawSpriteTile((x * 16) + 24, (y * 16), 10, 28, 2, false, false, 1, 2);
648 } else if (id_ == 0x41) // Blue soldier
649 {
650 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10);
651 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 10, true, false, 1, 2);
652 DrawSpriteTile((x * 16), (y * 16), 0, 20, 10);
653 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 10, false, false, 1,
654 2); // Shield
655 DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 14, 22, 10, false, true, 1,
656 2); // Sword
657 } else if (id_ == 0x42) // Green soldier
658 {
659 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 12);
660 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 12, true, false, 1, 2);
661 DrawSpriteTile((x * 16), (y * 16), 0, 20, 12);
662 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 12, false, false, 1,
663 2); // Shield
664 DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 14, 22, 12, false, true, 1,
665 2); // Sword
666 } else if (id_ == 0x43) // Red spear soldier
667 {
668 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8);
669 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 8, true, false, 1, 2);
670 DrawSpriteTile((x * 16), (y * 16), 0, 20, 8);
671 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 8, false, false, 1,
672 2); // Shield
673 DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 11, 22, 8, false, true, 1,
674 2); // Spear
675 } else if (id_ == 0x44) // Sword blue holding up
676 {
677 DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 10);
678 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10, false, false, 1, 2);
679 DrawSpriteTile((x * 16), (y * 16), 0, 16, 10); // Head
680 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 14, 22, 10, false, true, 1,
681 2); // Sword
682 } else if (id_ == 0x45) // Green spear soldier
683 {
684 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 12);
685 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 12, true, false, 1, 2);
686 DrawSpriteTile((x * 16), (y * 16), 0, 20, 12);
687 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 12, false, false, 1,
688 2); // Shield
689 DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 11, 22, 12, false, true, 1,
690 2); // Spear
691 } else if (id_ == 0x46) // Blue archer
692 {
693 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10);
694 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 10, true, false, 1, 2);
695 DrawSpriteTile((x * 16), (y * 16), 0, 20, 10); // Head
696 DrawSpriteTile((x * 16), (y * 16) + 16, 10, 16, 10, false, false, 1,
697 1); // Bow1
698 DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 10, 16, 10, true, false, 1,
699 1); // Bow2
700 } else if (id_ == 0x47) // Green archer
701 {
702 DrawSpriteTile((x * 16), (y * 16) + 8, 14, 16, 12);
703 DrawSpriteTile((x * 16), (y * 16), 0, 20, 12);
704 DrawSpriteTile((x * 16), (y * 16) + 16, 10, 16, 12, false, false, 1,
705 1); // Bow1
706 DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 10, 16, 12, true, false, 1,
707 1); // Bow2
708 } else if (id_ == 0x48) // Javelin soldier red
709 {
710 DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8);
711 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2);
712 DrawSpriteTile((x * 16), (y * 16), 0, 16, 8); // Head
713 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 11, 22, 8, false, true, 1,
714 2); // Sword
715 } else if (id_ == 0x49) // Javelin soldier red from bush
716 {
717 DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8);
718 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2);
719 DrawSpriteTile((x * 16), (y * 16), 0, 18, 8); // Head
720 DrawSpriteTile((x * 16), (y * 16) + 24, 0, 20, 2);
721 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 11, 22, 8, false, true, 1,
722 2); // Sword
723 } else if (id_ == 0x4A) // Red bomb soldier
724 {
725 DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8);
726 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2);
727 DrawSpriteTile((x * 16), (y * 16), 0, 16, 8); // Head
728 DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 14, 22, 11); // Bomb
729 } else if (id_ == 0x4B) // Green soldier recruit
730 {
731 // 0,4
732 DrawSpriteTile((x * 16), (y * 16), 6, 24, 12);
733 DrawSpriteTile((x * 16), (y * 16) - 10, 0, 20, 12);
734 } else if (id_ == 0x4C) // Jazzhand
735 {
736 DrawSpriteTile((x * 16), (y * 16), 0, 26, 14, false, false, 6, 2);
737 } else if (id_ == 0x4D) // Rabit??
738 {
739 DrawSpriteTile((x * 16), (y * 16), 0, 26, 12, false, false, 6, 2);
740 } else if (id_ == 0x4E) // Popo1
741 {
742 DrawSpriteTile((x * 16), (y * 16), 0, 20, 10);
743 } else if (id_ == 0x4F) // Popo2
744 {
745 DrawSpriteTile((x * 16), (y * 16), 2, 20, 10);
746 } else if (id_ == 0x50) // Canon ball
747 {
748 DrawSpriteTile((x * 16), (y * 16), 0, 24, 10);
749 } else if (id_ == 0x51) // Armos
750 {
751 DrawSpriteTile((x * 16), (y * 16), 0, 28, 11, false, false, 2, 4);
752 } else if (id_ == 0x53) // Armos Knight
753 {
754 DrawSpriteTile((x * 16), (y * 16), 0, 28, 10, false, false, 4, 4);
755 } else if (id_ == 0x54) {
756 DrawSpriteTile((x * 16), (y * 16), 2, 28, 12);
757 DrawSpriteTile((x * 16) + 8, (y * 16) + 10, 6, 28, 12);
758 DrawSpriteTile((x * 16) + 16, (y * 16) + 18, 10, 28, 12);
759 } else if (id_ == 0x55) // Fireball Zora
760 {
761 DrawSpriteTile((x * 16), (y * 16), 4, 26, 11);
762 } else if (id_ == 0x56) // Zora
763 {
764 DrawSpriteTile((x * 16), (y * 16), 10, 20, 2);
765 DrawSpriteTile((x * 16), (y * 16) + 8, 8, 30, 2);
766 } else if (id_ == 0x57) // Desert Rocks
767 {
768 DrawSpriteTile((x * 16), (y * 16), 14, 24, 2, false, false, 2, 4);
769 DrawSpriteTile((x * 16) + 16, (y * 16), 14, 24, 2, true, false, 2, 4);
770 } else if (id_ == 0x58) // Crab
771 {
772 DrawSpriteTile((x * 16), (y * 16), 14, 24, 12);
773 DrawSpriteTile((x * 16) + 16, (y * 16), 14, 24, 12, true);
774 } else if (id_ == 0x5B) // Spark
775 {
776 DrawSpriteTile((x * 16), (y * 16), 8, 18, 4);
777 } else if (id_ == 0x5C) // Spark
778 {
779 DrawSpriteTile((x * 16), (y * 16), 8, 18, 4, true);
780 } else if (id_ == 0x5D) // Roller vertical1
781 {
782 // Subset3
783 if (((y * 16) & 0x10) == 0x10) {
784 DrawSpriteTile((x * 16), (y * 16), 8, 24, 11);
785
786 for (int i = 0; i < 7; i++) {
787 DrawSpriteTile((x * 16) + 8 + (i * 16), (y * 16), 9, 24, 11);
788 }
789
790 DrawSpriteTile((x * 16) + (16 * 7), (y * 16), 8, 24, 11, true);
791 } else {
792 DrawSpriteTile((x * 16), (y * 16), 8, 24, 11);
793 DrawSpriteTile((x * 16) + 16, (y * 16), 9, 24, 11);
794 DrawSpriteTile((x * 16) + 32, (y * 16), 9, 24, 11);
795 DrawSpriteTile((x * 16) + 48, (y * 16), 8, 24, 11, true);
796 }
797
798 } else if (id_ == 0x5E) // Roller vertical2
799 {
800 // Subset3
801 if (((y * 16) & 0x10) == 0x10) {
802 DrawSpriteTile((x * 16), (y * 16), 8, 24, 11);
803
804 for (int i = 0; i < 7; i++) {
805 DrawSpriteTile((x * 16) + 8 + (i * 16), (y * 16), 9, 24, 11);
806 }
807
808 DrawSpriteTile((x * 16) + (16 * 7), (y * 16), 8, 24, 11, true);
809 } else {
810 DrawSpriteTile((x * 16), (y * 16), 8, 24, 11);
811 DrawSpriteTile((x * 16) + 16, (y * 16), 9, 24, 11);
812 DrawSpriteTile((x * 16) + 32, (y * 16), 9, 24, 11);
813 DrawSpriteTile((x * 16) + 48, (y * 16), 8, 24, 11, true);
814 }
815 } else if (id_ == 0x5F) // Roller horizontal
816 {
817 if (((x * 16) & 0x10) == 0x10) {
818 DrawSpriteTile((x * 16), (y * 16), 14, 24, 11);
819 DrawSpriteTile((x * 16), (y * 16) + 16, 14, 25, 11);
820 DrawSpriteTile((x * 16), (y * 16) + 32, 14, 25, 11);
821 DrawSpriteTile((x * 16), (y * 16) + 48, 14, 24, 11, false, true);
822 } else {
823 for (int i = 0; i < 7; i++) {
824 DrawSpriteTile((x * 16), (y * 16) + i * 16, 14, 25, 11);
825 }
826
827 DrawSpriteTile((x * 16), (y * 16), 14, 24, 11);
828 DrawSpriteTile((x * 16), (y * 16) + (7 * 16), 14, 24, 11, false, true);
829 }
830 } else if (id_ == 0x60) // Roller horizontal2 (right to left)
831 {
832 // Subset3
833 if (((x * 16) & 0x10) == 0x10) {
834 DrawSpriteTile((x * 16), (y * 16), 14, 24, 11);
835 DrawSpriteTile((x * 16), (y * 16) + 16, 14, 25, 11);
836 DrawSpriteTile((x * 16), (y * 16) + 32, 14, 25, 11);
837 DrawSpriteTile((x * 16), (y * 16) + 48, 14, 24, 11, false, true);
838 } else {
839 for (int i = 0; i < 7; i++) {
840 DrawSpriteTile((x * 16), (y * 16) + i * 16, 14, 25, 11);
841 }
842
843 DrawSpriteTile((x * 16), (y * 16), 14, 24, 11);
844 DrawSpriteTile((x * 16), (y * 16) + (7 * 16), 14, 24, 11, false, true);
845 }
846
847 } else if (id_ == 0x61) // Beamos
848 {
849 DrawSpriteTile((x * 16), (y * 16) - 16, 8, 20, 14, false, false, 2, 4);
850 DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 10, 20, 14, false, false, 1, 1);
851 } else if (id_ == 0x63) // Devalant non-shooter
852 {
853 DrawSpriteTile((x * 16) - 8, (y * 16) - 8, 2, 16, 2);
854 DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 2, 16, 2, true);
855 DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 2, 16, 2, false, true);
856 DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 2, 16, 2, true, true);
857 DrawSpriteTile((x * 16), (y * 16), 0, 16, 10);
858 } else if (id_ == 0x64) // Devalant non-shooter
859 {
860 DrawSpriteTile((x * 16) - 8, (y * 16) - 8, 2, 16, 2);
861 DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 2, 16, 2, true);
862 DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 2, 16, 2, false, true);
863 DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 2, 16, 2, true, true);
864 DrawSpriteTile((x * 16), (y * 16), 0, 16, 8);
865 } else if (id_ == 0x66) // Moving wall canon right
866 {
867 DrawSpriteTile((x * 16), (y * 16), 14, 16, 14, true);
868 } else if (id_ == 0x67) // Moving wall canon right
869 {
870 DrawSpriteTile((x * 16), (y * 16), 14, 16, 14);
871 } else if (id_ == 0x68) // Moving wall canon right
872 {
873 DrawSpriteTile((x * 16), (y * 16), 12, 16, 14);
874 } else if (id_ == 0x69) // Moving wall canon right
875 {
876 DrawSpriteTile((x * 16), (y * 16), 12, 16, 14, false, true);
877 } else if (id_ == 0x6A) // Chainball soldier
878 {
879 DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 14);
880 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 14, false, false, 1, 2);
881 DrawSpriteTile((x * 16), (y * 16), 0, 16, 14); // Head
882 DrawSpriteTile((x * 16) + 12, (y * 16) - 16, 10, 18, 14); // Ball
883 } else if (id_ == 0x6B) // Cannon soldier
884 {
885 DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 14);
886 DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 14, false, false, 1, 2);
887 DrawSpriteTile((x * 16), (y * 16), 0, 16, 14); // Head
888 DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 4, 18, 14); // Cannon
889 } else if (id_ == 0x6C) // Mirror portal
890 {
891 // Useless
892 } else if (id_ == 0x6D) // Rat
893 {
894 DrawSpriteTile((x * 16), (y * 16), 14, 24, 5);
895 } else if (id_ == 0x6E) // Rope
896 {
897 DrawSpriteTile((x * 16), (y * 16), 10, 26, 5);
898 } else if (id_ == 0x6F) {
899 DrawSpriteTile((x * 16), (y * 16), 4, 24, 10);
900 } else if (id_ == 0x70) // Helma fireball
901 {
902 DrawSpriteTile((x * 16), (y * 16), 10, 28, 4);
903 } else if (id_ == 0x71) // Leever
904 {
905 DrawSpriteTile((x * 16), (y * 16), 6, 16, 4);
906 } else if (id_ == 0x73) // Uncle priest
907 {
908 } else if (id_ == 0x79) // Bee
909 {
910 DrawSpriteTile((x * 16), (y * 16), 4, 14, 11, false, false, 1, 1);
911 } else if (id_ == 0x7C) // Skull head
912 {
913 DrawSpriteTile((x * 16), (y * 16), 0, 16, 10);
914 } else if (id_ == 0x7D) // Big spike
915 {
916 DrawSpriteTile((x * 16), (y * 16), 4, 28, 11);
917 DrawSpriteTile((x * 16) + 16, (y * 16), 4, 28, 11, true);
918 DrawSpriteTile((x * 16), (y * 16) + 16, 4, 28, 11, false, true);
919 DrawSpriteTile((x * 16) + 16, (y * 16) + 16, 4, 28, 11, true, true);
920 } else if (id_ == 0x7E) // Guruguru clockwise
921 {
922 DrawSpriteTile((x * 16), (y * 16) - 14, 8, 18, 4);
923 DrawSpriteTile((x * 16), (y * 16) - 28, 8, 18, 4);
924 DrawSpriteTile((x * 16), (y * 16) - 42, 8, 18, 4);
925 DrawSpriteTile((x * 16), (y * 16) - 56, 8, 18, 4);
926 } else if (id_ == 0x7F) // Guruguru Counterclockwise
927 {
928 DrawSpriteTile((x * 16), (y * 16) - 14, 8, 18, 4);
929 DrawSpriteTile((x * 16), (y * 16) - 28, 8, 18, 4);
930 DrawSpriteTile((x * 16), (y * 16) - 42, 8, 18, 4);
931 DrawSpriteTile((x * 16), (y * 16) - 56, 8, 18, 4);
932 } else if (id_ == 0x80) // Winder (moving firebar)
933 {
934 DrawSpriteTile((x * 16), (y * 16), 8, 18, 4);
935 DrawSpriteTile((x * 16) - 14, (y * 16), 8, 18, 4);
936 DrawSpriteTile((x * 16) - 28, (y * 16), 8, 18, 4);
937 DrawSpriteTile((x * 16) - 42, (y * 16), 8, 18, 4);
938 DrawSpriteTile((x * 16) - 56, (y * 16), 8, 18, 4);
939 } else if (id_ == 0x81) // Water tektite
940 {
941 DrawSpriteTile((x * 16), (y * 16), 0, 24, 11);
942 } else if (id_ == 0x82) // circle antifairy
943 {
944 // Antifairy top
945 DrawSpriteTile((x * 16 + 2) - 4, (y * 16 + 8) - 16, 3, 30, 5, false, false,
946 1, 1);
947 DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 2) - 16, 3, 30, 5, false, false,
948 1, 1);
949 DrawSpriteTile((x * 16 + 14) - 4, (y * 16 + 8) - 16, 3, 30, 5, false, false,
950 1, 1);
951 DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 14) - 16, 3, 30, 5, false, false,
952 1, 1);
953 DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 8) - 16, 1, 30, 5, false, false,
954 1, 1); // Middle
955 // Left
956 DrawSpriteTile((x * 16 + 2) - 16, (y * 16 + 8) - 4, 3, 30, 5, false, false,
957 1, 1);
958 DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 2) - 4, 3, 30, 5, false, false,
959 1, 1);
960 DrawSpriteTile((x * 16 + 14) - 16, (y * 16 + 8) - 4, 3, 30, 5, false, false,
961 1, 1);
962 DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 14) - 4, 3, 30, 5, false, false,
963 1, 1);
964 DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 8) - 4, 1, 30, 5, false, false,
965 1, 1); // Middle
966
967 DrawSpriteTile((x * 16 + 2) - 4, (y * 16 + 8) + 8, 3, 30, 5, false, false,
968 1, 1);
969 DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 2) + 8, 3, 30, 5, false, false,
970 1, 1);
971 DrawSpriteTile((x * 16 + 14) - 4, (y * 16 + 8) + 8, 3, 30, 5, false, false,
972 1, 1);
973 DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 14) + 8, 3, 30, 5, false, false,
974 1, 1);
975 DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 8) + 8, 1, 30, 5, false, false,
976 1, 1); // Middle
977 // Left
978 DrawSpriteTile((x * 16 + 2) + 8, (y * 16 + 8) - 4, 3, 30, 5, false, false,
979 1, 1);
980 DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 2) - 4, 3, 30, 5, false, false,
981 1, 1);
982 DrawSpriteTile((x * 16 + 14) + 8, (y * 16 + 8) - 4, 3, 30, 5, false, false,
983 1, 1);
984 DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 14) - 4, 3, 30, 5, false, false,
985 1, 1);
986 DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 8) - 4, 1, 30, 5, false, false,
987 1, 1); // Middle
988 } else if (id_ == 0x83) // Green eyegore
989 {
990 DrawSpriteTile((x * 16), (y * 16), 12, 24, 14, false, false, 2, 3);
991 DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 14, true, false, 1, 3);
992 } else if (id_ == 0x84) // Red eyegore
993 {
994 DrawSpriteTile((x * 16), (y * 16), 12, 24, 8, false, false, 2, 3);
995 DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 8, true, false, 1, 3);
996 } else if (id_ == 0x85) // Yellow stalfos
997 {
998 DrawSpriteTile((x * 16), (y * 16), 10, 16, 11);
999 DrawSpriteTile((x * 16), (y * 16) - 12, 0, 16, 11); // Head
1000 } else if (id_ == 0x86) // Kodongo
1001 {
1002 DrawSpriteTile((x * 16), (y * 16), 4, 26, 14);
1003 } else if (id_ == 0x88) // Mothula
1004 {
1005 DrawSpriteTile((x * 16), (y * 16), 8, 24, 14, false, false, 2, 4);
1006 DrawSpriteTile((x * 16) + 16, (y * 16), 8, 24, 14, true, false, 2, 4);
1007 } else if (id_ == 0x8A) // Spike
1008 {
1009 DrawSpriteTile((x * 16), (y * 16), 6, 30, 15);
1010 } else if (id_ == 0x8B) // Gibdo
1011 {
1012 DrawSpriteTile((x * 16), (y * 16), 10, 24, 14);
1013 DrawSpriteTile((x * 16), (y * 16) - 8, 0, 24, 14);
1014 } else if (id_ == 0x8C) // Arrghus
1015 {
1016 DrawSpriteTile((x * 16), (y * 16), 0, 24, 14, false, false, 2, 4);
1017 DrawSpriteTile((x * 16) + 16, (y * 16), 0, 24, 14, true, false, 2, 4);
1018 } else if (id_ == 0x8D) // Arrghus spawn
1019 {
1020 DrawSpriteTile((x * 16), (y * 16), 6, 24, 14);
1021 } else if (id_ == 0x8E) // Terrorpin
1022 {
1023 DrawSpriteTile((x * 16), (y * 16), 14, 24, 12);
1024 } else if (id_ == 0x8F) // Slime
1025 {
1026 DrawSpriteTile((x * 16), (y * 16), 0, 20, 12);
1027 } else if (id_ == 0x90) // Wall master
1028 {
1029 DrawSpriteTile((x * 16), (y * 16), 6, 26, 12);
1030 DrawSpriteTile((x * 16) + 16, (y * 16), 15, 26, 12, false, false, 1, 1);
1031 DrawSpriteTile((x * 16) + 16, (y * 16) + 8, 9, 26, 12, false, false, 1, 2);
1032 DrawSpriteTile((x * 16), (y * 16) + 16, 10, 27, 12, false, false, 1, 1);
1033 DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 8, 27, 12, false, false, 1, 1);
1034 } else if (id_ == 0x91) // Stalfos knight
1035 {
1036 // USDASM $1EACEC frame 0, head direction 2 and SprMiscB=0: a chosen
1037 // visible static pose, not the initial hidden state. Paint reverse OAM
1038 // order so earlier entries win overlaps. OBJ palette 5 is unchanged.
1039 DrawSpriteTile((x * 16) + 11, (y * 16) + 16, 4, 23, 12, true, false, 1, 1);
1040 DrawSpriteTile((x * 16) - 3, (y * 16) + 16, 4, 23, 12, false, false, 1, 1);
1041 DrawSpriteTile((x * 16) + 4, (y * 16), 2, 22, 12);
1042 DrawSpriteTile((x * 16) - 4, (y * 16), 1, 22, 12);
1043 DrawSpriteTile((x * 16) - 4, (y * 16) - 8, 4, 22, 12, false, false, 1, 1);
1044 DrawSpriteTile((x * 16), (y * 16) - 12, 6, 20, 12);
1045 } else if (id_ == 0x92) // Helmaking
1046 {
1047 DrawSpriteTile((x * 16), (y * 16) + 32, 14, 26, 14);
1048 DrawSpriteTile((x * 16) + 16, (y * 16) + 32, 0, 28, 14);
1049 DrawSpriteTile((x * 16) + 32, (y * 16) + 32, 14, 26, 14, true);
1050
1051 DrawSpriteTile((x * 16), (y * 16) + 16 + 32, 2, 28, 14);
1052 DrawSpriteTile((x * 16) + 16, (y * 16) + 16 + 32, 4, 28, 14);
1053 DrawSpriteTile((x * 16) + 32, (y * 16) + 16 + 32, 2, 28, 14, true);
1054
1055 DrawSpriteTile((x * 16) + 8, (y * 16) + 32 + 32, 6, 28, 14);
1056 DrawSpriteTile((x * 16) + 24, (y * 16) + 32 + 32, 6, 28, 14, true);
1057 } else if (id_ == 0x93) // Bumper
1058 {
1059 DrawSpriteTile((x * 16), (y * 16), 12, 30, 7);
1060 DrawSpriteTile((x * 16) + 16, (y * 16), 12, 30, 7, true);
1061 DrawSpriteTile((x * 16) + 16, (y * 16) + 16, 12, 30, 7, true, true);
1062 DrawSpriteTile((x * 16), (y * 16) + 16, 12, 30, 7, false, true);
1063 } else if (id_ == 0x95) // Right laser eye
1064 {
1065 DrawSpriteTile((x * 16), (y * 16), 9, 28, 3, true, false, 1, 2);
1066 DrawSpriteTile((x * 16), (y * 16) + 16, 9, 28, 3, true, true, 1, 1);
1067 } else if (id_ == 0x96) // Left laser eye
1068 {
1069 DrawSpriteTile((x * 16) + 8, (y * 16) - 4, 9, 28, 3, false, false, 1, 2);
1070 DrawSpriteTile((x * 16) + 8, (y * 16) + 12, 9, 28, 3, false, true, 1, 1);
1071 } else if (id_ == 0x97) // Right laser eye
1072 {
1073 DrawSpriteTile((x * 16), (y * 16), 6, 28, 3, false, false, 2, 1);
1074 DrawSpriteTile((x * 16) + 16, (y * 16), 6, 28, 3, true, false, 1, 1);
1075 } else if (id_ == 0x98) // Right laser eye
1076 {
1077 DrawSpriteTile((x * 16), (y * 16), 6, 28, 3, false, true, 2, 1);
1078 DrawSpriteTile((x * 16) + 16, (y * 16), 6, 28, 3, true, true, 1, 1);
1079 } else if (id_ == 0x99) {
1080 DrawSpriteTile((x * 16), (y * 16), 6, 24, 12);
1081 DrawSpriteTile((x * 16), (y * 16) - 8, 0, 24, 12);
1082 } else if (id_ == 0x9A) // Water bubble kyameron
1083 {
1084 DrawSpriteTile((x * 16), (y * 16), 10, 24, 6);
1085 } else if (id_ == 0x9B) // Water bubble kyameron
1086 {
1087 DrawSpriteTile((x * 16), (y * 16), 6, 24, 11);
1088 DrawSpriteTile((x * 16), (y * 16) - 8, 2, 27, 11, false, false, 2, 1);
1089 } else if (id_ == 0x9C) // Water bubble kyameron
1090 {
1091 DrawSpriteTile((x * 16), (y * 16), 12, 22, 11);
1092 DrawSpriteTile((x * 16) + 16, (y * 16), 13, 22, 11, false, false, 1, 2);
1093 } else if (id_ == 0x9D) // Babasu, visible upward frame
1094 {
1095 // USDASM $0DBCA0: two overlapping 16x16 tiles, properties $0A XOR $01
1096 // (OBJ page 1, palette 5). Draw the earlier OAM entry last.
1097 DrawSpriteTile((x * 16), (y * 16), 14, 21, 12);
1098 DrawSpriteTile((x * 16), (y * 16) - 8, 14, 20, 12);
1099 } else if (id_ == 0xA1) {
1100 DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 6, 26, 14);
1101 DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 6, 26, 14, true);
1102 } else if (id_ == 0xA2) {
1103 DrawSpriteTile((x * 16), (y * 16) + 8, 0, 24, 14, false, false, 4, 4);
1104 } else if (id_ == 0xA5) {
1105 DrawSpriteTile((x * 16), (y * 16), 0, 26, 10, false, false, 3, 2);
1106 DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 0, 24, 10);
1107 } else if (id_ == 0xA6) {
1108 DrawSpriteTile((x * 16), (y * 16), 0, 26, 8, false, false, 3, 2);
1109 DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 0, 24, 8);
1110 } else if (id_ == 0xA7) { // Stalfos, grounded front-facing static pose
1111 // USDASM $0DC0F3 frame 0, head direction 2. The body entry is duplicated
1112 // in OAM; draw it once, then the higher-priority head. OBJ palette 4 stays.
1113 DrawSpriteTile((x * 16), (y * 16), 6, 16, 10);
1114 DrawSpriteTile((x * 16), (y * 16) - 10, 0, 16, 10);
1115 } else if (id_ == 0xAC) {
1116 DrawSpriteTile((x * 16), (y * 16), 5, 14, 4);
1117 } else if (id_ == 0xAD) {
1118 DrawSpriteTile((x * 16), (y * 16) + 8, 14, 10, 10);
1119 DrawSpriteTile((x * 16), (y * 16), 12, 10, 10);
1120 } else if (id_ == 0xBA) {
1121 DrawSpriteTile((x * 16), (y * 16), 14, 14, 6);
1122 } else if (id_ == 0xC1 || id_ == 0x7A) {
1123 DrawSpriteTile((x * 16), (y * 16) - 16, 2, 24, 12, false, false, 2, 4);
1124 DrawSpriteTile((x * 16) + 16, (y * 16) - 16, 2, 24, 12, true, false, 2, 4);
1125 } else if (id_ == 0xC3) {
1126 DrawSpriteTile((x * 16), (y * 16), 10, 14, 12);
1127 } else if (id_ == 0xC4) {
1128 DrawSpriteTile((x * 16), (y * 16), 0, 18, 14);
1129 DrawSpriteTile((x * 16), (y * 16) - 8, 0, 16, 14);
1130 } else if (id_ == 0xC5) {
1131 } else if (id_ == 0xC6) {
1132 DrawSpriteTile((x * 16) + 4, (y * 16) + 14, 3, 30, 14, false, false, 1, 1);
1133 DrawSpriteTile((x * 16) + 14, (y * 16) + 4, 3, 30, 14, false, false, 1, 1);
1134 DrawSpriteTile((x * 16) + 4, (y * 16) + 2, 1, 31, 14, false, false, 1, 1);
1135 DrawSpriteTile((x * 16) - 6, (y * 16) + 4, 3, 30, 14, false, false, 1, 1);
1136 DrawSpriteTile((x * 16) + 4, (y * 16) - 6, 3, 30, 14, false, false, 1, 1);
1137 } else if (id_ == 0xC7) {
1138 DrawSpriteTile((x * 16), (y * 16), 0, 26, 4);
1139 DrawSpriteTile((x * 16), (y * 16) - 10, 0, 26, 4);
1140 DrawSpriteTile((x * 16), (y * 16) - 20, 0, 26, 4);
1141 DrawSpriteTile((x * 16), (y * 16) - 30, 2, 26, 4);
1142 } else if (id_ == 0xC8) {
1143 DrawSpriteTile((x * 16), (y * 16), 12, 24, 12, false, false, 2, 3);
1144 DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 12, true, false, 1, 3);
1145 } else if (id_ == 0xC9) {
1146 DrawSpriteTile((x * 16), (y * 16), 8, 28, 8, false);
1147 DrawSpriteTile((x * 16) + 16, (y * 16), 8, 28, 8, true);
1148 } else if (id_ == 0xCA) {
1149 DrawSpriteTile((x * 16), (y * 16), 8, 10, 10);
1150 } else if (id_ == 0xD0) {
1151 DrawSpriteTile((x * 16), (y * 16), 7, 14, 11, false, false, 3, 2);
1152 DrawSpriteTile((x * 16), (y * 16) - 10, 8, 12, 11);
1153 } else if (id_ == 0xD1) {
1154 DrawSpriteTile((x * 16) + 2, (y * 16) + 8, 7, 13, 11, true, true, 1, 1);
1155 DrawSpriteTile((x * 16) + 8, (y * 16) + 2, 7, 13, 11, true, false, 1, 1);
1156 DrawSpriteTile((x * 16) + 14, (y * 16) + 8, 7, 13, 11, true, true, 1, 1);
1157 DrawSpriteTile((x * 16) + 8, (y * 16) + 14, 7, 13, 11, false, true, 1, 1);
1158 DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 7, 13, 11, false, false, 1,
1159 1); // Middle
1160 // 6,7 / 13
1161 } else if (id_ == 0xD4) {
1162 DrawSpriteTile((x * 16) - 4, (y * 16), 0, 7, 7, false, false, 1, 1);
1163 DrawSpriteTile((x * 16) + 4, (y * 16), 0, 7, 7, true, false, 1, 1);
1164 } else if (id_ == 0xE3) // Fairy
1165 {
1166 DrawSpriteTile((x * 16), (y * 16), 10, 14, 10);
1167 } else if (id_ == 0xE4) // Key
1168 {
1169 DrawSpriteTile((x * 16), (y * 16), 11, 06, 11, false, false, 1, 2);
1170 } else if (id_ == 0xE7) // Mushroom
1171 {
1172 DrawSpriteTile((x * 16), (y * 16), 14, 30, 16);
1173 } else if (id_ == 0xE8) // Fake ms
1174 {
1175 DrawSpriteTile((x * 16) + 4, (y * 16), 4, 31, 10, false, false, 1, 1);
1176 DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 5, 31, 10, false, false, 1, 1);
1177 } else if (id_ == 0xEB) {
1178 DrawSpriteTile((x * 16), (y * 16), 0, 14, 5);
1179 } else if (id_ == 0xF2) {
1180 DrawSpriteTile((x * 16), (y * 16) - 16, 12, 24, 2, false, false, 2, 4);
1181 DrawSpriteTile((x * 16) + 16, (y * 16) - 16, 12, 24, 2, true, false, 2, 4);
1182 } else if (id_ == 0xF4) {
1183 DrawSpriteTile((x * 16), (y * 16), 12, 28, 5, false, false, 4, 4);
1184 } else {
1185 DrawSpriteTile((x * 16), (y * 16), 4, 4, 5);
1186 }
1187
1188 bounding_box_.x = (lower_x_ + (x * 16));
1189 bounding_box_.y = (lower_y_ + (y * 16));
1192}
1193
1194void Sprite::RenderPreviewGraphics(std::span<const uint8_t> graphics,
1195 const SpriteOamLayout* layout_override,
1196 std::span<const uint8_t> graphics_resource) {
1198 if (graphics.empty()) {
1199 return;
1200 }
1201
1202 std::vector<uint8_t> resource_graphics;
1203 if (layout_override != nullptr && layout_override->sprite_id == id_ &&
1204 layout_override->graphics_resource != nullptr) {
1205 // Dynamic graphics are preview-local: never replace the room's sheets or
1206 // use unrelated room art when the external OBJ page is unavailable.
1207 constexpr size_t kObjPageBytes = 0x2000;
1208 constexpr size_t kPageOneOffset = 0x300 * 64;
1209 if (graphics_resource.size() != kObjPageBytes ||
1210 graphics.size() < kPageOneOffset + kObjPageBytes * 2) {
1211 return;
1212 }
1213 resource_graphics.assign(graphics.begin(), graphics.end());
1214 for (size_t tile_id = 0; tile_id < 256; ++tile_id) {
1215 const auto tile = gfx::UnpackBppTile(graphics_resource, tile_id * 32, 4);
1216 const size_t tile_offset =
1217 kPageOneOffset + (tile_id / 16) * 1024 + (tile_id % 16) * 8;
1218 for (size_t row = 0; row < 8; ++row) {
1219 std::copy_n(tile.data + row * 8, 8,
1220 resource_graphics.begin() + tile_offset + row * 128);
1221 }
1222 }
1223 graphics = resource_graphics;
1224 }
1225
1226 external_gfx_ = graphics.data();
1227 external_gfx_size_ = graphics.size();
1228
1229 const uint8_t old_nx = nx_;
1230 const uint8_t old_ny = ny_;
1231 const int old_x = x_;
1232 const int old_y = y_;
1233 const SDL_Rect old_bounding_box = bounding_box_;
1234
1235 // Sprite::Draw() was written around room/map coordinates. Normalize to the
1236 // preview origin instead of baking absolute room coordinates into the buffer.
1237 nx_ = 0;
1238 ny_ = 0;
1239 x_ = 0;
1240 y_ = 0;
1241 const auto draw_preview = [&]() {
1242 if (layout_override != nullptr && layout_override->sprite_id == id_) {
1243 // Layout entries are in OAM order: the first entry has highest priority.
1244 for (auto tile = layout_override->tiles.rbegin();
1245 tile != layout_override->tiles.rend(); ++tile) {
1246 if (tile->tile_id > 0x1FF || tile->palette > 7) {
1247 continue;
1248 }
1249 const int size = tile->size_16x16 ? 2 : 1;
1250 // Convert the OBJ palette to its CGRAM row using DrawSpriteTile's
1251 // half-palette selectors with base 112.
1252 DrawSpriteTile(tile->x_offset, tile->y_offset, tile->tile_id % 16,
1253 tile->tile_id / 16, 2 + tile->palette * 2, tile->flip_x,
1254 tile->flip_y, size, size);
1255 }
1256 } else {
1257 Draw();
1258 }
1259 };
1260
1261 // Measure the same tile stream we render, without decoding pixels or keeping
1262 // a second sprite-size table. Union with the legacy extent so ordinary
1263 // previews retain their 64x64 layout and (16,16) anchor.
1265 draw_preview();
1267 // Index 0 is transparent; 0xFF remains a visible armor-palette color.
1269 draw_preview();
1270
1271 nx_ = old_nx;
1272 ny_ = old_ny;
1273 x_ = old_x;
1274 y_ = old_y;
1275 bounding_box_ = old_bounding_box;
1276
1277 external_gfx_ = nullptr;
1279}
1280
1285
1286void Sprite::DrawSpriteTile(int x, int y, int srcx, int srcy, int pal,
1287 bool mirror_x, bool mirror_y, int sizex,
1288 int sizey) {
1289 const bool use_external_8bpp = external_gfx_ != nullptr;
1290 const uint8_t* gfx_data =
1291 use_external_8bpp ? external_gfx_ : current_gfx_.data();
1292 const size_t gfx_size =
1293 use_external_8bpp ? external_gfx_size_ : current_gfx_.size();
1294
1295 if (gfx_data == nullptr || gfx_size == 0) {
1296 return;
1297 }
1298
1299 // Validate input parameters
1300 if (sizex <= 0 || sizey <= 0) {
1301 return;
1302 }
1303
1304 if (srcx < 0 || srcy < 0 || pal < 0) {
1305 return;
1306 }
1307
1308 int drawid_ = (srcx + (srcy * 16)) + 512;
1309
1310 // Validate drawid_ is within reasonable bounds
1311 if (drawid_ < 0 || drawid_ > 4096) {
1312 return;
1313 }
1314
1316 const int left = std::min(preview_bounds_.x, x);
1317 const int top = std::min(preview_bounds_.y, y);
1318 const int right =
1319 std::max(preview_bounds_.x + preview_bounds_.w, x + sizex * 8);
1320 const int bottom =
1321 std::max(preview_bounds_.y + preview_bounds_.h, y + sizey * 8);
1322 preview_bounds_ = {left, top, right - left, bottom - top};
1323 return;
1324 }
1325
1326 if (use_external_8bpp) {
1327 x -= preview_bounds_.x;
1328 y -= preview_bounds_.y;
1329 } else {
1330 // Packed overworld drawing keeps its fixed buffer and sentinel. Restore
1331 // that storage if an external preview previously enlarged this Sprite.
1333 if (preview_gfx_.size() != 64 * 64) {
1334 preview_gfx_.assign(64 * 64, 0xFF);
1335 }
1336 x += 16;
1337 y += 16;
1338 }
1339
1340 if (use_external_8bpp) {
1341 const int width = sizex * 8;
1342 const int height = sizey * 8;
1343 constexpr int kTilesPerRow = 16;
1344 constexpr int kTileSize = 8;
1345 constexpr int kTileRowStride = 1024;
1346 constexpr int kPixelRowStride = 128;
1347
1348 for (int dest_y = 0; dest_y < height; ++dest_y) {
1349 const int src_y = mirror_y ? (height - 1 - dest_y) : dest_y;
1350 const int src_tile_y = src_y / kTileSize;
1351 const int src_py = src_y % kTileSize;
1352
1353 for (int dest_x = 0; dest_x < width; ++dest_x) {
1354 const int src_x = mirror_x ? (width - 1 - dest_x) : dest_x;
1355 const int src_tile_x = src_x / kTileSize;
1356 const int src_px = src_x % kTileSize;
1357 const int tile_id = drawid_ + (src_tile_y * kTilesPerRow) + src_tile_x;
1358 if (tile_id < 0) {
1359 continue;
1360 }
1361
1362 const int tile_col = tile_id % kTilesPerRow;
1363 const int tile_row = tile_id / kTilesPerRow;
1364 const int gfx_index = (tile_row * kTileRowStride) +
1365 (src_py * kPixelRowStride) +
1366 (tile_col * kTileSize) + src_px;
1367 if (gfx_index < 0 || gfx_index >= static_cast<int>(gfx_size)) {
1368 continue;
1369 }
1370
1371 const uint8_t pixel = gfx_data[gfx_index] & 0x0F;
1372 if (pixel == 0) {
1373 continue;
1374 }
1375
1376 const int preview_x = x + dest_x;
1377 const int preview_y = y + dest_y;
1378 if (preview_x < 0 || preview_x >= preview_bounds_.w || preview_y < 0 ||
1379 preview_y >= preview_bounds_.h) {
1380 continue;
1381 }
1382 const int index = preview_x + (preview_y * preview_bounds_.w);
1383 if (index >= 0 && index < static_cast<int>(preview_gfx_.size())) {
1384 preview_gfx_[index] =
1385 static_cast<uint8_t>((pixel & 0x0F) + 112 + (pal * 8));
1386 }
1387 }
1388 }
1389 return;
1390 }
1391
1392 for (auto yl = 0; yl < sizey * 8; yl++) {
1393 for (auto xl = 0; xl < (sizex * 8) / 2; xl++) {
1394 int mx = xl;
1395 int my = yl;
1396
1397 if (mirror_x) {
1398 mx = (((sizex * 8) / 2) - 1) - xl;
1399 }
1400 if (mirror_y) {
1401 my = ((sizey * 8) - 1) - yl;
1402 }
1403
1404 // Formula information to get tile index position in the array
1405 //((ID / nbrofXtiles) * (imgwidth/2) + (ID - ((ID/16)*16) ))
1406
1407 int tx = ((drawid_ / 0x10) * 0x400) +
1408 ((drawid_ - ((drawid_ / 0x10) * 0x10)) * 8);
1409
1410 // Validate graphics buffer access
1411 int gfx_index = tx + (yl * 0x80) + xl;
1412 if (gfx_index < 0 || gfx_index >= static_cast<int>(gfx_size)) {
1413 continue; // Skip this pixel if out of bounds
1414 }
1415
1416 auto pixel = gfx_data[gfx_index];
1417 // nx,ny = object position, xx,yy = tile position, xl,yl = pixel
1418 // position
1419 int index = (x) + (y * 64) + (mx + (my * 0x80));
1420
1421 // Validate preview buffer access
1422 if (index >= 0 && index < static_cast<int>(preview_gfx_.size()) &&
1423 index <= 4096) {
1424 preview_gfx_[index] = (uint8_t)((pixel & 0x0F) + 112 + (pal * 8));
1425 }
1426 }
1427 }
1428}
1429
1430} // namespace zelda3
1431} // namespace yaze
bool PreferHMagicNames() const
Get whether Hyrule Magic names are preferred.
std::string GetLabel(ResourceType type, int id) const
Get a label for a resource by type and ID.
void SetPreferHMagicNames(bool prefer)
Set whether to prefer Hyrule Magic sprite names.
std::vector< uint8_t > preview_gfx_
Definition sprite.h:163
const uint8_t * external_gfx_
Definition sprite.h:165
void RenderPreviewGraphics(std::span< const uint8_t > graphics, const SpriteOamLayout *layout_override=nullptr, std::span< const uint8_t > graphics_resource={})
Definition sprite.cc:1194
void ClearPreviewGraphics()
Definition sprite.cc:1281
void UpdateMapProperties(uint16_t map_id, const void *context=nullptr) override
Update entity properties based on map position.
Definition sprite.cc:328
bool measuring_preview_bounds_
Definition sprite.h:162
auto map_x() const
Definition sprite.h:114
std::string name_
Definition sprite.h:159
void DrawSpriteTile(int x, int y, int srcx, int srcy, int pal, bool mirror_x=false, bool mirror_y=false, int sizex=2, int sizey=2)
Definition sprite.cc:1286
std::vector< uint8_t > current_gfx_
Definition sprite.h:164
SDL_Rect bounding_box_
Definition sprite.h:168
void UpdateCoordinates(int map_x, int map_y)
Definition sprite.cc:335
size_t external_gfx_size_
Definition sprite.h:166
auto y() const
Definition sprite.h:110
auto width() const
Definition sprite.h:121
static constexpr SDL_Rect kDefaultPreviewBounds
Definition sprite.h:160
auto x() const
Definition sprite.h:109
auto height() const
Definition sprite.h:122
auto map_y() const
Definition sprite.h:115
SDL_Rect preview_bounds_
Definition sprite.h:161
snes_tile8 UnpackBppTile(std::span< const uint8_t > data, const uint32_t offset, const uint32_t bpp)
Definition snes_tile.cc:24
const size_t kSpriteNameCount
Definition sprite.cc:296
const char *const kSpriteNames[]
Definition sprite.cc:295
const std::string kOverlordNames[26]
Definition sprite.cc:299
const std::string kSpriteDefaultNames[256]
Definition sprite.cc:16
bool PreferHmagicSpriteNames()
Definition sprite.cc:280
void SetPreferHmagicSpriteNames(bool prefer)
Definition sprite.cc:276
const char * ResolveSpriteName(uint16_t id)
Definition sprite.cc:287
ResourceLabelProvider & GetResourceLabels()
Get the global ResourceLabelProvider instance.
Complete OAM layout for a vanilla sprite.
std::vector< SpriteOamEntry > tiles