Advertisement
Guest User

pure insanity

a guest
Dec 20th, 2019
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.91 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement