Skip to content

Commit

Permalink
Rewrite Map: Tiles AB Initial Support
Browse files Browse the repository at this point in the history
  • Loading branch information
jetrotal committed Jan 12, 2025
1 parent b983e20 commit 8bcba94
Showing 1 changed file with 54 additions and 33 deletions.
87 changes: 54 additions & 33 deletions src/tilemap_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ static constexpr uint8_t BlockD_Subtiles_IDS[50][2][2][2] = {
// Set of neighboring autotiles -> autotile variant
// Each neighbor is represented by a single bit (1 - same autotile, 0 - any other case)
// The bits are ordered as follows (from most to least significant bit): NW N NE W E SW S SE
static const std::unordered_map<uint8_t, int> AUTOTILE_D_VARIANTS_MAP = {
static const std::unordered_map<uint8_t, int> AUTOTILE_D_VARIANTS_MAP = { //it also works with A
{0b11111111, 0},
{0b01111111, 1},
{0b11011111, 2},
Expand Down Expand Up @@ -771,6 +771,27 @@ static inline bool IsAutotileD(int tile_id) {
return tile_id >= BLOCK_D && tile_id < BLOCK_E;
}

static inline bool IsSameAutotileAB(int current_tile_id, int neighbor_tile_id) {
// Special case for water tiles - allow mixing of A and B blocks
bool current_is_water = (IsTileFromBlock(current_tile_id, BLOCK_A) ||
IsTileFromBlock(current_tile_id, BLOCK_B));
bool neighbor_is_water = (IsTileFromBlock(neighbor_tile_id, BLOCK_A) ||
IsTileFromBlock(neighbor_tile_id, BLOCK_B));

if (current_is_water && neighbor_is_water) {
return true;
}

// For non-water tiles, keep original behavior of requiring same block
if (IsTileFromBlock(current_tile_id, BLOCK_A) && IsTileFromBlock(neighbor_tile_id, BLOCK_A)) {
return true;
}
if (IsTileFromBlock(current_tile_id, BLOCK_B) && IsTileFromBlock(neighbor_tile_id, BLOCK_B)) {
return true;
}
return false;
}

static inline bool IsSameAutotileD(int current_tile_id, int neighbor_tile_id) {
return ChipIdToIndex(current_tile_id) == ChipIdToIndex(neighbor_tile_id);
}
Expand Down Expand Up @@ -798,44 +819,44 @@ static inline void ApplyCornerFixups(uint8_t& neighbors) {
}

void TilemapLayer::RecalculateAutotile(int x, int y, int tile_id) {
// TODO: make it work for AB autotiles
bool is_tileAB = IsTileFromBlock(tile_id, BLOCK_A) || IsTileFromBlock(tile_id, BLOCK_B);
if (is_tileAB) {
RecreateTileDataAt(x, y, tile_id);
Output::Warning("Maniac Patch: Autotiles AB in RewriteMap are only partially supported.");
return;
}

if (!IsAutotileD(tile_id)) {
return;
}

const int block = (tile_id - BLOCK_D) / BLOCK_D_STRIDE;
uint8_t neighbors = 0;

// Get all neighboring tiles in a single pass
static constexpr struct { int dx; int dy; uint8_t bit; } adjacent[8] = {
{-1, -1, NEIGHBOR_NW}, { 0, -1, NEIGHBOR_N}, { 1, -1, NEIGHBOR_NE},
{-1, 0, NEIGHBOR_W }, { 1, 0, NEIGHBOR_E},
{-1, 1, NEIGHBOR_SW}, { 0, 1, NEIGHBOR_S}, { 1, 1, NEIGHBOR_SE}
{-1, -1, NEIGHBOR_NW}, { 0, -1, NEIGHBOR_N}, { 1, -1, NEIGHBOR_NE},
{-1, 0, NEIGHBOR_W }, { 1, 0, NEIGHBOR_E},
{-1, 1, NEIGHBOR_SW}, { 0, 1, NEIGHBOR_S}, { 1, 1, NEIGHBOR_SE}
};

// Build the neighbors mask and fixup corners
for (const auto& adj : adjacent) {
auto nx = x + adj.dx;
auto ny = y + adj.dy;
auto adj_tile_id = IsInMapBounds(nx, ny) ? GetDataCache(nx, ny).ID : tile_id;
if (IsSameAutotileD(tile_id, adj_tile_id)) {
neighbors |= adj.bit;
auto calculateNeighbors = [&](auto isSameAutotileFn) {
uint8_t neighbors = 0;
for (const auto& adj : adjacent) {
auto nx = x + adj.dx;
auto ny = y + adj.dy;
auto adj_tile_id = IsInMapBounds(nx, ny) ? GetDataCache(nx, ny).ID : tile_id;
if (isSameAutotileFn(tile_id, adj_tile_id)) {
neighbors |= adj.bit;
}
}
}
ApplyCornerFixups(neighbors);
ApplyCornerFixups(neighbors);
return neighbors;
};

// Recalculate tile id using the neighbors -> variant map
const int new_tile_id = BLOCK_D + block * BLOCK_D_STRIDE + AUTOTILE_D_VARIANTS_MAP.at(neighbors);
RecreateTileDataAt(x, y, new_tile_id);
}
auto processBlock = [&](int blockType, int blockStride, int blockBase, auto isSameAutotileFn) {
uint8_t neighbors = calculateNeighbors(isSameAutotileFn);
int block = (tile_id - blockBase) / blockStride;
int variant = AUTOTILE_D_VARIANTS_MAP.at(neighbors);
int new_tile_id = blockBase + (block * blockStride) + variant;
RecreateTileDataAt(x, y, new_tile_id);
};

if (IsTileFromBlock(tile_id, BLOCK_A)) {
processBlock(BLOCK_A, BLOCK_A_STRIDE, BLOCK_A, IsSameAutotileAB);
}
if (IsTileFromBlock(tile_id, BLOCK_B)) {
processBlock(BLOCK_B, BLOCK_B_STRIDE, BLOCK_B, IsSameAutotileAB);
}
if (IsTileFromBlock(tile_id, BLOCK_D)) {
processBlock(BLOCK_D, BLOCK_D_STRIDE, BLOCK_D, IsSameAutotileD);
}
}
void TilemapLayer::SetPassable(std::vector<unsigned char> npassable) {
passable = std::move(npassable);

Expand Down

0 comments on commit 8bcba94

Please sign in to comment.