@@ -722,6 +722,10 @@ void TilemapLayer::SetMapData(std::vector<short> nmap_data) {
722722 map_data = std::move (nmap_data);
723723}
724724
725+ static inline bool IsAutotileD (int tile_id) {
726+ return tile_id >= BLOCK_D && tile_id < BLOCK_E;
727+ }
728+
725729static inline bool IsTileFromBlock (int tile_id, int block) {
726730 switch (block) {
727731 case BLOCK_A: return tile_id >= BLOCK_A && tile_id < BLOCK_A_END;
@@ -734,41 +738,11 @@ static inline bool IsTileFromBlock(int tile_id, int block) {
734738 }
735739}
736740
737- void TilemapLayer::SetMapTileDataAt (int x, int y, int tile_id, bool disable_autotile) {
738- if (!IsInMapBounds (x, y))
739- return ;
740-
741- substitutions = Game_Map::GetTilesLayer (layer);
742-
743- bool is_autotile = IsTileFromBlock (tile_id, BLOCK_A) || IsTileFromBlock (tile_id, BLOCK_B) || IsTileFromBlock (tile_id, BLOCK_D);
744-
745- if (disable_autotile || !is_autotile) {
746- RecreateTileDataAt (x, y, tile_id);
747- } else {
748- // Recalculate the replaced tile itself + every neighboring tile
749- static constexpr struct { int dx; int dy; } adjacent[8 ] = {
750- {-1 , -1 }, { 0 , -1 }, { 1 , -1 },
751- {-1 , 0 }, { 1 , 0 },
752- {-1 , 1 }, { 0 , 1 }, { 1 , 1 }
753- };
754-
755- // TODO: make it work for AB autotiles
756- RecalculateAutotile (x, y, tile_id);
757-
758- for (const auto & adj : adjacent) {
759- auto nx = x + adj.dx ;
760- auto ny = y + adj.dy ;
761- if (IsInMapBounds (nx, ny)) {
762- RecalculateAutotile (nx, ny, GetDataCache (nx, ny).ID );
763- }
764- }
765- }
766-
767- SetMapData (map_data);
741+ static bool IsWaterTile (int tile_id) {
742+ return tile_id >= 0 && tile_id < 3000 ;
768743}
769-
770- static inline bool IsAutotileD (int tile_id) {
771- return tile_id >= BLOCK_D && tile_id < BLOCK_E;
744+ static bool IsDeepWaterTile (int tile_id) {
745+ return tile_id >= 2000 && tile_id < 3000 ;
772746}
773747
774748static inline bool IsSameAutotileAB (int current_tile_id, int neighbor_tile_id) {
@@ -818,6 +792,39 @@ static inline void ApplyCornerFixups(uint8_t& neighbors) {
818792 }
819793}
820794
795+ // Maniac Patch - Rewrite Map Main Method:
796+ void TilemapLayer::SetMapTileDataAt (int x, int y, int tile_id, bool disable_autotile) {
797+ if (!IsInMapBounds (x, y))
798+ return ;
799+
800+ substitutions = Game_Map::GetTilesLayer (layer);
801+
802+ bool is_autotile = IsTileFromBlock (tile_id, BLOCK_A) || IsTileFromBlock (tile_id, BLOCK_B) || IsTileFromBlock (tile_id, BLOCK_D);
803+
804+ if (disable_autotile || !is_autotile) {
805+ RecreateTileDataAt (x, y, tile_id);
806+ } else {
807+ // Recalculate the replaced tile itself + every neighboring tile
808+ static constexpr struct { int dx; int dy; } adjacent[8 ] = {
809+ {-1 , -1 }, { 0 , -1 }, { 1 , -1 },
810+ {-1 , 0 }, { 1 , 0 },
811+ {-1 , 1 }, { 0 , 1 }, { 1 , 1 }
812+ };
813+
814+ RecalculateAutotile (x, y, tile_id);
815+
816+ for (const auto & adj : adjacent) {
817+ auto nx = x + adj.dx ;
818+ auto ny = y + adj.dy ;
819+ if (IsInMapBounds (nx, ny)) {
820+ RecalculateAutotile (nx, ny, GetDataCache (nx, ny).ID );
821+ }
822+ }
823+ }
824+
825+ SetMapData (map_data);
826+ }
827+
821828void TilemapLayer::RecalculateAutotile (int x, int y, int tile_id) {
822829 static constexpr struct { int dx; int dy; uint8_t bit; } adjacent[8 ] = {
823830 {-1 , -1 , NEIGHBOR_NW}, { 0 , -1 , NEIGHBOR_N}, { 1 , -1 , NEIGHBOR_NE},
@@ -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 type == 2 ;
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