SHARE
TWEET

pure insanity

a guest Dec 20th, 2019 5 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #define USE_FLOODFILL 1
  2. #if USE_FLOODFILL
  3. // BEGIN FLOODFILL AMMENDMENT
  4. #include <vector>
  5.  
  6. struct point_t
  7. {
  8.     point_t(int _x, int _y) : x(_x), y(_y)
  9.     {
  10.     }
  11.     void operator=(point_t &p)
  12.     {
  13.         x = p.x;
  14.         y = p.y;
  15.     }
  16.     int x;
  17.     int y;
  18. };
  19.  
  20. template <typename T>
  21. struct floodfill_stack_t
  22. {
  23.     floodfill_stack_t()
  24.     {
  25.         stack.reserve(16);
  26.         stack_pointer = 0;
  27.         max_stack = 0;
  28.     }
  29.     bool push(T t)
  30.     {
  31.         if (stack_pointer == stack.size() - 1) {
  32.             stack.resize(stack.size() + 16);
  33.         }
  34.         stack[stack_pointer] = t;
  35.         stack_pointer++;
  36.         if (stack_pointer > max_stack) {
  37.             max_stack = stack_pointer;
  38.         }
  39.         return 1;
  40.     }    
  41.     bool pop(T &t)
  42.     {
  43.         if (stack_pointer > 0) {
  44.             t = stack[stack_pointer - 1];
  45.             stack_pointer--;
  46.             return 1;
  47.         } else {
  48.             return 0;
  49.         }    
  50.     }    
  51.     void clear()
  52.     {
  53.         stack_pointer = 0;
  54.     }
  55.     int stack_pointer;
  56.     int max_stack;
  57.     std::vector<T> stack;
  58. };
  59.  
  60. // type T must store >= (last - first) bits
  61. template <typename T>
  62. T getbits(const void *p, const int first, const int last)
  63. {
  64.     using U8T = std::uint8_t;
  65.     int bits = last - first + 1;
  66.     int offset = first;
  67.     T dat = 0;
  68.     U8T *src = (U8T *)p;
  69.  
  70.     src += (offset/8);
  71.     offset -= (offset/8)*8;
  72.  
  73.     if (offset > 0) {
  74.         dat |= *src >> offset;
  75.         if (bits < 8) {
  76.             dat &= ((1 << bits) - 1);
  77.         }
  78.         src++;
  79.         offset = (8 - offset);
  80.         bits -= offset;
  81.     }
  82.  
  83.     while (bits >= 8) {
  84.         dat |= *src << offset;
  85.         src++;
  86.         offset += 8;
  87.         bits -= 8;
  88.     }
  89.  
  90.     if (bits > 0) {
  91.         dat |= (*src << offset) & (((1 << bits) - 1) << offset);
  92.     }
  93.  
  94.     return dat;
  95. }
  96.  
  97. // type T must store >= (last - first) bits
  98. template <typename T>
  99. void setbits(void *p, const int first, const int last, T dat)
  100. {
  101.     using U8T = std::uint8_t;
  102.     int bits = last - first + 1;
  103.     int offset = first;
  104.     U8T *dest = (U8T *)p;
  105.  
  106.     dest += (offset/8);
  107.     offset -= (offset/8)*8;
  108.  
  109.     if (offset) {
  110.         U8T mask = 255 >> (8 - offset);
  111.         if (bits < 8 - offset) {
  112.             U8T amask = ~(255 >> (8 - bits - offset));
  113.             mask |= amask;
  114.         }
  115.         *dest &= mask;
  116.         *dest |= (dat << offset) & (U8T)~mask;
  117.         dest++;
  118.         bits -= (8 - offset);
  119.         dat >>= (8 - offset);
  120.     }
  121.  
  122.     while (bits >= 8) {
  123.         *dest = dat & 255;
  124.         dest++;
  125.         bits -= 8;
  126.         dat >>= 8;
  127.     }
  128.  
  129.     if (bits > 0) {
  130.         U8T mask = ((1 << bits) - 1);
  131.         *dest &= ~mask;
  132.         *dest |= dat & mask;
  133.     }
  134. }
  135.  
  136. std::uintmax_t read_tile_xy_bits(int x, int y, const int first, const int last, const std::uintmax_t mask)
  137. {
  138.     const TileIndex ti = TileXY(x, y);
  139.     return getbits<std::uintmax_t>(&_m[ti], first, last) & mask;
  140. }
  141.  
  142. void write_tile_xy_bits(int x, int y, const int first, const int last, const std::uintmax_t data, const std::uintmax_t mask)
  143. {
  144.     const TileIndex ti = TileXY(x, y);
  145.     std::uintmax_t existing_data = read_tile_xy_bits(x, y, first, last, ~mask);
  146.     setbits<std::uintmax_t>(&_m[ti], first, last, existing_data | (data & mask));
  147. }
  148.  
  149. void floodfill(TileIndex t, const int8 *new_data_ptr, const int8 *target_data_ptr, const int first_bit, const int last_bit, std::uintmax_t read_mask, std::uintmax_t write_mask)
  150. {
  151.     using BT = std::uintmax_t;
  152.     using T = point_t;
  153.     floodfill_stack_t<T> stack;
  154.  
  155.     BT target_data = getbits<BT>(target_data_ptr, first_bit, last_bit) & read_mask;
  156.     BT new_data_read_mask = getbits<BT>(new_data_ptr, first_bit, last_bit) & read_mask;
  157.  
  158.     // ensure the new data does not match the targeted data (escape from ouroboros)
  159.     assert(target_data != new_data_read_mask);
  160.     if (target_data == new_data_read_mask) {
  161.         return;
  162.     }
  163.  
  164.     BT new_data = getbits<BT>(new_data_ptr, first_bit, last_bit) & write_mask;
  165.     point_t p(TileX(t), TileY(t));
  166.  
  167.     const int width = MapSizeX();
  168.     const int height = MapSizeY();
  169.     const int x_min = 1;
  170.     const int x_max = width - 1;
  171.     const int y_min = 1;
  172.     const int y_max = height - 1;
  173.  
  174.     stack.clear();
  175.  
  176.     if (!stack.push(p)) {
  177.         return;
  178.     }
  179.        
  180.     while (stack.pop(p)) {    
  181.         int y1 = p.y;
  182.         while (y1 >= y_min) {
  183.             BT c = read_tile_xy_bits(p.x, y1, first_bit, last_bit, read_mask);
  184.             if (c != target_data) {
  185.                 break;
  186.             }
  187.             y1--;
  188.         }
  189.         y1++;
  190.                
  191.         bool span_left = false;
  192.         bool span_right = false;
  193.  
  194.         while (y1 < y_max) {
  195.             BT c = read_tile_xy_bits(p.x, y1, first_bit, last_bit, read_mask);
  196.             if (c != target_data) {
  197.                 break;
  198.             }
  199.  
  200.             // target match, write the new data
  201.             write_tile_xy_bits(p.x, y1, first_bit, last_bit, new_data, write_mask);
  202.  
  203.             if (!span_left && p.x > x_min && read_tile_xy_bits(p.x - 1, y1, first_bit, last_bit, read_mask) == target_data) {
  204.                     if (!stack.push(point_t(p.x - 1, y1))) {
  205.                         return;
  206.                     }
  207.                     span_left = true;
  208.             } else if (span_left && p.x > x_min && read_tile_xy_bits(p.x - 1, y1, first_bit, last_bit, read_mask) != target_data) {
  209.                     span_left = false;
  210.             }
  211.            
  212.             if (!span_right && p.x < x_max && read_tile_xy_bits(p.x + 1, y1, first_bit, last_bit, read_mask) == target_data) {
  213.                     if (!stack.push(point_t(p.x + 1, y1))) {
  214.                         return;
  215.                     }
  216.                     span_right = true;
  217.                 } else if (span_right && p.x < x_max && read_tile_xy_bits(p.x + 1, y1, first_bit, last_bit, read_mask) != target_data) {
  218.                     span_right = false;
  219.             }
  220.             y1++;
  221.         }
  222.     }
  223. }
  224.  
  225. /**
  226.  * Floodfill from selected tile
  227.  * @param tile end tile of stretch-dragging
  228.  * @param flags type of operation
  229.  * @param p1 start tile of stretch-dragging
  230.  * @param p2 {1, 2} waterclass. {3 to 8} unused. {9 to 16} height to add during fill. {17 to 32} unused.
  231.  * @param text unused
  232.  * @return the cost of this operation or an error
  233.  */
  234. CommandCost CmdFloodFill(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
  235. {
  236.     WaterClass wc = Extract<WaterClass, 0, 2>(p2);
  237.     if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR;
  238.  
  239.     /* Outside of the editor you can only build canals, not oceans */
  240.     if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;
  241.  
  242.     TileArea ta(tile, p1);
  243.  
  244.     /* Outside the editor you can only drag canals, and not areas */
  245.     if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
  246.  
  247.     CommandCost cost(EXPENSES_CONSTRUCTION);
  248.     TILE_AREA_LOOP(tile, ta) {
  249.         CommandCost ret;
  250.  
  251.         Slope slope = GetTileSlope(tile);
  252.         if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
  253.             return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
  254.         }
  255.  
  256.         /* can't make water of water! */
  257.         if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;
  258.  
  259.         bool water = IsWaterTile(tile);
  260.         ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
  261.         if (ret.Failed()) return ret;
  262.  
  263.         if (!water) cost.AddCost(ret);
  264.  
  265.         if (flags & DC_EXEC) {
  266.             switch (wc) {
  267.                 case WATER_CLASS_RIVER:
  268.                     MakeRiver(tile, Random());
  269.                     if (_game_mode == GM_EDITOR) {
  270.                         TileIndex tile2 = tile;
  271.                         CircularTileSearch(&tile2, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
  272.                     }
  273.                     break;
  274.  
  275.                 case WATER_CLASS_SEA:
  276.                     if (TileHeight(tile) == 0) {
  277.                         MakeSea(tile);
  278.                         break;
  279.                     }
  280.                     FALLTHROUGH;
  281.  
  282.                 default:
  283.                     MakeCanal(tile, _current_company, Random());
  284.                     if (Company::IsValidID(_current_company)) {
  285.                         Company::Get(_current_company)->infrastructure.water++;
  286.                         DirtyCompanyInfrastructureWindows(_current_company);
  287.                     }
  288.                     break;
  289.             }
  290.             MarkTileDirtyByTile(tile);
  291.             MarkCanalsAndRiversAroundDirty(tile);
  292.             CheckForDockingTile(tile);
  293.         }
  294.  
  295.         cost.AddCost(_price[PR_BUILD_CANAL]);
  296.     }
  297.  
  298.     if (cost.GetCost() == 0) {
  299.         return_cmd_error(STR_ERROR_ALREADY_BUILT);
  300.     } else {
  301.         return cost;
  302.     }
  303. }
  304. // END FLOODFILL AMMENDMENT
  305. #endif
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top