diff --git a/src/tile.cc b/src/tile.cc index a7e98aa..af68a39 100644 --- a/src/tile.cc +++ b/src/tile.cc @@ -5,6 +5,7 @@ #include #include +#include #include "art.h" #include "color.h" @@ -49,11 +50,16 @@ typedef struct UpsideDownTriangle { int field_8; } UpsideDownTriangle; +struct roof_fill_task { + int x; + int y; +}; + static void tileSetBorder(int windowWidth, int windowHeight, int hexGridWidth, int hexGridHeight); static void tileRefreshMapper(Rect* rect, int elevation); static void tileRefreshGame(Rect* rect, int elevation); -static void roof_fill_on(int x, int y, int elevation); -static void roof_fill_off(int x, int y, int elevation); +static void roof_fill_push_task_if_in_bounds(std::stack& tasks_stack, int x, int y); +static void roof_fill_off_process_task(std::stack& tasks_stack, int elevation, bool on); static void tileRenderRoof(int fid, int x, int y, Rect* rect, int light); static void _draw_grid(int tile, int elevation, Rect* rect); static void tileRenderFloor(int fid, int x, int y, Rect* rect); @@ -1258,27 +1264,39 @@ void tileRenderRoofsInRect(Rect* rect, int elevation) } } -// 0x4B22D0 -static void roof_fill_on(int x, int y, int elevation) +static void roof_fill_push_task_if_in_bounds(std::stack& tasks_stack, int x, int y) { if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) { - int squareTileIndex = gSquareGridWidth * y + x; - int squareTile = gTileSquares[elevation]->field_0[squareTileIndex]; - int roof = (squareTile >> 16) & 0xFFFF; + tasks_stack.push(roof_fill_task { x, y }); + }; +}; - int id = roof & 0xFFF; - if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { - int flag = (roof & 0xF000) >> 12; - if ((flag & 0x01) != 0) { +static void roof_fill_off_process_task(std::stack& tasks_stack, int elevation, bool on) +{ + auto [x, y] = tasks_stack.top(); + tasks_stack.pop(); + + int squareTileIndex = gSquareGridWidth * y + x; + int squareTile = gTileSquares[elevation]->field_0[squareTileIndex]; + int roof = (squareTile >> 16) & 0xFFFF; + + int id = roof & 0xFFF; + if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { + int flag = (roof & 0xF000) >> 12; + + if (on ? ((flag & 0x01) != 0) : ((flag & 0x03) == 0)) { + if (on) { flag &= ~0x01; - - gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16); - - roof_fill_on(x - 1, y, elevation); - roof_fill_on(x + 1, y, elevation); - roof_fill_on(x, y - 1, elevation); - roof_fill_on(x, y + 1, elevation); + } else { + flag |= 0x01; } + + gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16); + + roof_fill_push_task_if_in_bounds(tasks_stack, x - 1, y); + roof_fill_push_task_if_in_bounds(tasks_stack, x + 1, y); + roof_fill_push_task_if_in_bounds(tasks_stack, x, y - 1); + roof_fill_push_task_if_in_bounds(tasks_stack, x, y + 1); } } } @@ -1286,35 +1304,12 @@ static void roof_fill_on(int x, int y, int elevation) // 0x4B23D4 void tile_fill_roof(int x, int y, int elevation, bool on) { - if (on) { - roof_fill_on(x, y, elevation); - } else { - roof_fill_off(x, y, elevation); - } -} + std::stack tasks_stack; -// 0x4B23DC -static void roof_fill_off(int x, int y, int elevation) -{ - if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) { - int squareTileIndex = gSquareGridWidth * y + x; - int squareTile = gTileSquares[elevation]->field_0[squareTileIndex]; - int roof = (squareTile >> 16) & 0xFFFF; + roof_fill_push_task_if_in_bounds(tasks_stack, x, y); - int id = roof & 0xFFF; - if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { - int flag = (roof & 0xF000) >> 12; - if ((flag & 0x03) == 0) { - flag |= 0x01; - - gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16); - - roof_fill_off(x - 1, y, elevation); - roof_fill_off(x + 1, y, elevation); - roof_fill_off(x, y - 1, elevation); - roof_fill_off(x, y + 1, elevation); - } - } + while (!tasks_stack.empty()) { + roof_fill_off_process_task(tasks_stack, elevation, on); } }