Index: src/industry_cmd.cpp =================================================================== --- src/industry_cmd.cpp (revision 27177) +++ src/industry_cmd.cpp (working copy) @@ -1756,8 +1756,13 @@ WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID); + /* While it's true Industry Tiles don't have any owner, the following + DoCommand below is inadvertently setting bit 4 of m1 to 1. To preserve its + original value, store it first before executing DoCommand, then restore it + before MakeIndustry takes action. */ + Owner old_owner = GetTileOwner(cur_tile); DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR); - + SetTileOwner(cur_tile, old_owner); MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc); if (_generating_world) { Index: src/industry_map.h =================================================================== --- src/industry_map.h (revision 27177) +++ src/industry_map.h (working copy) @@ -280,7 +280,7 @@ static inline void MakeIndustry(TileIndex t, IndustryID index, IndustryGfx gfx, uint8 random, WaterClass wc) { SetTileType(t, MP_INDUSTRY); - _m[t].m1 = 0; + _m[t].m1 &= 1<<4; // Make sure bit 4 is unaffected. _m[t].m2 = index; SetIndustryRandomBits(t, random); // m3 _m[t].m4 = 0; Index: src/saveload/afterload.cpp =================================================================== --- src/saveload/afterload.cpp (revision 27177) +++ src/saveload/afterload.cpp (working copy) @@ -430,7 +430,7 @@ */ static void FixOwnerOfRailTrack(TileIndex t) { - assert(!Company::IsValidID(GetTileOwner(t)) && (IsLevelCrossingTile(t) || IsPlainRailTile(t))); + assert(!Company::IsValidID(GetTileOwnerOld(t)) && (IsLevelCrossingTile(t) || IsPlainRailTile(t))); /* remove leftover rail piece from crossing (from very old savegames) */ Train *v = NULL, *w; @@ -452,8 +452,8 @@ TileIndex tt = t + TileOffsByDiagDir(dd); if (GetTileTrackStatus(t, TRANSPORT_RAIL, 0, dd) != 0 && GetTileTrackStatus(tt, TRANSPORT_RAIL, 0, ReverseDiagDir(dd)) != 0 && - Company::IsValidID(GetTileOwner(tt))) { - SetTileOwner(t, GetTileOwner(tt)); + Company::IsValidID(GetTileOwnerOld(tt))) { + SetTileOwner(t, GetTileOwnerOld(tt)); return; } } @@ -614,7 +614,7 @@ * walk through the whole map.. */ if (IsSavegameVersionBefore(4, 3)) { for (TileIndex t = 0; t < map_size; t++) { - if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= MAX_COMPANIES) { + if (IsTileType(t, MP_WATER) && GetTileOwnerOld(t) >= MAX_COMPANIES) { SetTileOwner(t, OWNER_WATER); } } @@ -820,7 +820,7 @@ default: break; case MP_WATER: - if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE); + if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwnerOld(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE); break; case MP_STATION: { @@ -949,7 +949,7 @@ case MP_ROAD: _m[t].m4 |= (_m[t].m2 << 4); - if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwner(t)) == OWNER_TOWN) { + if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwnerOld(t)) == OWNER_TOWN) { SetTownIndex(t, CalcClosestTownFromTile(t)->index); } else { SetTownIndex(t, 0); @@ -1104,7 +1104,7 @@ if (!IsRoadStop(t)) break; if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_m[t].m3, 0, 3)); - SB(_me[t].m7, 0, 5, HasBit(_me[t].m6, 2) ? OWNER_TOWN : GetTileOwner(t)); + SB(_me[t].m7, 0, 5, HasBit(_me[t].m6, 2) ? OWNER_TOWN : GetTileOwnerOld(t)); SB(_m[t].m3, 4, 4, _m[t].m1); _m[t].m4 = 0; break; @@ -1114,7 +1114,7 @@ if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_m[t].m3, 0, 3)); - Owner o = GetTileOwner(t); + Owner o = GetTileOwnerOld(t); SB(_me[t].m7, 0, 5, o); // road owner SB(_m[t].m3, 4, 4, o == OWNER_NONE ? OWNER_TOWN : o); // tram owner } @@ -1143,7 +1143,7 @@ if (GB(_m[t].m5, 3, 2) == TRANSPORT_RAIL) { MakeRailNormal( t, - GetTileOwner(t), + GetTileOwnerOld(t), axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, GetRailType(t) ); @@ -1155,7 +1155,7 @@ axis == AXIS_X ? ROAD_Y : ROAD_X, ROADTYPES_ROAD, town, - GetTileOwner(t), OWNER_NONE + GetTileOwnerOld(t), OWNER_NONE ); } } else { @@ -1165,10 +1165,10 @@ if (!IsTileFlat(t)) { MakeShore(t); } else { - if (GetTileOwner(t) == OWNER_WATER) { + if (GetTileOwnerOld(t) == OWNER_WATER) { MakeSea(t); } else { - MakeCanal(t, GetTileOwner(t), Random()); + MakeCanal(t, GetTileOwnerOld(t), Random()); } } } @@ -1604,7 +1604,7 @@ for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_WATER) && GetWaterTileType(t) == WATER_TILE_CLEAR && - GetTileOwner(t) == OWNER_WATER && + GetTileOwnerOld(t) == OWNER_WATER && TileHeight(t) != 0) { SetTileOwner(t, OWNER_NONE); } @@ -1756,7 +1756,7 @@ if (IsTileType(t, MP_WATER)) { if (GetWaterClass(t) != WATER_CLASS_RIVER) { if (IsWater(t)) { - Owner o = GetTileOwner(t); + Owner o = GetTileOwnerOld(t); if (o == OWNER_WATER) { MakeSea(t); } else { @@ -1792,7 +1792,7 @@ } if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) { - Owner o = GetTileOwner(t); + Owner o = GetTileOwnerOld(t); if (o < MAX_COMPANIES && !Company::IsValidID(o)) { Backup cur_company(_current_company, o, FILE_LINE); ChangeTileOwner(t, o, INVALID_OWNER); @@ -1811,10 +1811,10 @@ if (o < MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rt, OWNER_NONE); } if (IsLevelCrossing(t)) { - if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); + if (!Company::IsValidID(GetTileOwnerOld(t))) FixOwnerOfRailTrack(t); } } else if (IsPlainRailTile(t)) { - if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); + if (!Company::IsValidID(GetTileOwnerOld(t))) FixOwnerOfRailTrack(t); } } @@ -2447,7 +2447,7 @@ if (IsSavegameVersionBefore(148)) { Object *o; FOR_ALL_OBJECTS(o) { - Owner owner = GetTileOwner(o->location.tile); + Owner owner = GetTileOwnerOld(o->location.tile); o->colour = (owner == OWNER_NONE) ? Random() & 0xF : Company::Get(owner)->livery->colour1; } } @@ -2821,7 +2821,7 @@ if (IsSavegameVersionBefore(172)) { for (TileIndex t = 0; t < map_size; t++) { if (!IsStandardRoadStopTile(t)) continue; - Owner o = GetTileOwner(t); + Owner o = GetTileOwnerOld(t); SetRoadOwner(t, ROADTYPE_ROAD, o); SetRoadOwner(t, ROADTYPE_TRAM, o); } @@ -2985,6 +2985,18 @@ ResetSignalHandlers(); AfterLoadLinkGraphs(); + + /* Convert m1 bit 4 value for all industry tiles */ + if (IsSavegameVersionBefore(195)) { + for (TileIndex t = 0; t < map_size; t++) { + /* It's not possible to know who was the original owner of a canal tile built under + an Oil Rig tile from an old save game. To preserve savegame backward compatibility, + don't do anything about them. Old and new values for a given industry tile can co-exist. */ + if (IsTileType(t, MP_INDUSTRY) && (GetWaterClass(t) != WATER_CLASS_CANAL)) { + SB(_m[t].m1, 4, 1, 1); + } + } + } return true; } Index: src/saveload/saveload.cpp =================================================================== --- src/saveload/saveload.cpp (revision 27177) +++ src/saveload/saveload.cpp (working copy) @@ -262,8 +262,9 @@ * 192 26700 * 193 26802 * 194 26881 + * 195 CanalOwner testings */ -extern const uint16 SAVEGAME_VERSION = 194; ///< Current savegame version of OpenTTD. +extern const uint16 SAVEGAME_VERSION = 195; ///< Current savegame version of OpenTTD. SavegameType _savegame_type; ///< type of savegame we are loading Index: src/tile_map.h =================================================================== --- src/tile_map.h (revision 27177) +++ src/tile_map.h (working copy) @@ -168,14 +168,27 @@ * @pre IsValidTile(tile) * @pre The type of the tile must not be MP_HOUSE and MP_INDUSTRY */ -static inline Owner GetTileOwner(TileIndex tile) + +static inline Owner GetTileOwnerOld(TileIndex tile) { assert(IsValidTile(tile)); assert(!IsTileType(tile, MP_HOUSE)); assert(!IsTileType(tile, MP_INDUSTRY)); - return (Owner)GB(_m[tile].m1, 0, 5); } +static inline Owner GetTileOwner(TileIndex tile) +{ + assert(IsValidTile(tile)); + assert(!IsTileType(tile, MP_HOUSE)); + assert(!IsTileType(tile, MP_INDUSTRY)); + if ((IsTileType(tile, MP_STATION) || IsTileType(tile, MP_WATER) || IsTileType(tile, MP_OBJECT))) { + Owner co = (Owner)GB(_m[tile].m1, 0, 4); + return co == OWNER_TOWN ? OWNER_NONE : co; + + } else { + return (Owner)GB(_m[tile].m1, 0, 5); + } +} /** * Sets the owner of a tile @@ -193,8 +206,11 @@ assert(IsValidTile(tile)); assert(!IsTileType(tile, MP_HOUSE)); assert(!IsTileType(tile, MP_INDUSTRY)); - - SB(_m[tile].m1, 0, 5, owner); + if ((IsTileType(tile, MP_STATION) || IsTileType(tile, MP_WATER) || IsTileType(tile, MP_OBJECT)) && owner == OWNER_NONE) { + SB(_m[tile].m1, 0, 4, OWNER_TOWN); + } else { + SB(_m[tile].m1, 0, 5, owner); + } } /** Index: src/water_cmd.cpp =================================================================== --- src/water_cmd.cpp (revision 27177) +++ src/water_cmd.cpp (working copy) @@ -419,7 +419,9 @@ if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue; bool water = IsWaterTile(tile); + ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR); + if (ret.Failed()) return ret; if (!water) cost.AddCost(ret); Index: src/water_map.h =================================================================== --- src/water_map.h (revision 27177) +++ src/water_map.h (working copy) @@ -176,6 +176,12 @@ return IsWater(t) && GetWaterClass(t) == WATER_CLASS_RIVER; } +static inline bool IsCanalOnRiver(TileIndex t) +{ + assert(HasTileWaterClass(t)); + return HasBit(_m[t].m1, 4); +} + /** * Is it a water tile with plain water? * @param t Tile to query. @@ -346,8 +352,33 @@ return HasTileWaterClass(t) && IsTileOnWater(t) && !IsCoastTile(t); } +/** + * Comment about getting owner of canal + */ +static inline Owner GetCanalOwner(TileIndex t) +{ + assert(HasTileWaterGround(t)); + if (GetWaterClass(t) != WATER_CLASS_CANAL) { + return GetTileOwner(t); + } else { + Owner co = (Owner)(GB(_me[t].m6, 0, 2) && GB(_me[t].m6, 6, 2)); + /* Canals don't have OWNER_TOWN, and remapping OWNER_NONE + * to OWNER_TOWN makes it use one bit less */ + return co == OWNER_TOWN ? OWNER_NONE : co; + } +} /** + * Comment about setting owner of canal + */ +static inline void SetCanalOwner(TileIndex t, Owner co) +{ + if (co == OWNER_NONE) co = OWNER_TOWN; + SB(_me[t].m6, 0, 2, GB(co, 0, 2)); + SB(_me[t].m6, 6, 2, GB(co, 2, 2)); +} + +/** * Helper function to make a coast tile. * @param t The tile to change into water */ @@ -413,6 +444,7 @@ { assert(o != OWNER_WATER); MakeWater(t, o, WATER_CLASS_CANAL, random_bits); + SetCanalOwner(t, o); } /**