From 3bbd7ea2c1a7f3631362805da76848112f7a606d Mon Sep 17 00:00:00 2001 From: PeterN Date: Sat, 13 Apr 2019 14:27:57 +0100 Subject: [PATCH] Fix: Industry coverage area is no longer rectangular. (#7464) AIs test station catchment in reverse to how players see station catchment. This did not take account of non-rectangular station catchment areas, so AIs could end up placing stations in locations that did not accept/deliver cargo. --- bin/ai/regression/tst_regression/result.txt | 4 +- src/bitmap_type.h | 8 ++++ src/script/api/script_tilelist.cpp | 44 ++++++++++++++++----- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/bin/ai/regression/tst_regression/result.txt b/bin/ai/regression/tst_regression/result.txt index 58736c68b8..18ae14cb7a 100644 --- a/bin/ai/regression/tst_regression/result.txt +++ b/bin/ai/regression/tst_regression/result.txt @@ -8534,7 +8534,7 @@ ERROR: IsEnd() is invalid as Begin() is never called 19693 => 8 --TileList_IndustryProducing-- - Count(): 92 + Count(): 90 Location ListDump: 46919 => 1 46918 => 1 @@ -8626,8 +8626,6 @@ ERROR: IsEnd() is invalid as Begin() is never called 44353 => 1 44352 => 1 44351 => 1 - 46920 => 0 - 46911 => 0 --TileList_StationType-- Count(): 4 diff --git a/src/bitmap_type.h b/src/bitmap_type.h index 11a4190938..3c9c4afbdf 100644 --- a/src/bitmap_type.h +++ b/src/bitmap_type.h @@ -34,6 +34,14 @@ public: this->h = 0; } + BitmapTileArea(const TileArea &ta) + { + this->tile = ta.tile; + this->w = ta.w; + this->h = ta.h; + this->data.resize(Index(this->w, this->h)); + } + /** * Reset and clear the BitmapTileArea. */ diff --git a/src/script/api/script_tilelist.cpp b/src/script/api/script_tilelist.cpp index adddb989cc..fcee67d965 100644 --- a/src/script/api/script_tilelist.cpp +++ b/src/script/api/script_tilelist.cpp @@ -49,6 +49,32 @@ void ScriptTileList::RemoveTile(TileIndex tile) this->RemoveItem(tile); } +/** + * Helper to get list of tiles that will cover an industry's production or acceptance. + * @param i Industry in question + * @param radius Catchment radius to test + * @param bta BitmapTileArea to fill + */ +static void FillIndustryCatchment(const Industry *i, int radius, BitmapTileArea &bta) +{ + TILE_AREA_LOOP(cur_tile, i->location) { + if (!::IsTileType(cur_tile, MP_INDUSTRY) || ::GetIndustryIndex(cur_tile) != i->index) continue; + + int tx = TileX(cur_tile); + int ty = TileY(cur_tile); + for (int y = -radius; y <= radius; y++) { + if (ty + y < 0 || ty + y > (int)MapMaxY()) continue; + for (int x = -radius; x <= radius; x++) { + if (tx + x < 0 || tx + x > (int)MapMaxX()) continue; + TileIndex tile = TileXY(tx + x, ty + y); + if (!IsValidTile(tile)) continue; + if (::IsTileType(tile, MP_INDUSTRY) && ::GetIndustryIndex(tile) == i->index) continue; + bta.SetTile(tile); + } + } + } +} + ScriptTileList_IndustryAccepting::ScriptTileList_IndustryAccepting(IndustryID industry_id, int radius) { if (!ScriptIndustry::IsValidIndustry(industry_id) || radius <= 0) return; @@ -66,12 +92,11 @@ ScriptTileList_IndustryAccepting::ScriptTileList_IndustryAccepting(IndustryID in if (!_settings_game.station.modified_catchment) radius = CA_UNMODIFIED; - TileArea ta = TileArea(i->location).Expand(radius); - TILE_AREA_LOOP(cur_tile, ta) { - if (!::IsValidTile(cur_tile)) continue; - /* Exclude all tiles that belong to this industry */ - if (::IsTileType(cur_tile, MP_INDUSTRY) && ::GetIndustryIndex(cur_tile) == industry_id) continue; + BitmapTileArea bta(TileArea(i->location).Expand(radius)); + FillIndustryCatchment(i, radius, bta); + BitmapTileIterator it(bta); + for (TileIndex cur_tile = it; cur_tile != INVALID_TILE; cur_tile = ++it) { /* Only add the tile if it accepts the cargo (sometimes just 1 tile of an * industry triggers the acceptance). */ CargoArray acceptance = ::GetAcceptanceAroundTiles(cur_tile, 1, 1, radius); @@ -102,12 +127,11 @@ ScriptTileList_IndustryProducing::ScriptTileList_IndustryProducing(IndustryID in if (!_settings_game.station.modified_catchment) radius = CA_UNMODIFIED; - TileArea ta = TileArea(i->location).Expand(radius); - TILE_AREA_LOOP(cur_tile, ta) { - if (!::IsValidTile(cur_tile)) continue; - /* Exclude all tiles that belong to this industry */ - if (::IsTileType(cur_tile, MP_INDUSTRY) && ::GetIndustryIndex(cur_tile) == industry_id) continue; + BitmapTileArea bta(TileArea(i->location).Expand(radius)); + FillIndustryCatchment(i, radius, bta); + BitmapTileIterator it(bta); + for (TileIndex cur_tile = it; cur_tile != INVALID_TILE; cur_tile = ++it) { this->AddTile(cur_tile); } }