@@ -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+
737744void 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+
860941void TilemapLayer::SetPassable (std::vector<unsigned char > npassable) {
861942 passable = std::move (npassable);
862943
0 commit comments