/** * Check and update town and house values. * * Checked are the HouseIDs. Updated are the * town population the number of houses per * town, the town radius and the max passengers * of the town. */ void UpdateHousesAndTowns() { for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_id = GetCleanHouseType(t); if (!HouseSpec::Get(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) { /* The specs for this type of house are not available any more, so * replace it with the substitute original house type. */ house_id = _house_mngr.GetSubstituteID(house_id); SetHouseType(t, house_id); } } /* Check for cases when a NewGRF has set a wrong house substitute type. */ for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_type = GetCleanHouseType(t); TileIndex north_tile = t + GetHouseNorthPart(house_type); // modifies 'house_type'! if (t == north_tile) { const HouseSpec *hs = HouseSpec::Get(house_type); bool valid_house = true; if (hs->building_flags & TILE_SIZE_2x1) { TileIndex tile = t + TileDiffXY(1, 0); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; } else if (hs->building_flags & TILE_SIZE_1x2) { TileIndex tile = t + TileDiffXY(0, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; } else if (hs->building_flags & TILE_SIZE_2x2) { TileIndex tile = t + TileDiffXY(0, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; tile = t + TileDiffXY(1, 0); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 2) valid_house = false; tile = t + TileDiffXY(1, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 3) valid_house = false; } /* If not all tiles of this house are present remove the house. * The other tiles will get removed later in this loop because * their north tile is not the correct type anymore. */ if (!valid_house) DoClearSquare(t); } else if (!IsTileType(north_tile, MP_HOUSE) || GetCleanHouseType(north_tile) != house_type) { /* This tile should be part of a multi-tile building but the * north tile of this house isn't on the map. */ DoClearSquare(t); } } RebuildTownCaches(); }
static void DisasterClearSquare(TileIndex tile) { if (EnsureNoVehicleOnGround(tile).Failed()) return; switch (GetTileType(tile)) { case MP_RAILWAY: if (Company::IsHumanID(GetTileOwner(tile))) { Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE); DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); /* update signals in buffer */ UpdateSignalsInBuffer(); } break; case MP_HOUSE: { Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE); DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); break; } case MP_TREES: case MP_CLEAR: DoClearSquare(tile); break; default: break; } }
static void DisasterClearSquare(TileIndex tile) { if (!EnsureNoVehicleOnGround(tile)) return; switch (GetTileType(tile)) { case MP_RAILWAY: if (Company::IsHumanID(GetTileOwner(tile))) { CompanyID old_company = _current_company; _current_company = OWNER_WATER; DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); _current_company = old_company; /* update signals in buffer */ UpdateSignalsInBuffer(); } break; case MP_HOUSE: { CompanyID old_company = _current_company; _current_company = OWNER_NONE; DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); _current_company = old_company; break; } case MP_TREES: case MP_CLEAR: DoClearSquare(tile); break; default: break; } }
/** * Remove a lock. * @param tile Central tile of the lock. * @param flags Operation to perform. * @return The cost in case of success, or an error code if it failed. */ static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags) { if (GetTileOwner(tile) != OWNER_NONE) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile)); /* make sure no vehicle is on the tile. */ CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta); if (ret.Failed()) return ret; if (flags & DC_EXEC) { DoClearSquare(tile); MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta)); MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta)); MarkCanalsAndRiversAroundDirty(tile - delta); MarkCanalsAndRiversAroundDirty(tile + delta); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]); }
void MakeWaterKeepingClass(TileIndex tile, Owner o) { WaterClass wc = GetWaterClass(tile); /* Autoslope might turn an originally canal or river tile into land */ int z; Slope slope = GetTileSlope(tile, &z); if (slope != SLOPE_FLAT) { if (wc == WATER_CLASS_CANAL) { /* If we clear the canal, we have to remove it from the infrastructure count as well. */ Company *c = Company::GetIfValid(o); if (c != NULL) { c->infrastructure.water--; DirtyCompanyInfrastructureWindows(c->index); } /* Sloped canals are locks and no natural water remains whatever the slope direction */ wc = WATER_CLASS_INVALID; } /* Only river water should be restored on appropriate slopes. Other water would be invalid on slopes */ if (wc != WATER_CLASS_RIVER || GetInclinedSlopeDirection(slope) == INVALID_DIAGDIR) { wc = WATER_CLASS_INVALID; } } if (wc == WATER_CLASS_SEA && z > 0) { /* Update company infrastructure count. */ Company *c = Company::GetIfValid(o); if (c != NULL) { c->infrastructure.water++; DirtyCompanyInfrastructureWindows(c->index); } wc = WATER_CLASS_CANAL; } /* Zero map array and terminate animation */ DoClearSquare(tile); /* Maybe change to water */ switch (wc) { case WATER_CLASS_SEA: MakeSea(tile); break; case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break; case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break; default: break; } MarkTileDirtyByTile(tile); }
static CommandCost ClearTile_Trees(TileIndex tile, DoCommandFlag flags) { uint num; if (Company::IsValidID(_current_company)) { Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); if (t != NULL) ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM, flags); } num = GetTreeCount(tile); if (IsInsideMM(GetTreeType(tile), TREE_RAINFOREST, TREE_CACTUS)) num *= 4; if (flags & DC_EXEC) DoClearSquare(tile); return CommandCost(EXPENSES_CONSTRUCTION, num * _price[PR_CLEAR_TREES]); }
void MakeWaterKeepingClass(TileIndex tile, Owner o) { assert(IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_STATION) && (IsBuoy(tile) || IsDock(tile) || IsOilRig(tile))) || IsTileType(tile, MP_INDUSTRY)); WaterClass wc = GetWaterClass(tile); /* Autoslope might turn an originally canal or river tile into land */ uint z; if (GetTileSlope(tile, &z) != SLOPE_FLAT) wc = WATER_CLASS_INVALID; if (wc == WATER_CLASS_SEA && z > 0) wc = WATER_CLASS_CANAL; switch (wc) { case WATER_CLASS_SEA: MakeSea(tile); break; case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break; case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break; default: DoClearSquare(tile); break; } }
static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlag flags) { static const Price clear_price_table[] = { PR_CLEAR_GRASS, PR_CLEAR_ROUGH, PR_CLEAR_ROCKS, PR_CLEAR_FIELDS, PR_CLEAR_ROUGH, PR_CLEAR_ROUGH, }; CommandCost price(EXPENSES_CONSTRUCTION); if (!IsClearGround(tile, CLEAR_GRASS) || GetClearDensity(tile) != 0) { price.AddCost(_price[clear_price_table[GetClearGround(tile)]]); } if (flags & DC_EXEC) DoClearSquare(tile); return price; }
static CommandCost RemoveShiplift(TileIndex tile, DoCommandFlag flags) { TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile)); if (!CheckTileOwnership(tile) && GetTileOwner(tile) != OWNER_NONE) return CMD_ERROR; /* make sure no vehicle is on the tile. */ if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile + delta) || !EnsureNoVehicleOnGround(tile - delta)) return CMD_ERROR; if (flags & DC_EXEC) { DoClearSquare(tile); MakeWaterKeepingClass(tile + delta, GetTileOwner(tile)); MakeWaterKeepingClass(tile - delta, GetTileOwner(tile)); MarkTileDirtyByTile(tile - delta); MarkTileDirtyByTile(tile + delta); MarkCanalsAndRiversAroundDirty(tile - delta); MarkCanalsAndRiversAroundDirty(tile + delta); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER] * 2); }
void MakeWaterKeepingClass(TileIndex tile, Owner o) { WaterClass wc = GetWaterClass(tile); /* Autoslope might turn an originally canal or river tile into land */ uint z; if (GetTileSlope(tile, &z) != SLOPE_FLAT) wc = WATER_CLASS_INVALID; if (wc == WATER_CLASS_SEA && z > 0) wc = WATER_CLASS_CANAL; /* Zero map array and terminate animation */ DoClearSquare(tile); /* Maybe change to water */ switch (wc) { case WATER_CLASS_SEA: MakeSea(tile); break; case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break; case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break; default: break; } MarkTileDirtyByTile(tile); }
/** * Remove a lock. * @param tile Central tile of the lock. * @param flags Operation to perform. * @return The cost in case of success, or an error code if it failed. */ static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags) { if (GetTileOwner(tile) != OWNER_NONE) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile)); /* make sure no vehicle is on the tile. */ CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta); if (ret.Failed()) return ret; if (flags & DC_EXEC) { /* Remove middle part from company infrastructure count. */ Company *c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) { c->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // three parts of the lock. DirtyCompanyInfrastructureWindows(c->index); } if (GetWaterClass(tile) == WATER_CLASS_RIVER) { MakeRiver(tile, Random()); } else { DoClearSquare(tile); } MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta)); MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta)); MarkCanalsAndRiversAroundDirty(tile); MarkCanalsAndRiversAroundDirty(tile - delta); MarkCanalsAndRiversAroundDirty(tile + delta); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]); }
/** * Prepare for removal of this stop; update other neighbouring stops * if needed. Also update the length etc. */ void RoadStop::ClearDriveThrough() { assert(this->east != NULL && this->west != NULL); RoadStopType rst = GetRoadStopType(this->xy); DiagDirection dir = GetRoadStopDir(this->xy); /* Use absolute so we always go towards the nortern tile */ TileIndexDiff offset = abs(TileOffsByDiagDir(dir)); /* Information about the tile north of us */ TileIndex north_tile = this->xy - offset; bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile); RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL; /* Information about the tile south of us */ TileIndex south_tile = this->xy + offset; bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile); RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL; /* Must only be cleared after we determined which neighbours are * part of our little entry 'queue' */ DoClearSquare(this->xy); if (north) { /* There is a tile to the north, so we can't clear ourselves. */ if (south) { /* There are more southern tiles too, they must be split; * first make the new southern 'base' */ SetBit(rs_south->status, RSSFB_BASE_ENTRY); rs_south->east = new Entry(); rs_south->west = new Entry(); /* Keep track of the base because we need it later on */ RoadStop *rs_south_base = rs_south; TileIndex base_tile = south_tile; /* Make all (even more) southern stops part of the new entry queue */ for (south_tile += offset; IsDriveThroughRoadStopContinuation(base_tile, south_tile); south_tile += offset) { rs_south = RoadStop::GetByTile(south_tile, rst); rs_south->east = rs_south_base->east; rs_south->west = rs_south_base->west; } /* Find the other end; the northern most tile */ for (; IsDriveThroughRoadStopContinuation(base_tile, north_tile); north_tile -= offset) { rs_north = RoadStop::GetByTile(north_tile, rst); } /* We have to rebuild the entries because we cannot easily determine * how full each part is. So instead of keeping and maintaining a list * of vehicles and using that to 'rebuild' the occupied state we just * rebuild it from scratch as that removes lots of maintainance code * for the vehicle list and it's faster in real games as long as you * do not keep split and merge road stop every tick by the millions. */ rs_south_base->east->Rebuild(rs_south_base); rs_south_base->west->Rebuild(rs_south_base); assert(HasBit(rs_north->status, RSSFB_BASE_ENTRY)); rs_north->east->Rebuild(rs_north); rs_north->west->Rebuild(rs_north); } else { /* Only we left, so simple update the length. */ rs_north->east->length -= TILE_SIZE; rs_north->west->length -= TILE_SIZE; } } else if (south) { /* There is only something to the south. Hand over the base entry */ SetBit(rs_south->status, RSSFB_BASE_ENTRY); rs_south->east->length -= TILE_SIZE; rs_south->west->length -= TILE_SIZE; } else { /* We were the last */ delete this->east; delete this->west; } /* Make sure we don't get used for something 'incorrect' */ ClrBit(this->status, RSSFB_BASE_ENTRY); this->east = NULL; this->west = NULL; }
/** * Check and update town and house values. * * Checked are the HouseIDs. Updated are the * town population the number of houses per * town, the town radius and the max passengers * of the town. */ void UpdateHousesAndTowns() { Town *town; InitializeBuildingCounts(); /* Reset town population and num_houses */ FOR_ALL_TOWNS(town) { town->population = 0; town->num_houses = 0; } for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_id = GetCleanHouseType(t); if (!HouseSpec::Get(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) { /* The specs for this type of house are not available any more, so * replace it with the substitute original house type. */ house_id = _house_mngr.GetSubstituteID(house_id); SetHouseType(t, house_id); } } /* Check for cases when a NewGRF has set a wrong house substitute type. */ for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_type = GetCleanHouseType(t); TileIndex north_tile = t + GetHouseNorthPart(house_type); // modifies 'house_type'! if (t == north_tile) { const HouseSpec *hs = HouseSpec::Get(house_type); bool valid_house = true; if (hs->building_flags & TILE_SIZE_2x1) { TileIndex tile = t + TileDiffXY(1, 0); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; } else if (hs->building_flags & TILE_SIZE_1x2) { TileIndex tile = t + TileDiffXY(0, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; } else if (hs->building_flags & TILE_SIZE_2x2) { TileIndex tile = t + TileDiffXY(0, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; tile = t + TileDiffXY(1, 0); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 2) valid_house = false; tile = t + TileDiffXY(1, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 3) valid_house = false; } /* If not all tiles of this house are present remove the house. * The other tiles will get removed later in this loop because * their north tile is not the correct type anymore. */ if (!valid_house) DoClearSquare(t); } else if (!IsTileType(north_tile, MP_HOUSE) || GetCleanHouseType(north_tile) != house_type) { /* This tile should be part of a multi-tile building but the * north tile of this house isn't on the map. */ DoClearSquare(t); } } for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_id = GetCleanHouseType(t); town = Town::GetByTile(t); IncreaseBuildingCount(town, house_id); if (IsHouseCompleted(t)) town->population += HouseSpec::Get(house_id)->population; /* Increase the number of houses for every house, but only once. */ if (GetHouseNorthPart(house_id) == 0) town->num_houses++; } /* Update the population and num_house dependant values */ FOR_ALL_TOWNS(town) { UpdateTownRadius(town); UpdateTownCargos(town); } }