#include "overworld_map.h" #include #include #include #include #include #include #include "app/core/common.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" namespace yaze { namespace app { namespace zelda3 { namespace { void CopyTile8bpp16(int x, int y, int tile, Bytes& bitmap, Bytes& blockset) { int src_pos = ((tile - ((tile / 0x08) * 0x08)) * 0x10) + ((tile / 0x08) * 2048); int dest_pos = (x + (y * 0x200)); for (int yy = 0; yy < 0x10; yy++) { for (int xx = 0; xx < 0x10; xx++) { bitmap[dest_pos + xx + (yy * 0x200)] = blockset[src_pos + xx + (yy * 0x80)]; } } } void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, gfx::SNESPalette main, gfx::SNESPalette animated, gfx::SNESPalette aux1, gfx::SNESPalette aux2, gfx::SNESPalette hud, gfx::SNESColor bgrcolor, gfx::SNESPalette spr, gfx::SNESPalette spr2) { // Palettes infos, color 0 of a palette is always transparent (the arrays // contains 7 colors width wide) There is 16 color per line so 16*Y // Left side of the palette - Main, Animated std::vector new_palette(256); // Main Palette, Location 0,2 : 35 colors [7x5] int k = 0; for (int y = 2; y < 7; y++) { for (int x = 1; x < 8; x++) { new_palette[x + (16 * y)] = main[k]; k++; } } // Animated Palette, Location 0,7 : 7colors for (int x = 1; x < 8; x++) { new_palette[(16 * 7) + (x)] = animated[(x - 1)]; } // Right side of the palette - Aux1, Aux2 // Aux1 Palette, Location 8,2 : 21 colors [7x3] k = 0; for (int y = 2; y < 5; y++) { for (int x = 9; x < 16; x++) { new_palette[x + (16 * y)] = aux1[k]; k++; } } // Aux2 Palette, Location 8,5 : 21 colors [7x3] k = 0; for (int y = 5; y < 8; y++) { for (int x = 9; x < 16; x++) { new_palette[x + (16 * y)] = aux2[k]; k++; } } // Hud Palette, Location 0,0 : 32 colors [16x2] for (int i = 0; i < 32; i++) { new_palette[i] = hud[i]; } // Hardcoded grass color (that might change to become invisible instead) for (int i = 0; i < 8; i++) { new_palette[(i * 16)] = bgrcolor; new_palette[(i * 16) + 8] = bgrcolor; } // Sprite Palettes k = 0; for (int y = 8; y < 9; y++) { for (int x = 1; x < 8; x++) { new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux1")[1][k]; k++; } } // Sprite Palettes k = 0; for (int y = 8; y < 9; y++) { for (int x = 9; x < 16; x++) { new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux3")[0][k]; k++; } } // Sprite Palettes k = 0; for (int y = 9; y < 13; y++) { for (int x = 1; x < 16; x++) { new_palette[x + (16 * y)] = rom.GetPaletteGroup("global_sprites")[0][k]; k++; } } // Sprite Palettes k = 0; for (int y = 13; y < 14; y++) { for (int x = 1; x < 8; x++) { new_palette[x + (16 * y)] = spr[k]; k++; } } // Sprite Palettes k = 0; for (int y = 14; y < 15; y++) { for (int x = 1; x < 8; x++) { new_palette[x + (16 * y)] = spr2[k]; k++; } } // Sprite Palettes k = 0; for (int y = 15; y < 16; y++) { for (int x = 1; x < 16; x++) { new_palette[x + (16 * y)] = rom.GetPaletteGroup("armors")[0][k]; k++; } } current.Create(new_palette); for (int i = 0; i < 256; i++) { current[(i / 16) * 16].setTransparent(true); } } } // namespace OverworldMap::OverworldMap(int index, ROM& rom, std::vector& tiles16) : parent_(index), index_(index), rom_(rom), tiles16_(tiles16) { LoadAreaInfo(); } absl::Status OverworldMap::BuildMap(int count, int game_state, int world, uchar* map_parent, OWBlockset& world_blockset) { game_state_ = game_state; world_ = world; if (large_map_) { parent_ = map_parent[index_]; if (parent_ != index_ && !initialized_) { if (index_ >= 0x80 && index_ <= 0x8A && index_ != 0x88) { area_graphics_ = rom_[core::overworldSpecialGFXGroup + (parent_ - 0x80)]; area_palette_ = rom_[core::overworldSpecialPALGroup + 1]; } else if (index_ == 0x88) { area_graphics_ = 0x51; area_palette_ = 0x00; } else { area_graphics_ = rom_[core::mapGfx + parent_]; area_palette_ = rom_[core::overworldMapPalette + parent_]; } initialized_ = true; } } LoadAreaGraphics(); RETURN_IF_ERROR(BuildTileset()) RETURN_IF_ERROR(BuildTiles16Gfx(count)) LoadPalette(); RETURN_IF_ERROR(BuildBitmap(world_blockset)) built_ = true; return absl::OkStatus(); } void OverworldMap::LoadAreaInfo() { if (index_ != 0x80 && index_ <= 150 && rom_[core::overworldMapSize + (index_ & 0x3F)] != 0) { large_map_ = true; } if (index_ < 64) { area_graphics_ = rom_[core::mapGfx + parent_]; area_palette_ = rom_[core::overworldMapPalette + parent_]; area_music_[0] = rom_[core::overworldMusicBegining + parent_]; area_music_[1] = rom_[core::overworldMusicZelda + parent_]; area_music_[2] = rom_[core::overworldMusicMasterSword + parent_]; area_music_[3] = rom_[core::overworldMusicAgahim + parent_]; sprite_graphics_[0] = rom_[core::overworldSpriteset + parent_]; sprite_graphics_[1] = rom_[core::overworldSpriteset + parent_ + 0x40]; sprite_graphics_[2] = rom_[core::overworldSpriteset + parent_ + 0x80]; sprite_palette_[0] = rom_[core::overworldSpritePalette + parent_]; sprite_palette_[1] = rom_[core::overworldSpritePalette + parent_ + 0x40]; sprite_palette_[2] = rom_[core::overworldSpritePalette + parent_ + 0x80]; } else if (index_ < 0x80) { area_graphics_ = rom_[core::mapGfx + parent_]; area_palette_ = rom_[core::overworldMapPalette + parent_]; area_music_[0] = rom_[core::overworldMusicDW + (parent_ - 64)]; sprite_graphics_[0] = rom_[core::overworldSpriteset + parent_ + 0x80]; sprite_graphics_[1] = rom_[core::overworldSpriteset + parent_ + 0x80]; sprite_graphics_[2] = rom_[core::overworldSpriteset + parent_ + 0x80]; sprite_palette_[0] = rom_[core::overworldSpritePalette + parent_ + 0x80]; sprite_palette_[1] = rom_[core::overworldSpritePalette + parent_ + 0x80]; sprite_palette_[2] = rom_[core::overworldSpritePalette + parent_ + 0x80]; } else { if (index_ == 0x94) { parent_ = 0x80; } else if (index_ == 0x95) { parent_ = 0x03; } else if (index_ == 0x96) { parent_ = 0x5B; // pyramid bg use 0x5B map } else if (index_ == 0x97) { parent_ = 0x00; // pyramid bg use 0x5B map } else if (index_ == 0x9C) { parent_ = 0x43; } else if (index_ == 0x9D) { parent_ = 0x00; } else if (index_ == 0x9E) { parent_ = 0x00; } else if (index_ == 0x9F) { parent_ = 0x2C; } else if (index_ == 0x88) { parent_ = 0x88; } area_palette_ = rom_[core::overworldSpecialPALGroup + parent_ - 0x80]; if (index_ >= 0x80 && index_ <= 0x8A && index_ != 0x88) { area_graphics_ = rom_[core::overworldSpecialGFXGroup + (parent_ - 0x80)]; area_palette_ = rom_[core::overworldSpecialPALGroup + 1]; } else if (index_ == 0x88) { area_graphics_ = 0x51; area_palette_ = 0x00; } else { // pyramid bg use 0x5B map area_graphics_ = rom_[core::mapGfx + parent_]; area_palette_ = rom_[core::overworldMapPalette + parent_]; } message_id_ = rom_[core::overworldMessages + parent_]; sprite_graphics_[0] = rom_[core::overworldSpriteset + parent_ + 0x80]; sprite_graphics_[1] = rom_[core::overworldSpriteset + parent_ + 0x80]; sprite_graphics_[2] = rom_[core::overworldSpriteset + parent_ + 0x80]; sprite_palette_[0] = rom_[core::overworldSpritePalette + parent_ + 0x80]; sprite_palette_[1] = rom_[core::overworldSpritePalette + parent_ + 0x80]; sprite_palette_[2] = rom_[core::overworldSpritePalette + parent_ + 0x80]; } } void OverworldMap::LoadAreaGraphics() { int world_index = 0x20; if (parent_ < 0x40) { world_index = 0x20; } else if (parent_ >= 0x40 && parent_ < 0x80) { world_index = 0x21; } else if (parent_ == 0x88) { world_index = 0x24; } // Sprites Blocksets static_graphics_[8] = 0x73 + 0x00; static_graphics_[9] = 0x73 + 0x01; static_graphics_[10] = 0x73 + 0x06; static_graphics_[11] = 0x73 + 0x07; for (int i = 0; i < 4; i++) { static_graphics_[12 + i] = (rom_[core::kSpriteBlocksetPointer + (sprite_graphics_[game_state_] * 4) + i] + 0x73); } // Main Blocksets for (int i = 0; i < 8; i++) { static_graphics_[i] = rom_[core::overworldgfxGroups2 + (world_index * 8) + i]; } if (rom_[core::overworldgfxGroups + (area_graphics_ * 4)] != 0) { static_graphics_[3] = rom_[core::overworldgfxGroups + (area_graphics_ * 4)]; } if (rom_[core::overworldgfxGroups + (area_graphics_ * 4) + 1] != 0) { static_graphics_[4] = rom_[core::overworldgfxGroups + (area_graphics_ * 4) + 1]; } if (rom_[core::overworldgfxGroups + (area_graphics_ * 4) + 2] != 0) { static_graphics_[5] = rom_[core::overworldgfxGroups + (area_graphics_ * 4) + 2]; } if (rom_[core::overworldgfxGroups + (area_graphics_ * 4) + 3] != 0) { static_graphics_[6] = rom_[core::overworldgfxGroups + (area_graphics_ * 4) + 3]; } // Hardcoded overworld GFX Values, for death mountain if ((parent_ >= 0x03 && parent_ <= 0x07) || (parent_ >= 0x0B && parent_ <= 0x0E)) { static_graphics_[7] = 0x59; } else if ((parent_ >= 0x43 && parent_ <= 0x47) || (parent_ >= 0x4B && parent_ <= 0x4E)) { static_graphics_[7] = 0x59; } else { static_graphics_[7] = 0x5B; } } void OverworldMap::LoadPalette() { int previousPalId = 0; int previousSprPalId = 0; if (index_ > 0) { previousPalId = rom_[core::overworldMapPalette + parent_ - 1]; previousSprPalId = rom_[core::overworldSpritePalette + parent_ - 1]; } if (area_palette_ >= 0xA3) { area_palette_ = 0xA3; } uchar pal0 = 0; uchar pal1 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4)]; uchar pal2 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) + 1]; // aux2 uchar pal3 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) + 2]; // animated uchar pal4 = rom_[core::overworldSpritePaletteGroup + (sprite_palette_[game_state_] * 2)]; // spr3 uchar pal5 = rom_[core::overworldSpritePaletteGroup + (sprite_palette_[game_state_] * 2) + 1]; // spr4 gfx::SNESPalette aux1; gfx::SNESPalette aux2; gfx::SNESPalette main; gfx::SNESPalette animated; gfx::SNESPalette hud; gfx::SNESPalette spr; gfx::SNESPalette spr2; gfx::SNESColor bgr = rom_.GetPaletteGroup("grass")[0].GetColor(0); if (pal1 == 255) { pal1 = rom_[core::overworldMapPaletteGroup + (previousPalId * 4)]; } if (pal1 != 255) { if (pal1 >= 20) { pal1 = 19; } aux1 = rom_.GetPaletteGroup("ow_aux")[pal1]; } else { aux1 = rom_.GetPaletteGroup("ow_aux")[0]; } if (pal2 == 255) { pal2 = rom_[core::overworldMapPaletteGroup + (previousPalId * 4) + 1]; } if (pal2 != 255) { if (pal2 >= 20) { pal2 = 19; } aux2 = rom_.GetPaletteGroup("ow_aux")[pal2]; } else { aux2 = rom_.GetPaletteGroup("ow_aux")[0]; } if (pal3 == 255) { pal3 = rom_[core::overworldMapPaletteGroup + (previousPalId * 4) + 2]; } if (parent_ < 0x40) { // Default LW Palette pal0 = 0; bgr = rom_.GetPaletteGroup("grass")[0].GetColor(0); if (parent_ == 0x03 || parent_ == 0x05 || parent_ == 0x07) { pal0 = 2; } } else if (parent_ >= 0x40 && parent_ < 0x80) { // Default DW Palette pal0 = 1; bgr = rom_.GetPaletteGroup("grass")[0].GetColor(1); if (parent_ == 0x43 || parent_ == 0x45 || parent_ == 0x47) { pal0 = 3; } } else if (parent_ >= 128 && parent_ < core::kNumOverworldMaps) { // Default SP Palette pal0 = 0; bgr = rom_.GetPaletteGroup("grass")[0].GetColor(2); } if (parent_ == 0x88) { pal0 = 4; } if (pal0 != 255) { main = rom_.GetPaletteGroup("ow_main")[pal0]; } else { main = rom_.GetPaletteGroup("ow_main")[0]; } if (pal3 >= 14) { pal3 = 13; } animated = rom_.GetPaletteGroup("ow_animated")[(pal3)]; hud = rom_.GetPaletteGroup("hud")[0]; if (pal4 == 255) { pal4 = rom_[core::overworldSpritePaletteGroup + (previousSprPalId * 2)]; // spr3 } if (pal4 == 255) { pal4 = 0; } if (pal4 >= 24) { pal4 = 23; } spr = rom_.GetPaletteGroup("sprites_aux3")[pal4]; if (pal5 == 255) { pal5 = rom_[core::overworldSpritePaletteGroup + (previousSprPalId * 2) + 1]; // spr3 } if (pal5 == 255) { pal5 = 0; } if (pal5 >= 24) { pal5 = 23; } spr2 = rom_.GetPaletteGroup("sprites_aux3")[pal5]; SetColorsPalette(rom_, parent_, current_palette_, main, animated, aux1, aux2, hud, bgr, spr, spr2); } absl::Status OverworldMap::BuildTileset() { all_gfx_ = rom_.GetGraphicsBuffer(); current_gfx_.reserve(0x10000); for (int i = 0; i < 0x10000; i++) { current_gfx_.push_back(0x00); } for (int i = 0; i < 0x10; i++) { for (int j = 0; j < 0x1000; j++) { auto byte = all_gfx_[j + (static_graphics_[i] * 0x1000)]; switch (i) { case 0: case 3: case 4: case 5: byte += 0x88; break; } current_gfx_[(i * 0x1000) + j] = byte; } } return absl::OkStatus(); } absl::Status OverworldMap::BuildTiles16Gfx(int count) { current_blockset_.reserve(0x100000); for (int i = 0; i < 0x100000; i++) { current_blockset_.push_back(0x00); } const int offsets[] = {0x00, 0x08, 0x400, 0x408}; auto yy = 0; auto xx = 0; for (auto i = 0; i < count; i++) { for (auto tile = 0; tile < 0x04; tile++) { gfx::TileInfo info = tiles16_[i].tiles_info[tile]; int offset = offsets[tile]; for (auto y = 0; y < 0x08; ++y) { for (auto x = 0; x < 0x08; ++x) { int mx = x; int my = y; if (info.horizontal_mirror_ != 0) { mx = 0x07 - x; } if (info.vertical_mirror_ != 0) { my = 0x07 - y; } int xpos = ((info.id_ % 0x10) * 0x08); int ypos = (((info.id_ / 0x10)) * 0x400); int source = ypos + xpos + (x + (y * 0x80)); auto destination = xx + yy + offset + (mx + (my * 0x80)); current_blockset_[destination] = (current_gfx_[source] & 0x0F) + (info.palette_ * 0x10); } } } xx += 0x10; if (xx >= 0x80) { yy += 0x800; xx = 0; } } return absl::OkStatus(); } absl::Status OverworldMap::BuildBitmap(OWBlockset& world_blockset) { bitmap_data_.reserve(0x40000); for (int i = 0; i < 0x40000; i++) { bitmap_data_.push_back(0x00); } int superY = ((index_ - (world_ * 0x40)) / 0x08); int superX = index_ - (world_ * 0x40) - (superY * 0x08); for (int y = 0; y < 0x20; y++) { for (int x = 0; x < 0x20; x++) { auto xt = x + (superX * 0x20); auto yt = y + (superY * 0x20); CopyTile8bpp16((x * 0x10), (y * 0x10), world_blockset[xt][yt], bitmap_data_, current_blockset_); } } return absl::OkStatus(); } } // namespace zelda3 } // namespace app } // namespace yaze