From a40ad243cad15733f65e40d5a49dc0b6e7aa68f2 Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 13 May 2013 19:18:10 +0000 Subject: [PATCH] (svn r25240) [1.3] -Backport from trunk: - Fix: [NewGRF] Make tick_counters work the same for vehicles (r25223, r25222) - Fix: [NewGRF] IsCompatibleTrainStationTile() is not a symmetric function. Clarify the parameters and fix the cases were they were swapped (r25221) - Fix: Consider map border as water with repsect to river/canal continuation (r25220) - Fix: [Script] Clarify on which tiles IsDesertTile and IsSnowTile work, i.e. the ones without infrastructure or buildings, and introduce GetTerrainType for the cases where IsDesertTile/IsSnowTile do not work [FS#5537] (r25213) - Fix: The baseset description translation script did not work with any awk other than gawk (r25218) --- media/baseset/translations.awk | 27 ++++++++++++++++-- src/aircraft_cmd.cpp | 17 +++++++---- src/newgrf_station.cpp | 4 +-- src/roadveh_cmd.cpp | 3 +- src/script/api/ai/ai_tile.hpp.sq | 5 ++++ src/script/api/ai_changelog.hpp | 5 ++++ src/script/api/game/game_tile.hpp.sq | 5 ++++ src/script/api/game_changelog.hpp | 5 ++++ src/script/api/script_tile.cpp | 13 +++++++++ src/script/api/script_tile.hpp | 29 +++++++++++++++++-- src/script/api/template/template_tile.hpp.sq | 2 ++ src/station_map.h | 30 ++++++++++---------- src/water_cmd.cpp | 2 ++ 13 files changed, 119 insertions(+), 28 deletions(-) diff --git a/media/baseset/translations.awk b/media/baseset/translations.awk index 3269d40b74..f15cb43ffe 100644 --- a/media/baseset/translations.awk +++ b/media/baseset/translations.awk @@ -18,6 +18,26 @@ # . = # +# Simple insertion sort since not all AWKs have a sort implementation +function isort(A) { + n = 0 + for (val in A) { + n++; + } + + for (i = 2; i <= n; i++) { + j = i; + hold = A[j] + while (A[j - 1] > hold) { + j--; + A[j + 1] = A[j] + } + A[j] = hold + } + + return n +} + /^!!/ { ini_key = $2; str_id = $3; @@ -28,16 +48,17 @@ lang = $2; } else if (match($0, "^" str_id " *:") > 0) { sub("^[^:]*:", "", $0) + i++; if (lang == "en_GB") { - texts[""] = ini_key " = "$0; + texts[i] = ini_key " = "$0; } else { - texts[lang] = ini_key "." lang " = "$0; + texts[i] = ini_key "." lang " = "$0; } } } close(file); - count = asort(texts); + count = isort(texts); for (i = 1; i <= count; i++) { print texts[i] } diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index deec94649d..f4bf03e9a8 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -1066,7 +1066,12 @@ static bool HandleCrashedAircraft(Aircraft *v) } -static void HandleAircraftSmoke(Aircraft *v) +/** + * Handle smoke of broken aircraft. + * @param v Aircraft + * @param mode Is this the non-first call for this vehicle in this tick? + */ +static void HandleAircraftSmoke(Aircraft *v, bool mode) { static const struct { int8 x; @@ -1084,13 +1089,15 @@ static void HandleAircraftSmoke(Aircraft *v) if (!(v->vehstatus & VS_AIRCRAFT_BROKEN)) return; + /* Stop smoking when landed */ if (v->cur_speed < 10) { v->vehstatus &= ~VS_AIRCRAFT_BROKEN; v->breakdown_ctr = 0; return; } - if ((v->tick_counter & 0x1F) == 0) { + /* Spawn effect et most once per Tick, i.e. !mode */ + if (!mode && (v->tick_counter & 0x0F) == 0) { CreateEffectVehicleRel(v, smoke_pos[v->direction].x, smoke_pos[v->direction].y, @@ -1893,8 +1900,6 @@ static void AircraftHandleDestTooFar(Aircraft *v, bool too_far) static bool AircraftEventHandler(Aircraft *v, int loop) { - v->tick_counter++; - if (v->vehstatus & VS_CRASHED) { return HandleCrashedAircraft(v); } @@ -1903,7 +1908,7 @@ static bool AircraftEventHandler(Aircraft *v, int loop) v->HandleBreakdown(); - HandleAircraftSmoke(v); + HandleAircraftSmoke(v, loop != 0); ProcessOrders(v); v->HandleLoading(loop != 0); @@ -1933,6 +1938,8 @@ bool Aircraft::Tick() { if (!this->IsNormalAircraft()) return true; + this->tick_counter++; + if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; if (this->subtype == AIR_HELICOPTER) HelicopterTickHandler(this); diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index 717c866f5d..6a0bb3a327 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -73,8 +73,8 @@ struct ETileArea : TileArea { Axis axis = GetRailStationAxis(tile); TileIndexDiff delta = TileOffsByDiagDir(AxisToDiagDir(axis)); - for (end = tile; IsRailStationTile(end + delta) && IsCompatibleTrainStationTile(tile, end + delta); end += delta) { /* Nothing */ } - for (start = tile; IsRailStationTile(start - delta) && IsCompatibleTrainStationTile(tile, start - delta); start -= delta) { /* Nothing */ } + for (end = tile; IsRailStationTile(end + delta) && IsCompatibleTrainStationTile(end + delta, tile); end += delta) { /* Nothing */ } + for (start = tile; IsRailStationTile(start - delta) && IsCompatibleTrainStationTile(start - delta, tile); start -= delta) { /* Nothing */ } this->tile = start; this->w = TileX(end) - TileX(start) + 1; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index bba108d4c6..4cfd5699a2 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -1501,7 +1501,6 @@ again: static bool RoadVehController(RoadVehicle *v) { /* decrease counters */ - v->tick_counter++; v->current_order_time++; if (v->reverse_ctr != 0) v->reverse_ctr--; @@ -1576,6 +1575,8 @@ Money RoadVehicle::GetRunningCost() const bool RoadVehicle::Tick() { + this->tick_counter++; + if (this->IsFrontEngine()) { if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; return RoadVehController(this); diff --git a/src/script/api/ai/ai_tile.hpp.sq b/src/script/api/ai/ai_tile.hpp.sq index 44d5e326c1..570e88cd28 100644 --- a/src/script/api/ai/ai_tile.hpp.sq +++ b/src/script/api/ai/ai_tile.hpp.sq @@ -66,6 +66,10 @@ void SQAITile_Register(Squirrel *engine) SQAITile.DefSQConst(engine, ScriptTile::BT_CLEAR_ROCKY, "BT_CLEAR_ROCKY"); SQAITile.DefSQConst(engine, ScriptTile::BT_CLEAR_FIELDS, "BT_CLEAR_FIELDS"); SQAITile.DefSQConst(engine, ScriptTile::BT_CLEAR_HOUSE, "BT_CLEAR_HOUSE"); + SQAITile.DefSQConst(engine, ScriptTile::TERRAIN_NORMAL, "TERRAIN_NORMAL"); + SQAITile.DefSQConst(engine, ScriptTile::TERRAIN_DESERT, "TERRAIN_DESERT"); + SQAITile.DefSQConst(engine, ScriptTile::TERRAIN_RAINFOREST, "TERRAIN_RAINFOREST"); + SQAITile.DefSQConst(engine, ScriptTile::TERRAIN_SNOW, "TERRAIN_SNOW"); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_AT_SEA_LEVEL, ScriptTile::ERR_TILE_TOO_HIGH); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_AT_SEA_LEVEL, ScriptTile::ERR_TILE_TOO_LOW); @@ -90,6 +94,7 @@ void SQAITile_Register(Squirrel *engine) SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsRoughTile, "IsRoughTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsSnowTile, "IsSnowTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsDesertTile, "IsDesertTile", 2, ".i"); + SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetTerrainType, "GetTerrainType", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetSlope, "GetSlope", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetComplementSlope, "GetComplementSlope", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetMinHeight, "GetMinHeight", 2, ".i"); diff --git a/src/script/api/ai_changelog.hpp b/src/script/api/ai_changelog.hpp index b2d2510c86..e694d7db4e 100644 --- a/src/script/api/ai_changelog.hpp +++ b/src/script/api/ai_changelog.hpp @@ -15,6 +15,11 @@ * functions may still be available if you return an older API version * in GetAPIVersion() in info.nut. * + * \b 1.3.1 + * + * API additions: + * \li AITile::GetTerrainType + * * \b 1.3.0 * * API additions: diff --git a/src/script/api/game/game_tile.hpp.sq b/src/script/api/game/game_tile.hpp.sq index c2d5cb55e5..6224919ffb 100644 --- a/src/script/api/game/game_tile.hpp.sq +++ b/src/script/api/game/game_tile.hpp.sq @@ -66,6 +66,10 @@ void SQGSTile_Register(Squirrel *engine) SQGSTile.DefSQConst(engine, ScriptTile::BT_CLEAR_ROCKY, "BT_CLEAR_ROCKY"); SQGSTile.DefSQConst(engine, ScriptTile::BT_CLEAR_FIELDS, "BT_CLEAR_FIELDS"); SQGSTile.DefSQConst(engine, ScriptTile::BT_CLEAR_HOUSE, "BT_CLEAR_HOUSE"); + SQGSTile.DefSQConst(engine, ScriptTile::TERRAIN_NORMAL, "TERRAIN_NORMAL"); + SQGSTile.DefSQConst(engine, ScriptTile::TERRAIN_DESERT, "TERRAIN_DESERT"); + SQGSTile.DefSQConst(engine, ScriptTile::TERRAIN_RAINFOREST, "TERRAIN_RAINFOREST"); + SQGSTile.DefSQConst(engine, ScriptTile::TERRAIN_SNOW, "TERRAIN_SNOW"); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_AT_SEA_LEVEL, ScriptTile::ERR_TILE_TOO_HIGH); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_AT_SEA_LEVEL, ScriptTile::ERR_TILE_TOO_LOW); @@ -90,6 +94,7 @@ void SQGSTile_Register(Squirrel *engine) SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsRoughTile, "IsRoughTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsSnowTile, "IsSnowTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsDesertTile, "IsDesertTile", 2, ".i"); + SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetTerrainType, "GetTerrainType", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetSlope, "GetSlope", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetComplementSlope, "GetComplementSlope", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetMinHeight, "GetMinHeight", 2, ".i"); diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp index 7ef72b8959..480e088be9 100644 --- a/src/script/api/game_changelog.hpp +++ b/src/script/api/game_changelog.hpp @@ -15,6 +15,11 @@ * functions may still be available if you return an older API version * in GetAPIVersion() in info.nut. * + * \b 1.3.1 + * + * API additions: + * \li GSTile::GetTerrainType + * * \b 1.3.0 * * API additions: diff --git a/src/script/api/script_tile.cpp b/src/script/api/script_tile.cpp index f6f016213d..b14bea649e 100644 --- a/src/script/api/script_tile.cpp +++ b/src/script/api/script_tile.cpp @@ -135,6 +135,19 @@ return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_DESERT)); } +/* static */ ScriptTile::TerrainType ScriptTile::GetTerrainType(TileIndex tile) +{ + if (!::IsValidTile(tile)) return TERRAIN_NORMAL; + + switch (::GetTerrainType(tile)) { + default: + case 0: return TERRAIN_NORMAL; + case 1: return TERRAIN_DESERT; + case 2: return TERRAIN_RAINFOREST; + case 4: return TERRAIN_SNOW; + } +} + /* static */ ScriptTile::Slope ScriptTile::GetSlope(TileIndex tile) { if (!::IsValidTile(tile)) return SLOPE_INVALID; diff --git a/src/script/api/script_tile.hpp b/src/script/api/script_tile.hpp index e4d9cda984..f4a2f0970e 100644 --- a/src/script/api/script_tile.hpp +++ b/src/script/api/script_tile.hpp @@ -120,6 +120,19 @@ public: BT_CLEAR_HOUSE, ///< Clear a tile with a house }; + /** + * The types of terrain a tile can have. + * + * @note When a desert or rainforest tile are changed, their terrain type will remain the same. In other words, a sea tile can be of the desert terrain type. + * @note The snow terrain type can change to the normal terrain type and vice versa based on landscaping or variable snow lines from NewGRFs. + */ + enum TerrainType { + TERRAIN_NORMAL, ///< A normal tile (default); not desert, rainforest or snow. + TERRAIN_DESERT, ///< A tile in the desert (manually set in in scenarios, below certain height and certain distance from water in random games). + TERRAIN_RAINFOREST, ///< A tile in the rainforest (manually set in scenarios, certain distance away from deserts in random games), + TERRAIN_SNOW ///< A tile on or above the snowline level. + }; + /** * Check if this tile is buildable, i.e. no things on it that needs * demolishing. @@ -222,7 +235,8 @@ public: static bool IsRoughTile(TileIndex tile); /** - * Check if the tile is a snow tile. + * Check if the tile without buildings or infrastructure is a snow tile. + * @note If you want to know if a tile (with or without buildings and infrastructure) is on or above the snowline, use ScriptTile::GetTerrainType(tile). * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is snow tile. @@ -230,13 +244,24 @@ public: static bool IsSnowTile(TileIndex tile); /** - * Check if the tile is a desert tile. + * Check if the tile without buildings or infrastructure is a desert tile. + * @note If you want to know if a tile (with or without buildings and infrastructure) is in a desert, use ScriptTile::GetTerrainType(tile). * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is desert tile. */ static bool IsDesertTile(TileIndex tile); + /** + * Get the type of terrain regardless of buildings or infrastructure. + * @note When a desert or rainforest tile are changed, their terrain type will remain the same. In other words, a sea tile can be of the desert terrain type. + * @note The snow terrain type can change to the normal terrain type and vice versa based on landscaping or variable snow lines from NewGRFs. + * @param tile The tile to check on. + * @pre ScriptMap::IsValidTile(tile). + * @return The #TerrainType. + */ + static TerrainType GetTerrainType(TileIndex tile); + /** * Get the slope of a tile. * This is the slope of the bare tile. A possible foundation on the tile does not influence this slope. diff --git a/src/script/api/template/template_tile.hpp.sq b/src/script/api/template/template_tile.hpp.sq index 8897e8c55e..e78aaa6ace 100644 --- a/src/script/api/template/template_tile.hpp.sq +++ b/src/script/api/template/template_tile.hpp.sq @@ -23,6 +23,8 @@ namespace SQConvert { template <> inline int Return(HSQUIRRELVM vm, ScriptTile::TransportType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTile::BuildType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTile::BuildType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTile::BuildType res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptTile::TerrainType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTile::TerrainType)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTile::TerrainType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptTile to be used as Squirrel parameter */ template <> inline ScriptTile *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTile *)instance; } diff --git a/src/station_map.h b/src/station_map.h index 1411a7833d..67f41f1d75 100644 --- a/src/station_map.h +++ b/src/station_map.h @@ -364,25 +364,25 @@ static inline TrackBits GetRailStationTrackBits(TileIndex t) } /** - * Check if tile is compatible with a railstation tile. The two tiles - * are compatible if all of the following are true: - * \li both tiles are rail station tiles - * \li the railtype of \a t1 is compatible with the railtype of \a t2 - * \li the tracks on \a t1 and \a t2 are in the same direction + * Check if a tile is a valid continuation to a railstation tile. + * The tile \a test_tile is a valid continuation to \a station_tile, if all of the following are true: + * \li \a test_tile is a rail station tile + * \li the railtype of \a test_tile is compatible with the railtype of \a station_tile + * \li the tracks on \a test_tile and \a station_tile are in the same direction * \li both tiles belong to the same station - * \li \a t1 is not blocked (@see IsStationTileBlocked) - * @param t1 First tile to compare - * @param t2 Second tile to compare - * @pre IsRailStationTile(t2) + * \li \a test_tile is not blocked (@see IsStationTileBlocked) + * @param test_tile Tile to test + * @param station_tile Station tile to compare with + * @pre IsRailStationTile(station_tile) * @return true if the two tiles are compatible */ -static inline bool IsCompatibleTrainStationTile(TileIndex t1, TileIndex t2) +static inline bool IsCompatibleTrainStationTile(TileIndex test_tile, TileIndex station_tile) { - assert(IsRailStationTile(t2)); - return IsRailStationTile(t1) && IsCompatibleRail(GetRailType(t1), GetRailType(t2)) && - GetRailStationAxis(t1) == GetRailStationAxis(t2) && - GetStationIndex(t1) == GetStationIndex(t2) && - !IsStationTileBlocked(t1); + assert(IsRailStationTile(station_tile)); + return IsRailStationTile(test_tile) && IsCompatibleRail(GetRailType(test_tile), GetRailType(station_tile)) && + GetRailStationAxis(test_tile) == GetRailStationAxis(station_tile) && + GetStationIndex(test_tile) == GetStationIndex(station_tile) && + !IsStationTileBlocked(test_tile); } /** diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 6b4f41eb98..ccda7fb063 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -606,6 +606,8 @@ static bool IsWateredTile(TileIndex tile, Direction from) case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from); + case MP_VOID: return true; // consider map border as water, esp. for rivers + default: return false; } }