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