mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r23461) -Fix: handle a missing airport newgrf as graceful as possible by not crashing when loading such savegame or when an airport is removed
This commit is contained in:
parent
42c4fdf9ab
commit
c9be5d50da
|
@ -18,6 +18,7 @@
|
||||||
#include "newgrf_class.h"
|
#include "newgrf_class.h"
|
||||||
#include "newgrf_commons.h"
|
#include "newgrf_commons.h"
|
||||||
#include "gfx_type.h"
|
#include "gfx_type.h"
|
||||||
|
#include "tilearea_type.h"
|
||||||
|
|
||||||
/** Copy from station_map.h */
|
/** Copy from station_map.h */
|
||||||
typedef byte StationGfx;
|
typedef byte StationGfx;
|
||||||
|
@ -28,6 +29,39 @@ struct AirportTileTable {
|
||||||
StationGfx gfx; ///< AirportTile to use for this tile.
|
StationGfx gfx; ///< AirportTile to use for this tile.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Iterator to iterate over all tiles belonging to an airport spec. */
|
||||||
|
class AirportTileTableIterator : public TileIterator {
|
||||||
|
private:
|
||||||
|
const AirportTileTable *att; ///< The offsets.
|
||||||
|
TileIndex base_tile; ///< The tile we base the offsets off.
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Construct the iterator.
|
||||||
|
* @param att The TileTable we want to iterate over.
|
||||||
|
* @param base_tile The basetile for all offsets.
|
||||||
|
*/
|
||||||
|
AirportTileTableIterator(const AirportTileTable *att, TileIndex base_tile) : TileIterator(base_tile + ToTileIndexDiff(att->ti)), att(att), base_tile(base_tile)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE TileIterator& operator ++()
|
||||||
|
{
|
||||||
|
this->att++;
|
||||||
|
if (this->att->ti.x == -0x80) {
|
||||||
|
this->tile = INVALID_TILE;
|
||||||
|
} else {
|
||||||
|
this->tile = base_tile + ToTileIndexDiff(att->ti);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual AirportTileTableIterator *Clone() const
|
||||||
|
{
|
||||||
|
return new AirportTileTableIterator(*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** List of default airport classes. */
|
/** List of default airport classes. */
|
||||||
enum AirportClassID {
|
enum AirportClassID {
|
||||||
APC_BEGIN = 0, ///< Lowest valid airport class id
|
APC_BEGIN = 0, ///< Lowest valid airport class id
|
||||||
|
|
|
@ -127,16 +127,17 @@
|
||||||
|
|
||||||
/* static */ int ScriptAirport::GetNoiseLevelIncrease(TileIndex tile, AirportType type)
|
/* static */ int ScriptAirport::GetNoiseLevelIncrease(TileIndex tile, AirportType type)
|
||||||
{
|
{
|
||||||
extern Town *AirportGetNearestTown(const AirportSpec *as, byte layout, TileIndex airport_tile);
|
extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it);
|
||||||
extern uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, byte layout, TileIndex town_tile, TileIndex tile);
|
extern uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIterator &it, TileIndex town_tile);
|
||||||
|
|
||||||
if (!::IsValidTile(tile)) return -1;
|
if (!::IsValidTile(tile)) return -1;
|
||||||
if (!IsAirportInformationAvailable(type)) return -1;
|
if (!IsAirportInformationAvailable(type)) return -1;
|
||||||
|
|
||||||
if (_settings_game.economy.station_noise_level) {
|
if (_settings_game.economy.station_noise_level) {
|
||||||
const AirportSpec *as = ::AirportSpec::Get(type);
|
const AirportSpec *as = ::AirportSpec::Get(type);
|
||||||
const Town *t = AirportGetNearestTown(as, 0, tile);
|
AirportTileTableIterator it(as->table[0], tile);
|
||||||
return GetAirportNoiseLevelForTown(as, 0, t->xy, tile);
|
const Town *t = AirportGetNearestTown(as, it);
|
||||||
|
return GetAirportNoiseLevelForTown(as, it, t->xy);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -144,12 +145,13 @@
|
||||||
|
|
||||||
/* static */ TownID ScriptAirport::GetNearestTown(TileIndex tile, AirportType type)
|
/* static */ TownID ScriptAirport::GetNearestTown(TileIndex tile, AirportType type)
|
||||||
{
|
{
|
||||||
extern Town *AirportGetNearestTown(const AirportSpec *as, byte layout, TileIndex airport_tile);
|
extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it);
|
||||||
|
|
||||||
if (!::IsValidTile(tile)) return INVALID_TOWN;
|
if (!::IsValidTile(tile)) return INVALID_TOWN;
|
||||||
if (!IsAirportInformationAvailable(type)) return INVALID_TOWN;
|
if (!IsAirportInformationAvailable(type)) return INVALID_TOWN;
|
||||||
|
|
||||||
return AirportGetNearestTown(AirportSpec::Get(type), 0, tile)->index;
|
const AirportSpec *as = AirportSpec::Get(type);
|
||||||
|
return AirportGetNearestTown(as, AirportTileTableIterator(as->table[0], tile))->index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ uint16 ScriptAirport::GetMaintenanceCostFactor(AirportType type)
|
/* static */ uint16 ScriptAirport::GetMaintenanceCostFactor(AirportType type)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "cargopacket.h"
|
#include "cargopacket.h"
|
||||||
#include "industry_type.h"
|
#include "industry_type.h"
|
||||||
#include "newgrf_storage.h"
|
#include "newgrf_storage.h"
|
||||||
|
#include "town.h"
|
||||||
|
|
||||||
typedef Pool<BaseStation, StationID, 32, 64000> StationPool;
|
typedef Pool<BaseStation, StationID, 32, 64000> StationPool;
|
||||||
extern StationPool _station_pool;
|
extern StationPool _station_pool;
|
||||||
|
@ -261,4 +262,34 @@ public:
|
||||||
|
|
||||||
#define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
|
#define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
|
||||||
|
|
||||||
|
/** Iterator to iterate over all tiles belonging to an airport. */
|
||||||
|
class AirportTileIterator : public OrthogonalTileIterator {
|
||||||
|
private:
|
||||||
|
const Station *st; ///< The station the airport is a part of.
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Construct the iterator.
|
||||||
|
* @param ta Area, i.e. begin point and width/height of to-be-iterated area.
|
||||||
|
*/
|
||||||
|
AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st)
|
||||||
|
{
|
||||||
|
if (!st->TileBelongsToAirport(this->tile)) ++(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE TileIterator& operator ++()
|
||||||
|
{
|
||||||
|
(*this).OrthogonalTileIterator::operator++();
|
||||||
|
while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
|
||||||
|
(*this).OrthogonalTileIterator::operator++();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual TileIterator *Clone() const
|
||||||
|
{
|
||||||
|
return new AirportTileIterator(*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* STATION_BASE_H */
|
#endif /* STATION_BASE_H */
|
||||||
|
|
|
@ -2019,24 +2019,17 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the minimal distance from town's xy to any airport's tile.
|
* Computes the minimal distance from town's xy to any airport's tile.
|
||||||
* @param as airport's description
|
* @param it An iterator over all airport tiles.
|
||||||
* @param town_tile town's tile (t->xy)
|
* @param town_tile town's tile (t->xy)
|
||||||
* @param airport_tile st->airport.tile
|
|
||||||
* @return minimal manhattan distance from town_tile to any airport's tile
|
* @return minimal manhattan distance from town_tile to any airport's tile
|
||||||
*/
|
*/
|
||||||
static uint GetMinimalAirportDistanceToTile(const AirportSpec *as, byte layout, TileIndex town_tile, TileIndex airport_tile)
|
static uint GetMinimalAirportDistanceToTile(TileIterator &it, TileIndex town_tile)
|
||||||
{
|
{
|
||||||
uint mindist = UINT_MAX;
|
uint mindist = UINT_MAX;
|
||||||
|
|
||||||
const AirportTileTable *it = as->table[layout];
|
for (TileIndex cur_tile = it; cur_tile != INVALID_TILE; cur_tile = ++it) {
|
||||||
do {
|
mindist = min(mindist, DistanceManhattan(town_tile, cur_tile));
|
||||||
TileIndex cur_tile = airport_tile + ToTileIndexDiff(it->ti);
|
}
|
||||||
|
|
||||||
uint dist = DistanceManhattan(town_tile, cur_tile);
|
|
||||||
if (dist < mindist) {
|
|
||||||
mindist = dist;
|
|
||||||
}
|
|
||||||
} while ((++it)->ti.x != -0x80);
|
|
||||||
|
|
||||||
return mindist;
|
return mindist;
|
||||||
}
|
}
|
||||||
|
@ -2046,18 +2039,17 @@ static uint GetMinimalAirportDistanceToTile(const AirportSpec *as, byte layout,
|
||||||
* The further you get, the less noise you generate.
|
* The further you get, the less noise you generate.
|
||||||
* So all those folks at city council can now happily slee... work in their offices
|
* So all those folks at city council can now happily slee... work in their offices
|
||||||
* @param as airport information
|
* @param as airport information
|
||||||
|
* @param it An iterator over all airport tiles.
|
||||||
* @param town_tile TileIndex of town's center, the one who will receive the airport's candidature
|
* @param town_tile TileIndex of town's center, the one who will receive the airport's candidature
|
||||||
* @param tile TileIndex of northern tile of an airport (present or to-be-built), NOT the station tile
|
|
||||||
* @return the noise that will be generated, according to distance
|
* @return the noise that will be generated, according to distance
|
||||||
*/
|
*/
|
||||||
uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, byte layout, TileIndex town_tile, TileIndex tile)
|
uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIterator &it, TileIndex town_tile)
|
||||||
{
|
{
|
||||||
/* 0 cannot be accounted, and 1 is the lowest that can be reduced from town.
|
/* 0 cannot be accounted, and 1 is the lowest that can be reduced from town.
|
||||||
* So no need to go any further*/
|
* So no need to go any further*/
|
||||||
if (as->noise_level < 2) return as->noise_level;
|
if (as->noise_level < 2) return as->noise_level;
|
||||||
|
|
||||||
assert(layout < as->num_table);
|
uint distance = GetMinimalAirportDistanceToTile(it, town_tile);
|
||||||
uint distance = GetMinimalAirportDistanceToTile(as, layout, town_tile, tile);
|
|
||||||
|
|
||||||
/* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance
|
/* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance
|
||||||
* adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance.
|
* adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance.
|
||||||
|
@ -2078,19 +2070,19 @@ uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, byte layout, TileIndex
|
||||||
* Finds the town nearest to given airport. Based on minimal manhattan distance to any airport's tile.
|
* Finds the town nearest to given airport. Based on minimal manhattan distance to any airport's tile.
|
||||||
* If two towns have the same distance, town with lower index is returned.
|
* If two towns have the same distance, town with lower index is returned.
|
||||||
* @param as airport's description
|
* @param as airport's description
|
||||||
* @param airport_tile st->airport.tile
|
* @param it An iterator over all airport tiles
|
||||||
* @return nearest town to airport
|
* @return nearest town to airport
|
||||||
*/
|
*/
|
||||||
Town *AirportGetNearestTown(const AirportSpec *as, byte layout, TileIndex airport_tile)
|
Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it)
|
||||||
{
|
{
|
||||||
assert(layout < as->num_table);
|
|
||||||
|
|
||||||
Town *t, *nearest = NULL;
|
Town *t, *nearest = NULL;
|
||||||
uint add = as->size_x + as->size_y - 2; // GetMinimalAirportDistanceToTile can differ from DistanceManhattan by this much
|
uint add = as->size_x + as->size_y - 2; // GetMinimalAirportDistanceToTile can differ from DistanceManhattan by this much
|
||||||
uint mindist = UINT_MAX - add; // prevent overflow
|
uint mindist = UINT_MAX - add; // prevent overflow
|
||||||
FOR_ALL_TOWNS(t) {
|
FOR_ALL_TOWNS(t) {
|
||||||
if (DistanceManhattan(t->xy, airport_tile) < mindist + add) { // avoid calling GetMinimalAirportDistanceToTile too often
|
if (DistanceManhattan(t->xy, it) < mindist + add) { // avoid calling GetMinimalAirportDistanceToTile too often
|
||||||
uint dist = GetMinimalAirportDistanceToTile(as, layout, t->xy, airport_tile);
|
TileIterator *copy = it.Clone();
|
||||||
|
uint dist = GetMinimalAirportDistanceToTile(*copy, t->xy);
|
||||||
|
delete copy;
|
||||||
if (dist < mindist) {
|
if (dist < mindist) {
|
||||||
nearest = t;
|
nearest = t;
|
||||||
mindist = dist;
|
mindist = dist;
|
||||||
|
@ -2113,8 +2105,9 @@ void UpdateAirportsNoise()
|
||||||
FOR_ALL_STATIONS(st) {
|
FOR_ALL_STATIONS(st) {
|
||||||
if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) {
|
if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) {
|
||||||
const AirportSpec *as = st->airport.GetSpec();
|
const AirportSpec *as = st->airport.GetSpec();
|
||||||
Town *nearest = AirportGetNearestTown(as, st->airport.layout, st->airport.tile);
|
AirportTileIterator it(st);
|
||||||
nearest->noise_reached += GetAirportNoiseLevelForTown(as, st->airport.layout, nearest->xy, st->airport.tile);
|
Town *nearest = AirportGetNearestTown(as, it);
|
||||||
|
nearest->noise_reached += GetAirportNoiseLevelForTown(as, it, nearest->xy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2166,8 +2159,9 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
||||||
if (cost.Failed()) return cost;
|
if (cost.Failed()) return cost;
|
||||||
|
|
||||||
/* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
|
/* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
|
||||||
Town *nearest = AirportGetNearestTown(as, layout, tile);
|
AirportTileTableIterator iter(as->table[layout], tile);
|
||||||
uint newnoise_level = GetAirportNoiseLevelForTown(as, layout, nearest->xy, tile);
|
Town *nearest = AirportGetNearestTown(as, iter);
|
||||||
|
uint newnoise_level = GetAirportNoiseLevelForTown(as, iter, nearest->xy);
|
||||||
|
|
||||||
/* Check if local auth would allow a new airport */
|
/* Check if local auth would allow a new airport */
|
||||||
StringID authority_refuse_message = STR_NULL;
|
StringID authority_refuse_message = STR_NULL;
|
||||||
|
@ -2309,6 +2303,16 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
|
||||||
if (a->targetairport == st->index && a->state != FLYING) return CMD_ERROR;
|
if (a->targetairport == st->index && a->state != FLYING) return CMD_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
const AirportSpec *as = st->airport.GetSpec();
|
||||||
|
/* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
|
||||||
|
* And as for construction, always remove it, even if the setting is not set, in order to avoid the
|
||||||
|
* need of recalculation */
|
||||||
|
AirportTileIterator it(st);
|
||||||
|
Town *nearest = AirportGetNearestTown(as, it);
|
||||||
|
nearest->noise_reached -= GetAirportNoiseLevelForTown(as, it, nearest->xy);
|
||||||
|
}
|
||||||
|
|
||||||
TILE_AREA_LOOP(tile_cur, st->airport) {
|
TILE_AREA_LOOP(tile_cur, st->airport) {
|
||||||
if (!st->TileBelongsToAirport(tile_cur)) continue;
|
if (!st->TileBelongsToAirport(tile_cur)) continue;
|
||||||
|
|
||||||
|
@ -2336,12 +2340,6 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
|
|
||||||
* And as for construction, always remove it, even if the setting is not set, in order to avoid the
|
|
||||||
* need of recalculation */
|
|
||||||
Town *nearest = AirportGetNearestTown(as, st->airport.layout, tile);
|
|
||||||
nearest->noise_reached -= GetAirportNoiseLevelForTown(as, st->airport.layout, nearest->xy, tile);
|
|
||||||
|
|
||||||
st->rect.AfterRemoveRect(st, st->airport);
|
st->rect.AfterRemoveRect(st, st->airport);
|
||||||
|
|
||||||
st->airport.Clear();
|
st->airport.Clear();
|
||||||
|
|
|
@ -94,6 +94,11 @@ public:
|
||||||
* Move ourselves to the next tile in the rectange on the map.
|
* Move ourselves to the next tile in the rectange on the map.
|
||||||
*/
|
*/
|
||||||
virtual TileIterator& operator ++() = 0;
|
virtual TileIterator& operator ++() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a new iterator that is a copy of this one.
|
||||||
|
*/
|
||||||
|
virtual TileIterator *Clone() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Iterator to iterate over a tile area (rectangle) of the map. */
|
/** Iterator to iterate over a tile area (rectangle) of the map. */
|
||||||
|
@ -129,6 +134,11 @@ public:
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual TileIterator *Clone() const
|
||||||
|
{
|
||||||
|
return new OrthogonalTileIterator(*this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Iterator to iterate over a diagonal area of the map. */
|
/** Iterator to iterate over a diagonal area of the map. */
|
||||||
|
@ -145,6 +155,11 @@ public:
|
||||||
DiagonalTileIterator(TileIndex begin, TileIndex end);
|
DiagonalTileIterator(TileIndex begin, TileIndex end);
|
||||||
|
|
||||||
TileIterator& operator ++();
|
TileIterator& operator ++();
|
||||||
|
|
||||||
|
virtual TileIterator *Clone() const
|
||||||
|
{
|
||||||
|
return new DiagonalTileIterator(*this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue