diff --git a/bin/ai/regression/regression.nut b/bin/ai/regression/regression.nut index 6a49eef1fd..bf6a4ed6c0 100644 --- a/bin/ai/regression/regression.nut +++ b/bin/ai/regression/regression.nut @@ -1755,6 +1755,48 @@ function Regression::PrintSubsidy(subsidy_id) print(" GetCargoType(): " + AISubsidy.GetCargoType(subsidy_id)); } +function Regression::Math() +{ + print(""); + print("--Math--"); + print(" -2147483648 < -2147483647: " + (-2147483648 < -2147483647)); + print(" -2147483648 < -1 : " + (-2147483648 < -1 )); + print(" -2147483648 < 0 : " + (-2147483648 < 0 )); + print(" -2147483648 < 1 : " + (-2147483648 < 1 )); + print(" -2147483648 < 2147483647: " + (-2147483648 < 2147483647)); + + print(" -2147483647 < -2147483648: " + (-2147483647 < -2147483648)); + print(" -1 < -2147483648: " + (-1 < -2147483648)); + print(" 0 < -2147483648: " + ( 0 < -2147483648)); + print(" 1 < -2147483648: " + ( 1 < -2147483648)); + print(" 2147483647 < -2147483648: " + ( 2147483647 < -2147483648)); + + print(" -1 > 2147483647: " + (-1 > 2147483647)); + print(" -1 > 1 : " + (-1 > 1 )); + print(" -1 > 0 : " + (-1 > 0 )); + print(" -1 > -1 : " + (-1 > -1 )); + print(" -1 > -2147483648: " + (-1 > -2147483648)); + + print(" 1 > 2147483647: " + ( 1 > 2147483647)); + print(" 1 > 1 : " + ( 1 > 1 )); + print(" 1 > 0 : " + ( 1 > 0 )); + print(" 1 > -1 : " + ( 1 > -1 )); + print(" 1 > -2147483648: " + ( 1 > -2147483648)); + + print(" 2147483647 > 2147483646: " + ( 2147483647 > 2147483646)); + print(" 2147483647 > 1 : " + ( 2147483647 > 1 )); + print(" 2147483647 > 0 : " + ( 2147483647 > 0 )); + print(" 2147483647 > -1 : " + ( 2147483647 > -1 )); + print(" 2147483647 > -2147483648: " + ( 2147483647 > -2147483648)); + + print(" 2147483646 > 2147483647: " + ( 2147483646 > 2147483647)); + print(" 1 > 2147483647: " + ( 1 > 2147483647)); + print(" 0 > 2147483647: " + ( 0 > 2147483647)); + print(" -1 > 2147483647: " + (-1 > 2147483647)); + print(" -2147483648 > 2147483647: " + (-2147483648 > 2147483647)); + + print(" 13725 > -2147483648: " + ( 13725 > -2147483648)); +} function Regression::Start() { @@ -1820,5 +1862,7 @@ function Regression::Start() } } print(" IsEventWaiting: false"); + + this.Math(); } diff --git a/bin/ai/regression/regression.txt b/bin/ai/regression/regression.txt index f78992a50b..67524ee85d 100644 --- a/bin/ai/regression/regression.txt +++ b/bin/ai/regression/regression.txt @@ -8630,4 +8630,37 @@ ERROR: HasNext() is invalid as Begin() is never called GetEventType: 6 Unknown Event IsEventWaiting: false + +--Math-- + -2147483648 < -2147483647: true + -2147483648 < -1 : true + -2147483648 < 0 : true + -2147483648 < 1 : true + -2147483648 < 2147483647: true + -2147483647 < -2147483648: false + -1 < -2147483648: false + 0 < -2147483648: false + 1 < -2147483648: false + 2147483647 < -2147483648: false + -1 > 2147483647: false + -1 > 1 : false + -1 > 0 : false + -1 > -1 : false + -1 > -2147483648: true + 1 > 2147483647: false + 1 > 1 : false + 1 > 0 : true + 1 > -1 : true + 1 > -2147483648: true + 2147483647 > 2147483646: true + 2147483647 > 1 : true + 2147483647 > 0 : true + 2147483647 > -1 : true + 2147483647 > -2147483648: true + 2147483646 > 2147483647: false + 1 > 2147483647: false + 0 > 2147483647: false + -1 > 2147483647: false + -2147483648 > 2147483647: false + 13725 > -2147483648: true ERROR: The AI died unexpectedly. diff --git a/readme.txt b/readme.txt index 7e76b4dee1..4dc8bb0d19 100644 --- a/readme.txt +++ b/readme.txt @@ -253,6 +253,9 @@ The required 3rd party files listed in the section 4.1 "(Required) 3rd party fil as well as other non-compulsory extensions (NewGRFs, AI, heightmaps, scenarios) can be placed in a few different locations: 1. The current working directory (from where you started OpenTTD) + For non-Windows operating systems OpenTTD will not scan for files in this + directory if it is your personal directory, i.e. "~/", or when it is the + root directory, i.e. "/". 2. Your personal directory Windows: C:\My Documents (95, 98, ME) C:\Documents and Settings\\My Documents\OpenTTD (2000, XP) diff --git a/src/3rdparty/squirrel/squirrel/sqvm.cpp b/src/3rdparty/squirrel/squirrel/sqvm.cpp index 5a2afe2a15..1dbd83f306 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.cpp +++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp @@ -186,7 +186,8 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result) case OT_STRING: _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2))); case OT_INTEGER: - _RET_SUCCEED(_integer(o1)-_integer(o2)); + /* FS#3954: wrong integer comparison */ + _RET_SUCCEED((_integer(o1)<_integer(o2))?-1:(_integer(o1)==_integer(o2))?0:1); case OT_FLOAT: _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); case OT_TABLE: diff --git a/src/elrail.cpp b/src/elrail.cpp index 41b0d5a740..e668e66127 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -165,20 +165,20 @@ static TrackBits MaskWireBits(TileIndex t, TrackBits tracks) /** * Get the base wire sprite to use. */ -static inline SpriteID GetWireBase(TileIndex tile) +static inline SpriteID GetWireBase(TileIndex tile, bool upper_halftile = false) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); - SpriteID wires = GetCustomRailSprite(rti, tile, RTSG_WIRES); + SpriteID wires = GetCustomRailSprite(rti, tile, RTSG_WIRES, upper_halftile); return wires == 0 ? SPR_WIRE_BASE : wires; } /** * Get the base pylon sprite to use. */ -static inline SpriteID GetPylonBase(TileIndex tile) +static inline SpriteID GetPylonBase(TileIndex tile, bool upper_halftile = false) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); - SpriteID pylons = GetCustomRailSprite(rti, tile, RTSG_PYLONS); + SpriteID pylons = GetCustomRailSprite(rti, tile, RTSG_PYLONS, upper_halftile); return pylons == 0 ? SPR_PYLON_BASE : pylons; } @@ -274,7 +274,11 @@ static void DrawCatenaryRailway(const TileInfo *ti) /* Half tile slopes coincide only with horizontal/vertical track. * Faking a flat slope results in the correct sprites on positions. */ - if (IsHalftileSlope(tileh[TS_HOME])) tileh[TS_HOME] = SLOPE_FLAT; + Corner halftile_corner = CORNER_INVALID; + if (IsHalftileSlope(tileh[TS_HOME])) { + halftile_corner = GetHalftileSlopeCorner(tileh[TS_HOME]); + tileh[TS_HOME] = SLOPE_FLAT; + } TLG tlg = GetTLG(ti->tile); byte PCPstatus = 0; @@ -295,9 +299,17 @@ static void DrawCatenaryRailway(const TileInfo *ti) AdjustTileh(ti->tile, &tileh[TS_HOME]); - SpriteID pylon_base = GetPylonBase(ti->tile); + SpriteID pylon_normal = GetPylonBase(ti->tile); + SpriteID pylon_halftile = (halftile_corner != CORNER_INVALID) ? GetPylonBase(ti->tile, true) : pylon_normal; for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) { + static const uint edge_corners[] = { + 1 << CORNER_N | 1 << CORNER_E, // DIAGDIR_NE + 1 << CORNER_S | 1 << CORNER_E, // DIAGDIR_SE + 1 << CORNER_S | 1 << CORNER_W, // DIAGDIR_SW + 1 << CORNER_N | 1 << CORNER_W, // DIAGDIR_NW + }; + SpriteID pylon_base = (halftile_corner != CORNER_INVALID && HasBit(edge_corners[i], halftile_corner)) ? pylon_halftile : pylon_normal; TileIndex neighbour = ti->tile + TileOffsByDiagDir(i); Foundation foundation = FOUNDATION_NONE; byte elevation = GetPCPElevation(ti->tile, i); @@ -426,11 +438,21 @@ static void DrawCatenaryRailway(const TileInfo *ti) if (height <= GetTileMaxZ(ti->tile) + TILE_HEIGHT) return; } - SpriteID wire_base = GetWireBase(ti->tile); + SpriteID wire_normal = GetWireBase(ti->tile); + SpriteID wire_halftile = (halftile_corner != CORNER_INVALID) ? GetWireBase(ti->tile, true) : wire_normal; + Track halftile_track; + switch (halftile_corner) { + case CORNER_W: halftile_track = TRACK_LEFT; break; + case CORNER_S: halftile_track = TRACK_LOWER; break; + case CORNER_E: halftile_track = TRACK_RIGHT; break; + case CORNER_N: halftile_track = TRACK_UPPER; break; + default: halftile_track = INVALID_TRACK; break; + } /* Drawing of pylons is finished, now draw the wires */ for (Track t = TRACK_BEGIN; t < TRACK_END; t++) { if (HasBit(wireconfig[TS_HOME], t)) { + SpriteID wire_base = (t == halftile_track) ? wire_halftile : wire_normal; byte PCPconfig = HasBit(PCPstatus, PCPpositions[t][0]) + (HasBit(PCPstatus, PCPpositions[t][1]) << 1); diff --git a/src/fileio.cpp b/src/fileio.cpp index e329571478..c43f87567c 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -44,7 +44,7 @@ struct Fio { FILE *handles[MAX_FILE_SLOTS]; ///< array of file handles we can have open byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file const char *filenames[MAX_FILE_SLOTS]; ///< array of filenames we (should) have open - char *shortnames[MAX_FILE_SLOTS];///< array of short names for spriteloader's use + char *shortnames[MAX_FILE_SLOTS]; ///< array of short names for spriteloader's use #if defined(LIMITED_FDS) uint open_handles; ///< current amount of open handles uint usage_count[MAX_FILE_SLOTS]; ///< count how many times this file has been opened @@ -53,6 +53,9 @@ struct Fio { static Fio _fio; +/** Whether the working directory should be scanned. */ +static bool _do_scan_working_directory = true; + /* Get current position in file */ size_t FioGetPos() { @@ -875,6 +878,33 @@ void ChangeWorkingDirectory(const char *exe) #endif /* WITH_COCOA */ } +/** + * Whether we should scan the working directory. + * It should not be scanned if it's the root or + * the home directory as in both cases a big data + * directory can cause huge amounts of unrelated + * files scanned. Furthermore there are nearly no + * use cases for the home/root directory to have + * OpenTTD directories. + * @return true if it should be scanned. + */ +bool DoScanWorkingDirectory() +{ + /* No working directory, so nothing to do. */ + if (_searchpaths[SP_WORKING_DIR] == NULL) return false; + + /* Working directory is root, so do nothing. */ + if (strcmp(_searchpaths[SP_WORKING_DIR], PATHSEP) == 0) return false; + + /* No personal/home directory, so the working directory won't be that. */ + if (_searchpaths[SP_PERSONAL_DIR] == NULL) return true; + + char tmp[MAX_PATH]; + snprintf(tmp, lengthof(tmp), "%s%s", _searchpaths[SP_WORKING_DIR], PERSONAL_DIR); + AppendPathSeparator(tmp, MAX_PATH); + return strcmp(tmp, _searchpaths[SP_PERSONAL_DIR]) != 0; +} + /** * Determine the base (personal dir and game data dir) paths * @param exe the path to the executable @@ -920,6 +950,8 @@ void DetermineBasePaths(const char *exe) _searchpaths[SP_WORKING_DIR] = strdup(tmp); #endif + _do_scan_working_directory = DoScanWorkingDirectory(); + /* Change the working directory to that one of the executable */ ChangeWorkingDirectory(exe); if (getcwd(tmp, MAX_PATH) == NULL) *tmp = '\0'; @@ -960,7 +992,10 @@ void DeterminePaths(const char *exe) DetermineBasePaths(exe); Searchpath sp; - FOR_ALL_SEARCHPATHS(sp) DEBUG(misc, 4, "%s added as search path", _searchpaths[sp]); + FOR_ALL_SEARCHPATHS(sp) { + if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; + DEBUG(misc, 4, "%s added as search path", _searchpaths[sp]); + } if (_config_file != NULL) { _personal_dir = strdup(_config_file); @@ -1176,6 +1211,9 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r uint num = 0; FOR_ALL_SEARCHPATHS(sp) { + /* Don't search in the working directory */ + if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; + FioAppendDirectory(path, MAX_PATH, sp, sd); num += ScanPath(this, extension, path, strlen(path), recursive); } diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index f95ad985cb..cbf54a24a3 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -17,8 +17,10 @@ #include "industrytype.h" #include "newgrf.h" #include "newgrf_commons.h" +#include "clear_map.h" #include "station_map.h" #include "tree_map.h" +#include "tunnelbridge_map.h" #include "core/mem_func.hpp" /** Constructor of generic class @@ -278,13 +280,56 @@ void IndustryTileOverrideManager::SetEntitySpec(const IndustryTileSpec *its) /** Function used by houses (and soon industries) to get information * on type of "terrain" the tile it is queries sits on. * @param tile TileIndex of the tile been queried + * @param upper_halftile If true, query upper halftile in case of rail tiles. * @return value corresponding to the grf expected format: * Terrain type: 0 normal, 1 desert, 2 rainforest, 4 on or above snowline */ -uint32 GetTerrainType(TileIndex tile) +uint32 GetTerrainType(TileIndex tile, bool upper_halftile) { switch (_settings_game.game_creation.landscape) { case LT_TROPIC: return GetTropicZone(tile); - case LT_ARCTIC: return GetTileZ(tile) > GetSnowLine() ? 4 : 0; + case LT_ARCTIC: { + bool has_snow; + switch (GetTileType(tile)) { + case MP_CLEAR: + has_snow = IsSnowTile(tile) && GetClearDensity(tile) >= 2; + break; + + case MP_RAILWAY: { + RailGroundType ground = GetRailGroundType(tile); + has_snow = (ground == RAIL_GROUND_ICE_DESERT || (upper_halftile && ground == RAIL_GROUND_HALF_SNOW)); + break; + } + + case MP_ROAD: + has_snow = IsOnSnow(tile); + break; + + case MP_TREES: { + TreeGround ground = GetTreeGround(tile); + has_snow = (ground == TREE_GROUND_SNOW_DESERT || ground == TREE_GROUND_ROUGH_SNOW) && GetTreeDensity(tile) >= 2; + break; + } + + case MP_TUNNELBRIDGE: + has_snow = HasTunnelBridgeSnowOrDesert(tile); + break; + + case MP_STATION: + case MP_HOUSE: + case MP_INDUSTRY: + case MP_UNMOVABLE: + /* These tiles usually have a levelling foundation. So use max Z */ + has_snow = (GetTileMaxZ(tile) > GetSnowLine()); + break; + + case MP_WATER: + has_snow = (GetTileZ(tile) > GetSnowLine()); + break; + + default: NOT_REACHED(); + } + return has_snow ? 4 : 0; + } default: return 0; } } diff --git a/src/newgrf_commons.h b/src/newgrf_commons.h index e58e7e6b04..df277b4b03 100644 --- a/src/newgrf_commons.h +++ b/src/newgrf_commons.h @@ -101,7 +101,7 @@ extern HouseOverrideManager _house_mngr; extern IndustryOverrideManager _industry_mngr; extern IndustryTileOverrideManager _industile_mngr; -uint32 GetTerrainType(TileIndex tile); +uint32 GetTerrainType(TileIndex tile, bool upper_halftile = false); TileIndex GetNearbyTile(byte parameter, TileIndex tile); uint32 GetNearbyTileInformation(TileIndex tile); diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 931f544e9c..9aa6e2b544 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -45,7 +45,7 @@ static uint32 RailTypeGetVariable(const ResolverObject *object, byte variable, b } switch (variable) { - case 0x40: return GetTerrainType(tile); + case 0x40: return GetTerrainType(tile, object->u.routes.upper_halftile); case 0x41: return 0; case 0x42: return IsLevelCrossingTile(tile) && IsCrossingBarred(tile); } @@ -63,7 +63,7 @@ static const SpriteGroup *RailTypeResolveReal(const ResolverObject *object, cons return NULL; } -static inline void NewRailTypeResolver(ResolverObject *res, TileIndex tile) +static inline void NewRailTypeResolver(ResolverObject *res, TileIndex tile, bool upper_halftile) { res->GetRandomBits = &RailTypeGetRandomBits; res->GetTriggers = &RailTypeGetTriggers; @@ -72,6 +72,7 @@ static inline void NewRailTypeResolver(ResolverObject *res, TileIndex tile) res->ResolveReal = &RailTypeResolveReal; res->u.routes.tile = tile; + res->u.routes.upper_halftile = upper_halftile; res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; @@ -82,7 +83,7 @@ static inline void NewRailTypeResolver(ResolverObject *res, TileIndex tile) res->count = 0; } -SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg) +SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, bool upper_halftile) { assert(rtsg < RTSG_END); @@ -91,7 +92,7 @@ SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSp const SpriteGroup *group; ResolverObject object; - NewRailTypeResolver(&object, tile); + NewRailTypeResolver(&object, tile, upper_halftile); group = SpriteGroup::Resolve(rti->group[rtsg], &object); if (group == NULL || group->GetNumResults() == 0) return 0; diff --git a/src/newgrf_railtype.h b/src/newgrf_railtype.h index 8dcd4fed07..40f772c034 100644 --- a/src/newgrf_railtype.h +++ b/src/newgrf_railtype.h @@ -5,7 +5,7 @@ #include "rail.h" -SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg); +SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, bool upper_halftile = false); uint8 GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile); diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 84aff8aa7d..5f63ed6ad2 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -342,6 +342,7 @@ struct ResolverObject { } generic; struct { TileIndex tile; + bool upper_halftile; ///< Are we resolving sprites for the upper halftile? } routes; } u; diff --git a/src/pbs.cpp b/src/pbs.cpp index 863f98b3b1..bb018739e9 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -314,6 +314,10 @@ Train *GetTrainForReservation(TileIndex tile, Track track) * have a train on it. We need FollowReservation to ignore one-way signals * here, as one of the two search directions will be the "wrong" way. */ for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) { + /* If the tile has a one-way block signal in the current trackdir, skip the + * search in this direction as the reservation can't come from this side.*/ + if (HasOnewaySignalBlockingTrackdir(tile, ReverseTrackdir(trackdir)) && !HasPbsSignalOnTrackdir(tile, trackdir)) continue; + FindTrainOnTrackInfo ftoti; ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true); diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 96d64b2490..1021deb77e 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1750,8 +1750,9 @@ static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image) static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti) { - /* Base sprite for track fences. */ - SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES); + /* Base sprite for track fences. + * Note: Halftile slopes only have fences on the upper part. */ + SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh)); if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X; switch (GetRailGroundType(ti->tile)) { @@ -1910,6 +1911,8 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn if (IsValidCorner(halftile_corner)) { DrawFoundation(ti, HalftileFoundation(halftile_corner)); + overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, true); + ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, true); /* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */ Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));