Changeset - r23618:10716e7cf9c1
[Not reviewed]
master
0 3 0
PeterN - 5 years ago 2019-04-13 13:27:57
peter@fuzzle.org
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.
3 files changed with 43 insertions and 13 deletions:
0 comments (0 inline, 0 general)
bin/ai/regression/tst_regression/result.txt
Show inline comments
 
@@ -8525,25 +8525,25 @@ ERROR: IsEnd() is invalid as Begin() is 
 
    20467 => 8
 
    20460 => 8
 
    20211 => 8
 
    20204 => 8
 
    19955 => 8
 
    19948 => 8
 
    19699 => 8
 
    19698 => 8
 
    19694 => 8
 
    19693 => 8
 

	
 
--TileList_IndustryProducing--
 
  Count():             92
 
  Count():             90
 
  Location ListDump:
 
    46919 => 1
 
    46918 => 1
 
    46917 => 1
 
    46916 => 1
 
    46915 => 1
 
    46914 => 1
 
    46913 => 1
 
    46912 => 1
 
    46664 => 1
 
    46663 => 1
 
    46662 => 1
 
@@ -8617,26 +8617,24 @@ ERROR: IsEnd() is invalid as Begin() is 
 
    44608 => 1
 
    44607 => 1
 
    44360 => 1
 
    44359 => 1
 
    44358 => 1
 
    44357 => 1
 
    44356 => 1
 
    44355 => 1
 
    44354 => 1
 
    44353 => 1
 
    44352 => 1
 
    44351 => 1
 
    46920 => 0
 
    46911 => 0
 

	
 
--TileList_StationType--
 
  Count():             4
 
  Location ListDump:
 
    33667 => 0
 
    33415 => 0
 
    33413 => 0
 
    33411 => 0
 

	
 
--Town--
 
  GetTownCount():    28
 
  Town 0
src/bitmap_type.h
Show inline comments
 
@@ -25,24 +25,32 @@ protected:
 
	inline uint Index(uint x, uint y) const { return y * this->w + x; }
 

	
 
	inline uint Index(TileIndex tile) const { return Index(TileX(tile) - TileX(this->tile), TileY(tile) - TileY(this->tile)); }
 

	
 
public:
 
	BitmapTileArea()
 
	{
 
		this->tile = INVALID_TILE;
 
		this->w = 0;
 
		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.
 
	 */
 
	void Reset()
 
	{
 
		this->tile = INVALID_TILE;
 
		this->w = 0;
 
		this->h = 0;
 
		this->data.clear();
 
	}
 

	
 
	/**
src/script/api/script_tilelist.cpp
Show inline comments
 
@@ -40,47 +40,72 @@ void ScriptTileList::RemoveRectangle(Til
 

	
 
	TileArea ta(t1, t2);
 
	TILE_AREA_LOOP(t, ta) this->RemoveItem(t);
 
}
 

	
 
void ScriptTileList::RemoveTile(TileIndex tile)
 
{
 
	if (!::IsValidTile(tile)) return;
 

	
 
	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;
 

	
 
	const Industry *i = ::Industry::Get(industry_id);
 

	
 
	/* Check if this industry accepts anything */
 
	{
 
		bool cargo_accepts = false;
 
		for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
 
			if (i->accepts_cargo[j] != CT_INVALID) cargo_accepts = true;
 
		}
 
		if (!cargo_accepts) return;
 
	}
 

	
 
	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);
 
		{
 
			bool cargo_accepts = false;
 
			for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
 
				if (i->accepts_cargo[j] != CT_INVALID && acceptance[i->accepts_cargo[j]] != 0) cargo_accepts = true;
 
			}
 
			if (!cargo_accepts) continue;
 
		}
 

	
 
		this->AddTile(cur_tile);
 
@@ -93,30 +118,29 @@ ScriptTileList_IndustryProducing::Script
 

	
 
	const Industry *i = ::Industry::Get(industry_id);
 

	
 
	/* Check if this industry produces anything */
 
	bool cargo_produces = false;
 
	for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
 
		if (i->produced_cargo[j] != CT_INVALID) cargo_produces = true;
 
	}
 
	if (!cargo_produces) return;
 

	
 
	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);
 
	}
 
}
 

	
 
ScriptTileList_StationType::ScriptTileList_StationType(StationID station_id, ScriptStation::StationType station_type)
 
{
 
	if (!ScriptStation::IsValidStation(station_id)) return;
 

	
 
	const StationRect *rect = &::Station::Get(station_id)->rect;
 

	
 
	uint station_type_value = 0;
 
	/* Convert ScriptStation::StationType to ::StationType, but do it in a
0 comments (0 inline, 0 general)