Skip to content

Commit f6909c7

Browse files
committed
Maniacs Patch - AB Autotiling Support
Introduces IsWaterTile and IsDeepWaterTile helpers and implements specialized autotiling logic for water and deep water tiles in RecalculateAutotile. This enables more accurate coastline and deep water boundary rendering, including diagonal and cardinal neighbor checks for seamless water transitions.
1 parent 31de2a7 commit f6909c7

File tree

1 file changed

+86
-5
lines changed

1 file changed

+86
-5
lines changed

src/tilemap_layer.cpp

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,13 @@ static inline bool IsTileFromBlock(int tile_id, int block) {
734734
}
735735
}
736736

737+
static bool IsWaterTile(int tile_id) {
738+
return tile_id >= 0 && tile_id < 3000;
739+
}
740+
static bool IsDeepWaterTile(int tile_id) {
741+
return tile_id >= 2000 && tile_id < 3000;
742+
}
743+
737744
void TilemapLayer::SetMapTileDataAt(int x, int y, int tile_id, bool disable_autotile) {
738745
if(!IsInMapBounds(x, y))
739746
return;
@@ -847,16 +854,90 @@ void TilemapLayer::RecalculateAutotile(int x, int y, int tile_id) {
847854
RecreateTileDataAt(x, y, new_tile_id);
848855
};
849856

850-
if (IsTileFromBlock(tile_id, BLOCK_A)) {
851-
processBlock(BLOCK_A, BLOCK_A_STRIDE, BLOCK_A, IsSameAutotileAB);
852-
}
853-
if (IsTileFromBlock(tile_id, BLOCK_B)) {
854-
processBlock(BLOCK_B, BLOCK_B_STRIDE, BLOCK_B, IsSameAutotileAB);
857+
if (IsWaterTile(tile_id)) {
858+
int type = tile_id / 1000;
859+
int base = type * 1000;
860+
861+
// 1. Calculate a_subtile (Coastline) - 8 neighbors
862+
// Any Water connects to Any Water (0-2999) + Animated (3000-3999)
863+
auto isWaterCompatible = [&](int /*curr*/, int neighbor) {
864+
return IsWaterTile(neighbor) || (neighbor >= 3000 && neighbor < 4000);
865+
};
866+
867+
uint8_t neighbors_a = calculateNeighbors(isWaterCompatible);
868+
int a_subtile = AUTOTILE_D_VARIANTS_MAP.at(neighbors_a);
869+
870+
// 2. Calculate b_subtile (Deep Boundary) - 4 neighbors (N, E, S, W)
871+
auto is_b_compatible = [&](int nid) {
872+
bool n_deep = IsDeepWaterTile(nid);
873+
bool n_water = IsWaterTile(nid) || (nid >= 3000 && nid < 4000);
874+
875+
if (type == 2) { // Deep
876+
// Deep connects to Deep or Land (Non-Water). Blocks on Shallow.
877+
return n_deep || !n_water;
878+
}
879+
else { // Shallow
880+
// Shallow connects to Shallow or Land. Blocks on Deep.
881+
return !n_deep;
882+
}
883+
};
884+
885+
auto check_blocked = [&](int dx, int dy) {
886+
auto nx = x + dx;
887+
auto ny = y + dy;
888+
if (!IsInMapBounds(nx, ny)) return false; // Treat map edge as connected
889+
auto adj_id = GetDataCache(nx, ny).ID;
890+
return !is_b_compatible(adj_id);
891+
};
892+
893+
bool b_n = check_blocked(0, -1);
894+
bool b_e = check_blocked(1, 0);
895+
bool b_s = check_blocked(0, 1);
896+
bool b_w = check_blocked(-1, 0);
897+
898+
int b_subtile = 0;
899+
900+
if (type == 2) {
901+
// Handle diagonal connections for Deep Water (Type 2)
902+
// A corner is only cut (border added) if the cardinal neighbors are blocked
903+
// AND the corresponding diagonal neighbor is NOT Deep Water.
904+
// If the diagonal neighbor IS Deep Water, we maintain the connection (don't cut).
905+
906+
auto check_diag_deep = [&](int dx, int dy) {
907+
auto nx = x + dx;
908+
auto ny = y + dy;
909+
if (!IsInMapBounds(nx, ny)) return false;
910+
auto adj_id = GetDataCache(nx, ny).ID;
911+
return IsDeepWaterTile(adj_id);
912+
};
913+
914+
bool d_nw = check_diag_deep(-1, -1);
915+
bool d_ne = check_diag_deep(1, -1);
916+
bool d_sw = check_diag_deep(-1, 1);
917+
bool d_se = check_diag_deep(1, 1);
918+
919+
if (b_n && b_w && !d_nw) b_subtile |= 1; // TL
920+
if (b_n && b_e && !d_ne) b_subtile |= 2; // TR
921+
if (b_s && b_w && !d_sw) b_subtile |= 4; // BL
922+
if (b_s && b_e && !d_se) b_subtile |= 8; // BR
923+
}
924+
else {
925+
// Shallow Water (Type 0 & 1) - Standard corner logic
926+
if (b_n && b_w) b_subtile |= 1; // TL
927+
if (b_n && b_e) b_subtile |= 2; // TR
928+
if (b_s && b_w) b_subtile |= 4; // BL
929+
if (b_s && b_e) b_subtile |= 8; // BR
930+
}
931+
932+
int new_tile_id = base + (b_subtile * 50) + a_subtile;
933+
RecreateTileDataAt(x, y, new_tile_id);
855934
}
935+
856936
if (IsTileFromBlock(tile_id, BLOCK_D)) {
857937
processBlock(BLOCK_D, BLOCK_D_STRIDE, BLOCK_D, IsSameAutotileD);
858938
}
859939
}
940+
860941
void TilemapLayer::SetPassable(std::vector<unsigned char> npassable) {
861942
passable = std::move(npassable);
862943

0 commit comments

Comments
 (0)