diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index 605d5142dd..68d23481b3 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -333,6 +333,7 @@ + @@ -469,6 +470,7 @@ + @@ -610,6 +612,7 @@ + @@ -641,6 +644,7 @@ + @@ -771,6 +775,7 @@ + @@ -864,6 +869,7 @@ + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index da71857c38..83b434cb3a 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -195,6 +195,9 @@ Source Files + + Source Files + Source Files @@ -603,6 +606,9 @@ Header Files + + Header Files + Header Files @@ -1026,6 +1032,9 @@ Header Files + + Header Files + Header Files @@ -1119,6 +1128,9 @@ Header Files + + Header Files + Header Files @@ -1509,6 +1521,9 @@ GUI Source Code + + GUI Source Code + GUI Source Code @@ -1788,6 +1803,9 @@ Command handlers + + Command handlers + Command handlers diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 806003f8ab..db235a4328 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -350,6 +350,7 @@ + @@ -486,6 +487,7 @@ + @@ -627,6 +629,7 @@ + @@ -658,6 +661,7 @@ + @@ -788,6 +792,7 @@ + @@ -881,6 +886,7 @@ + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index da71857c38..83b434cb3a 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -195,6 +195,9 @@ Source Files + + Source Files + Source Files @@ -603,6 +606,9 @@ Header Files + + Header Files + Header Files @@ -1026,6 +1032,9 @@ Header Files + + Header Files + Header Files @@ -1119,6 +1128,9 @@ Header Files + + Header Files + Header Files @@ -1509,6 +1521,9 @@ GUI Source Code + + GUI Source Code + GUI Source Code @@ -1788,6 +1803,9 @@ Command handlers + + Command handlers + Command handlers diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index 230eea467c..722ec6f578 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -554,6 +554,10 @@ RelativePath=".\..\src\disaster_vehicle.cpp" > + + @@ -1102,6 +1106,10 @@ RelativePath=".\..\src\music\dmusic.h" > + + @@ -1666,6 +1674,10 @@ RelativePath=".\..\src\video\sdl_v.h" > + + @@ -1790,6 +1802,10 @@ RelativePath=".\..\src\string_func.h" > + + @@ -2318,6 +2334,10 @@ RelativePath=".\..\src\roadveh_gui.cpp" > + + @@ -2698,6 +2718,10 @@ RelativePath=".\..\src\roadveh_cmd.cpp" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index c161f47197..12672abb71 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -551,6 +551,10 @@ RelativePath=".\..\src\disaster_vehicle.cpp" > + + @@ -1099,6 +1103,10 @@ RelativePath=".\..\src\music\dmusic.h" > + + @@ -1663,6 +1671,10 @@ RelativePath=".\..\src\video\sdl_v.h" > + + @@ -1787,6 +1799,10 @@ RelativePath=".\..\src\string_func.h" > + + @@ -2315,6 +2331,10 @@ RelativePath=".\..\src\roadveh_gui.cpp" > + + @@ -2695,6 +2715,10 @@ RelativePath=".\..\src\roadveh_cmd.cpp" > + + diff --git a/source.list b/source.list index 3b36f0ee0f..27535eb1a1 100644 --- a/source.list +++ b/source.list @@ -30,6 +30,7 @@ dedicated.cpp departures.cpp depot.cpp disaster_vehicle.cpp +dock.cpp driver.cpp economy.cpp effectvehicle.cpp @@ -197,6 +198,7 @@ direction_func.h direction_type.h disaster_vehicle.h music/dmusic.h +dock_base.h driver.h economy_base.h economy_func.h diff --git a/src/base_station_base.h b/src/base_station_base.h index 6d6b20ba3c..1db167ade6 100644 --- a/src/base_station_base.h +++ b/src/base_station_base.h @@ -156,6 +156,16 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { return (this->facilities & ~FACIL_WAYPOINT) != 0; } + /** + * Check whether the base station has given facilities. + * @param facilities The facilities to check. + * @return True if station has at least one of the given \a facilities. + */ + inline bool HasFacilities(StationFacility facilities) const + { + return (this->facilities & facilities) != 0; + } + static void PostDestructor(size_t index); }; diff --git a/src/dock.cpp b/src/dock.cpp new file mode 100644 index 0000000000..e37ca33d06 --- /dev/null +++ b/src/dock.cpp @@ -0,0 +1,37 @@ +/* $Id: dock.cpp $ */ + +/* +* This file is part of OpenTTD. +* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. +* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . +*/ + +/** @file dock.cpp Implementation of the dock base class. */ + +#include "stdafx.h" +#include "core/pool_func.hpp" +#include "dock_base.h" +#include "station_base.h" + +/** The pool of docks. */ +DockPool _dock_pool("Dock"); +INSTANTIATE_POOL_METHODS(Dock) + +/** +* Find a dock at a given tile. +* @param tile Tile with a dock. +* @return The dock in the given tile. +* @pre IsDockTile() +*/ +/* static */ Dock *Dock::GetByTile(TileIndex tile) +{ + const Station *st = Station::GetByTile(tile); + + for (Dock *d = st->GetPrimaryDock();; d = d->next) { + if (d->sloped == tile || d->flat == tile) return d; + assert(d->next != NULL); + } + + NOT_REACHED(); +} diff --git a/src/dock_base.h b/src/dock_base.h new file mode 100644 index 0000000000..95dae6e9ed --- /dev/null +++ b/src/dock_base.h @@ -0,0 +1,40 @@ +/* $Id: dock_base.h $ */ + +/* +* This file is part of OpenTTD. +* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. +* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . +*/ + +/** @file dock_base.h Base class for docks. */ + +#ifndef DOCK_BASE_H +#define DOCK_BASE_H + +#include "station_type.h" +#include "tile_type.h" +#include "core/pool_type.hpp" + +typedef Pool DockPool; +extern DockPool _dock_pool; + +/** A Dock structure. */ +struct Dock : DockPool::PoolItem<&_dock_pool> { + TileIndex sloped; ///< The sloped tile of the dock. + TileIndex flat; ///< Position on the map of the flat tile. + Dock *next; ///< Next dock of the given type at this station. + + Dock(TileIndex s = INVALID_TILE, TileIndex f = INVALID_TILE) : sloped(s), flat(f), next(NULL) { } + + ~Dock() {} + + inline Dock *GetNextDock() const { return this->next; } + + static Dock *GetByTile(TileIndex tile); +}; + +#define FOR_ALL_DOCKS_FROM(var, start) FOR_ALL_ITEMS_FROM(Dock, dock_index, var, start) +#define FOR_ALL_DOCKS(var) FOR_ALL_DOCKS_FROM(var, 0) + +#endif /* DOCK_BASE_H */ diff --git a/src/lang/english.txt b/src/lang/english.txt index 5b399e60de..3965eafb87 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4959,6 +4959,7 @@ STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Too many STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Too many lorry stations STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Too close to another station/loading area STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Too close to another dock +STR_ERROR_TOO_MANY_DOCKS :{WHITE}Too many docks STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Too close to another airport STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Can't rename station... STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... this is a town owned road diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 510bc34ab9..9152ad8be3 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -2525,7 +2525,7 @@ bool ProcessOrders(Vehicle *v) /* If it is unchanged, keep it. */ if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) && - (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) { + (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->HasFacilities(FACIL_DOCK))) { return false; } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index d9395690ed..b2ce60b052 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -30,6 +30,7 @@ #include "../station_base.h" #include "../waypoint_base.h" #include "../roadstop_base.h" +#include "../dock_base.h" #include "../tunnelbridge_map.h" #include "../pathfinder/yapf/yapf_cache.h" #include "../elrail_func.h" @@ -728,9 +729,9 @@ bool AfterLoadGame() /* no station is determined by 'tile == INVALID_TILE' now (instead of '0') */ Station *st; FOR_ALL_STATIONS(st) { - if (st->airport.tile == 0) st->airport.tile = INVALID_TILE; - if (st->dock_tile == 0) st->dock_tile = INVALID_TILE; - if (st->train_station.tile == 0) st->train_station.tile = INVALID_TILE; + if (st->airport.tile == 0) st->airport.tile = INVALID_TILE; + if (st->dock_station.tile == 0) st->dock_station.tile = INVALID_TILE; + if (st->train_station.tile == 0) st->train_station.tile = INVALID_TILE; } /* the same applies to Company::location_of_HQ */ @@ -877,7 +878,7 @@ bool AfterLoadGame() if (st->airport.tile == INVALID_TILE) continue; StringID err = INVALID_STRING_ID; if (st->airport.type == 9) { - if (st->dock_tile != INVALID_TILE && IsOilRig(st->dock_tile)) { + if (st->dock_station.tile != INVALID_TILE && IsOilRig(st->dock_station.tile)) { /* this airport is probably an oil rig, not a huge airport */ } else { err = STR_GAME_SAVELOAD_ERROR_HUGE_AIRPORTS_PRESENT; @@ -904,7 +905,7 @@ bool AfterLoadGame() Aircraft *v; FOR_ALL_AIRCRAFT(v) { Station *st = GetTargetAirportIfValid(v); - if (st != NULL && ((st->dock_tile != INVALID_TILE && IsOilRig(st->dock_tile)) || st->airport.type == AT_OILRIG)) { + if (st != NULL && ((st->dock_station.tile != INVALID_TILE && IsOilRig(st->dock_station.tile)) || st->airport.type == AT_OILRIG)) { /* aircraft is on approach to an oil rig, bail out now */ SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_HELI_OILRIG_BUG); /* Restore the signals */ @@ -1015,6 +1016,26 @@ bool AfterLoadGame() } } + if (SlXvIsFeatureMissing(XSLFI_MULTIPLE_DOCKS)) { + /* Dock type has changed. */ + Station *st; + FOR_ALL_STATIONS(st) { + if (st->dock_station.tile == INVALID_TILE) continue; + assert(Dock::CanAllocateItem()); + if (IsOilRig(st->dock_station.tile)) { + /* Set dock station tile to dest tile instead of station. */ + st->docks = new Dock(st->dock_station.tile, st->dock_station.tile + ToTileIndexDiff({ 1, 0 })); + } else if (IsDock(st->dock_station.tile)) { + /* A normal two-tiles dock. */ + st->docks = new Dock(st->dock_station.tile, TileAddByDiagDir(st->dock_station.tile, GetDockDirection(st->dock_station.tile))); + } else if (IsBuoy(st->dock_station.tile)) { + /* A buoy. */ + } else { + NOT_REACHED(); + } + } + } + for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_STATION: { diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index eebf8dd91c..a0861ab7a1 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -78,6 +78,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_CHUNNEL, XSCF_NULL, 1, 1, "chunnel", NULL, NULL, "TUNN" }, { XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 1, 1, "scheduled_dispatch", NULL, NULL, NULL }, { XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", NULL, NULL, NULL }, + { XSLFI_MULTIPLE_DOCKS, XSCF_NULL, 1, 1, "multiple_docks", NULL, NULL, "DOCK" }, { XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index dbd0b7e7c8..89c84fe346 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -52,6 +52,7 @@ enum SlXvFeatureIndex { XSLFI_CHUNNEL, ///< Tunnels under water (channel tunnel) XSLFI_SCHEDULED_DISPATCH, ///< Scheduled vehicle dispatching XSLFI_MORE_TOWN_GROWTH_RATES, ///< More town growth rates + XSLFI_MULTIPLE_DOCKS, ///< Multiple docks XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 0c57166816..907f4b2c45 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -728,7 +728,7 @@ static const OldChunks station_chunk[] = { OCL_NULL( 4 ), ///< bus/lorry tile OCL_SVAR( OC_TILE, Station, train_station.tile ), OCL_SVAR( OC_TILE, Station, airport.tile ), - OCL_SVAR( OC_TILE, Station, dock_tile ), + OCL_SVAR( OC_TILE, Station, dock_station.tile), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Station, train_station.w ), OCL_NULL( 1 ), ///< sort-index, no longer in use diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 2b49459359..f4a2cbc1d5 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -24,6 +24,7 @@ #include "../stdafx.h" #include "../debug.h" #include "../station_base.h" +#include "../dock_base.h" #include "../thread/thread.h" #include "../town.h" #include "../network/network.h" @@ -1344,6 +1345,7 @@ static size_t ReferenceToInt(const void *obj, SLRefType rt) case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1; case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1; case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1; + case REF_DOCKS: return ((const Dock*)obj)->index + 1; default: NOT_REACHED(); } } @@ -1409,6 +1411,10 @@ static void *IntToReference(size_t index, SLRefType rt) if (RoadStop::IsValidID(index)) return RoadStop::Get(index); SlErrorCorrupt("Referencing invalid RoadStop"); + case REF_DOCKS: + if (Dock::IsValidID(index)) return Dock::Get(index); + SlErrorCorrupt("Referencing invalid Dock"); + case REF_ENGINE_RENEWS: if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index); SlErrorCorrupt("Referencing invalid EngineRenew"); diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index c866919d39..08a19b0690 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -81,19 +81,20 @@ struct NullStruct { /** Type of reference (#SLE_REF, #SLE_CONDREF). */ enum SLRefType { - REF_ORDER = 0, ///< Load/save a reference to an order. - REF_VEHICLE = 1, ///< Load/save a reference to a vehicle. - REF_STATION = 2, ///< Load/save a reference to a station. - REF_TOWN = 3, ///< Load/save a reference to a town. - REF_VEHICLE_OLD = 4, ///< Load/save an old-style reference to a vehicle (for pre-4.4 savegames). - REF_ROADSTOPS = 5, ///< Load/save a reference to a bus/truck stop. - REF_ENGINE_RENEWS = 6, ///< Load/save a reference to an engine renewal (autoreplace). - REF_CARGO_PACKET = 7, ///< Load/save a reference to a cargo packet. - REF_ORDERLIST = 8, ///< Load/save a reference to an orderlist. - REF_STORAGE = 9, ///< Load/save a reference to a persistent storage. - REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph. - REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job. - REF_TEMPLATE_VEHICLE = 12, ///< Load/save a reference to a template vehicle + REF_ORDER = 0, ///< Load/save a reference to an order. + REF_VEHICLE = 1, ///< Load/save a reference to a vehicle. + REF_STATION = 2, ///< Load/save a reference to a station. + REF_TOWN = 3, ///< Load/save a reference to a town. + REF_VEHICLE_OLD = 4, ///< Load/save an old-style reference to a vehicle (for pre-4.4 savegames). + REF_ROADSTOPS = 5, ///< Load/save a reference to a bus/truck stop. + REF_ENGINE_RENEWS = 6, ///< Load/save a reference to an engine renewal (autoreplace). + REF_CARGO_PACKET = 7, ///< Load/save a reference to a cargo packet. + REF_ORDERLIST = 8, ///< Load/save a reference to an orderlist. + REF_STORAGE = 9, ///< Load/save a reference to a persistent storage. + REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph. + REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job. + REF_TEMPLATE_VEHICLE = 12, ///< Load/save a reference to a template vehicle + REF_DOCKS = 13, ///< Load/save a reference to a dock. }; /** Highest possible savegame version. */ diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index af95c4944a..20e4b111eb 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -13,6 +13,7 @@ #include "../station_base.h" #include "../waypoint_base.h" #include "../roadstop_base.h" +#include "../dock_base.h" #include "../vehicle_base.h" #include "../newgrf_station.h" @@ -123,6 +124,11 @@ void AfterLoadStations() Station *sta = Station::From(st); for (const RoadStop *rs = sta->bus_stops; rs != NULL; rs = rs->next) sta->bus_station.Add(rs->xy); for (const RoadStop *rs = sta->truck_stops; rs != NULL; rs = rs->next) sta->truck_station.Add(rs->xy); + + for (const Dock *d = sta->docks; d != NULL; d = d->next) { + sta->dock_station.Add(d->sloped); + sta->dock_station.Add(d->flat); + } } StationUpdateCachedTriggers(st); @@ -166,6 +172,14 @@ static const SaveLoad _roadstop_desc[] = { SLE_END() }; +static const SaveLoad _dock_desc[] = { + SLE_VAR(Dock, sloped, SLE_UINT32), + SLE_VAR(Dock, flat, SLE_UINT32), + SLE_REF(Dock, next, REF_DOCKS), + + SLE_END() +}; + static const SaveLoad _old_station_desc[] = { SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Station, xy, SLE_UINT32, 6, SL_MAX_VERSION), @@ -174,8 +188,8 @@ static const SaveLoad _old_station_desc[] = { SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Station, airport.tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(Station, dock_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Station, dock_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(Station, dock_station.tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(Station, dock_station.tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_REF(Station, town, REF_TOWN), SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16), SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, 2, SL_MAX_VERSION), @@ -425,7 +439,8 @@ static const SaveLoad _station_desc[] = { SLE_REF(Station, bus_stops, REF_ROADSTOPS), SLE_REF(Station, truck_stops, REF_ROADSTOPS), - SLE_VAR(Station, dock_tile, SLE_UINT32), + SLE_CONDVAR_X(Station, dock_station.tile, SLE_UINT32, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 0, 0)), + SLE_CONDREF_X(Station, docks, REF_DOCKS, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 1)), SLE_VAR(Station, airport.tile, SLE_UINT32), SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, 140, SL_MAX_VERSION), SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, 140, SL_MAX_VERSION), @@ -638,8 +653,38 @@ static void Ptrs_ROADSTOP() } } +static void Save_DOCK() +{ + Dock *d; + + FOR_ALL_DOCKS(d) { + SlSetArrayIndex(d->index); + SlObject(d, _dock_desc); + } +} + +static void Load_DOCK() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + Dock *d = new (index) Dock(); + + SlObject(d, _dock_desc); + } +} + +static void Ptrs_DOCK() +{ + Dock *d; + FOR_ALL_DOCKS(d) { + SlObject(d, _dock_desc); + } +} + extern const ChunkHandler _station_chunk_handlers[] = { { 'STNS', NULL, Load_STNS, Ptrs_STNS, NULL, CH_ARRAY }, { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, NULL, CH_ARRAY }, - { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, NULL, CH_ARRAY | CH_LAST}, + { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, NULL, CH_ARRAY}, + { 'DOCK', Save_DOCK, Load_DOCK, Ptrs_DOCK, NULL, CH_ARRAY | CH_LAST}, }; diff --git a/src/script/api/ai/ai_station.hpp.sq b/src/script/api/ai/ai_station.hpp.sq index af7012d354..9248493195 100644 --- a/src/script/api/ai/ai_station.hpp.sq +++ b/src/script/api/ai/ai_station.hpp.sq @@ -34,10 +34,10 @@ void SQAIStation_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); - ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_STATIONS_LOADING, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_TRUCK_STOPS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_BUS_STOPS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); + ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_DOCKS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT, ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN); ScriptError::RegisterErrorMapString(ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, "ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION"); diff --git a/src/script/api/game/game_station.hpp.sq b/src/script/api/game/game_station.hpp.sq index e3a7425caa..fa5f98e40c 100644 --- a/src/script/api/game/game_station.hpp.sq +++ b/src/script/api/game/game_station.hpp.sq @@ -34,10 +34,10 @@ void SQGSStation_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); - ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_STATIONS_LOADING, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_TRUCK_STOPS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_BUS_STOPS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); + ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_DOCKS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT, ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN); ScriptError::RegisterErrorMapString(ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, "ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION"); diff --git a/src/script/api/script_order.cpp b/src/script/api/script_order.cpp index 676262dc77..20ba33e5fc 100644 --- a/src/script/api/script_order.cpp +++ b/src/script/api/script_order.cpp @@ -17,6 +17,7 @@ #include "../../debug.h" #include "../../vehicle_base.h" #include "../../roadstop_base.h" +#include "../../dock_base.h" #include "../../depot_base.h" #include "../../station_base.h" #include "../../waypoint_base.h" @@ -260,8 +261,8 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr TILE_AREA_LOOP(t, st->train_station) { if (st->TileBelongsToRailStation(t)) return t; } - } else if (st->dock_tile != INVALID_TILE) { - return st->dock_tile; + } else if (st->docks != NULL) { + return st->docks->flat; } else if (st->bus_stops != NULL) { return st->bus_stops->xy; } else if (st->truck_stops != NULL) { diff --git a/src/script/api/script_station.hpp b/src/script/api/script_station.hpp index 8561cd9bdd..05a555a30b 100644 --- a/src/script/api/script_station.hpp +++ b/src/script/api/script_station.hpp @@ -30,10 +30,10 @@ public: ERR_STATION_BASE = ScriptError::ERR_CAT_STATION << ScriptError::ERR_CAT_BIT_SIZE, /** The station is build too close to another station, airport or dock */ - ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, // [STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT, STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION, STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK] + ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, // [STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT, STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION] /** There are too many stations, airports and docks in the game */ - ERR_STATION_TOO_MANY_STATIONS, // [STR_ERROR_TOO_MANY_STATIONS_LOADING, STR_ERROR_TOO_MANY_TRUCK_STOPS, STR_ERROR_TOO_MANY_BUS_STOPS] + ERR_STATION_TOO_MANY_STATIONS, // [STR_ERROR_TOO_MANY_STATIONS_LOADING, STR_ERROR_TOO_MANY_TRUCK_STOPS, STR_ERROR_TOO_MANY_BUS_STOPS, STR_ERROR_TOO_MANY_DOCKS] /** There are too many stations, airports of docks in a town */ ERR_STATION_TOO_MANY_STATIONS_IN_TOWN, // [STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT] diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index d57054af8d..41f2fe7343 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -11,6 +11,7 @@ #include "stdafx.h" #include "ship.h" +#include "dock_base.h" #include "landscape.h" #include "timetable.h" #include "news_func.h" @@ -285,13 +286,48 @@ void Ship::PlayLeaveStationSound() const PlayShipSound(this); } +/** + * Of all the docks a station has, return the best destination for a ship. + * @param v The ship. + * @param st Station the ship \a v is heading for. + * @return The free and closest (if none is free, just closest) dock of station \a st to ship \a v. + */ +const Dock* GetBestDock(const Ship *v, const Station *st) +{ + assert(st != NULL && st->HasFacilities(FACIL_DOCK) && st->docks != NULL); + if (st->docks->next == NULL) return st->docks; + + Dock *best_dock = NULL; + uint best_distance = UINT_MAX; + + for (Dock *dock = st->docks; dock != NULL; dock = dock->next) { + uint new_distance = DistanceManhattan(v->tile, dock->flat); + + if (new_distance < best_distance) { + best_dock = dock; + best_distance = new_distance; + } + } + + assert(best_dock != NULL); + + return best_dock; +} + TileIndex Ship::GetOrderStationLocation(StationID station) { if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION; const Station *st = Station::Get(station); - if (st->dock_tile != INVALID_TILE) { - return TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); + if (st->HasFacilities(FACIL_DOCK)) { + if (st->docks == NULL) { + return st->xy; // A buoy + } else { + const Dock* dock = GetBestDock(this, st); + + DiagDirection direction = DiagdirBetweenTiles(dock->sloped, dock->flat); + return dock->flat + TileOffsByDiagDir(direction); + } } else { this->IncrementRealOrderIndex(); return 0; diff --git a/src/station.cpp b/src/station.cpp index f0124f1f99..e2597c8442 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -22,6 +22,7 @@ #include "core/pool_func.hpp" #include "station_base.h" #include "roadstop_base.h" +#include "dock_base.h" #include "industry.h" #include "core/random_func.hpp" #include "linkgraph/linkgraph.h" @@ -59,7 +60,7 @@ Station::Station(TileIndex tile) : SpecializedStation(tile), bus_station(INVALID_TILE, 0, 0), truck_station(INVALID_TILE, 0, 0), - dock_tile(INVALID_TILE), + dock_station(INVALID_TILE, 0, 0), indtype(IT_INVALID), time_since_load(255), time_since_unload(255), @@ -280,10 +281,10 @@ uint Station::GetCatchmentRadius() const if (this->bus_stops != NULL) ret = max(ret, CA_BUS); if (this->truck_stops != NULL) ret = max(ret, CA_TRUCK); if (this->train_station.tile != INVALID_TILE) ret = max(ret, CA_TRAIN); - if (this->dock_tile != INVALID_TILE) ret = max(ret, CA_DOCK); + if (this->docks != NULL) ret = max(ret, CA_DOCK); if (this->airport.tile != INVALID_TILE) ret = max(ret, this->airport.GetSpec()->catchment); } else { - if (this->bus_stops != NULL || this->truck_stops != NULL || this->train_station.tile != INVALID_TILE || this->dock_tile != INVALID_TILE || this->airport.tile != INVALID_TILE) { + if (this->bus_stops != NULL || this->truck_stops != NULL || this->train_station.tile != INVALID_TILE || this->docks != NULL || this->airport.tile != INVALID_TILE) { ret = CA_UNMODIFIED; } } diff --git a/src/station_base.h b/src/station_base.h index c9fa6f8cb3..1b752924d8 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -458,9 +458,10 @@ public: TileArea bus_station; ///< Tile area the bus 'station' part covers RoadStop *truck_stops; ///< All the truck stops TileArea truck_station; ///< Tile area the truck 'station' part covers + Dock *docks; ///< All the docks + TileArea dock_station; ///< Tile area dock 'station' part covers Airport airport; ///< Tile area the airport covers - TileIndex dock_tile; ///< The location of the dock IndustryType indtype; ///< Industry type to get the name from @@ -490,6 +491,8 @@ public: void RecomputeIndustriesNear(); static void RecomputeIndustriesNearForAll(); + Dock *GetPrimaryDock() const { return docks; } + uint GetCatchmentRadius() const; Rect GetCatchmentRectUsingRadius(uint radius) const; inline Rect GetCatchmentRect() const diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 9c8ec41dce..cfb464f09f 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -38,6 +38,7 @@ #include "elrail_func.h" #include "station_base.h" #include "roadstop_base.h" +#include "dock_base.h" #include "newgrf_railtype.h" #include "waypoint_base.h" #include "waypoint_func.h" @@ -399,7 +400,7 @@ void Station::GetTileArea(TileArea *ta, StationType type) const case STATION_DOCK: case STATION_OILRIG: - ta->tile = this->dock_tile; + *ta = this->dock_station; break; default: NOT_REACHED(); @@ -2599,41 +2600,43 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR; - DiagDirection direction = GetInclinedSlopeDirection(GetTileSlope(tile)); + TileIndex slope_tile = tile; + + DiagDirection direction = GetInclinedSlopeDirection(GetTileSlope(slope_tile)); if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); direction = ReverseDiagDir(direction); + TileIndex flat_tile = slope_tile + TileOffsByDiagDir(direction); + /* Docks cannot be placed on rapids */ - if (HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); + if (HasTileWaterGround(slope_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); - CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags); + CommandCost ret = CheckIfAuthorityAllowsNewStation(slope_tile, flags); if (ret.Failed()) return ret; - if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); + if (IsBridgeAbove(slope_tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); - ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); + ret = DoCommand(slope_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; - TileIndex tile_cur = tile + TileOffsByDiagDir(direction); - - if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) { + if (!IsTileType(flat_tile, MP_WATER) || !IsTileFlat(flat_tile)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } - if (IsBridgeAbove(tile_cur)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); + if (IsBridgeAbove(flat_tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); /* Get the water class of the water tile before it is cleared.*/ - WaterClass wc = GetWaterClass(tile_cur); + WaterClass wc = GetWaterClass(flat_tile); - ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR); + ret = DoCommand(flat_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; - tile_cur += TileOffsByDiagDir(direction); - if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) { + TileIndex adjacent_tile = flat_tile + TileOffsByDiagDir(direction); + if (!IsTileType(adjacent_tile, MP_WATER) || !IsTileFlat(adjacent_tile)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } - TileArea dock_area = TileArea(tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]), + TileArea dock_area = TileArea(slope_tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]), _dock_w_chk[direction], _dock_h_chk[direction]); /* middle */ @@ -2644,14 +2647,20 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Distant join */ if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join); + if (!Dock::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_DOCKS); + ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK); if (ret.Failed()) return ret; - if (st != NULL && st->dock_tile != INVALID_TILE) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK); - if (flags & DC_EXEC) { - st->dock_tile = tile; - st->AddFacility(FACIL_DOCK, tile); + /* Create the dock and insert it into the list of docks. */ + Dock *dock = new Dock(slope_tile, flat_tile); + dock->next = st->docks; + st->docks = dock; + + st->dock_station.Add(slope_tile); + st->dock_station.Add(flat_tile); + st->AddFacility(FACIL_DOCK, slope_tile); st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY); @@ -2663,7 +2672,7 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Company::Get(st->owner)->infrastructure.station += 2; DirtyCompanyInfrastructureWindows(st->owner); - MakeDock(tile, st->owner, st->index, direction, wc); + MakeDock(slope_tile, st->owner, st->index, direction, wc); st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); @@ -2689,10 +2698,14 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; - TileIndex docking_location = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); + Dock *removing_dock = Dock::GetByTile(tile); + assert(removing_dock != NULL); + + TileIndex tile1 = removing_dock->sloped; + TileIndex tile2 = removing_dock->flat; - TileIndex tile1 = st->dock_tile; - TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1)); + DiagDirection direction = DiagdirBetweenTiles(removing_dock->sloped, removing_dock->flat); + TileIndex docking_location = removing_dock->flat + TileOffsByDiagDir(direction); ret = EnsureNoVehicleOnGround(tile1); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2); @@ -2700,6 +2713,23 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) if (flags & DC_EXEC) { ZoningMarkDirtyStationCoverageArea(st); + + if (st->docks == removing_dock) { + /* The first dock in the list is removed. */ + st->docks = removing_dock->next; + /* Last dock is removed. */ + if (st->docks == NULL) { + st->facilities &= ~FACIL_DOCK; + } + } else { + /* Tell the predecessor in the list to skip this dock. */ + Dock *pred = st->docks; + while (pred->next != removing_dock) pred = pred->next; + pred->next = removing_dock->next; + } + + delete removing_dock; + DoClearSquare(tile1); MarkTileDirtyByTile(tile1); MakeWaterKeepingClass(tile2, st->owner); @@ -2707,8 +2737,11 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) st->rect.AfterRemoveTile(st, tile1); st->rect.AfterRemoveTile(st, tile2); - st->dock_tile = INVALID_TILE; - st->facilities &= ~FACIL_DOCK; + st->dock_station.Clear(); + for (Dock *dock = st->docks; dock != NULL; dock = dock->next) { + st->dock_station.Add(dock->flat); + st->dock_station.Add(dock->sloped); + } Company::Get(st->owner)->infrastructure.station -= 2; DirtyCompanyInfrastructureWindows(st->owner); @@ -4028,8 +4061,17 @@ void BuildOilRig(TileIndex tile) st->owner = OWNER_NONE; st->airport.type = AT_OILRIG; st->airport.Add(tile); - st->dock_tile = tile; - st->facilities = FACIL_AIRPORT | FACIL_DOCK; + st->dock_station.tile = tile; + st->facilities = FACIL_AIRPORT; + + if (!Dock::CanAllocateItem()) { + DEBUG(misc, 0, "Can't allocate dock for oilrig at 0x%X, reverting to oilrig with airport only", tile); + } else { + st->docks = new Dock(tile, tile + ToTileIndexDiff({1, 0})); + st->dock_station.tile = tile; + st->facilities |= FACIL_DOCK; + } + st->build_date = _date; st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE); @@ -4047,7 +4089,11 @@ void DeleteOilRig(TileIndex tile) MakeWaterKeepingClass(tile, OWNER_NONE); - st->dock_tile = INVALID_TILE; + st->dock_station.tile = INVALID_TILE; + if (st->docks != NULL) { + delete st->docks; + st->docks = NULL; + } st->airport.Clear(); st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK); st->airport.flags = 0; diff --git a/src/station_type.h b/src/station_type.h index f5e7a8af84..038ab1abbf 100644 --- a/src/station_type.h +++ b/src/station_type.h @@ -19,10 +19,12 @@ typedef uint16 StationID; typedef uint16 RoadStopID; +typedef uint16 DockID; struct BaseStation; struct Station; struct RoadStop; +struct Dock; struct StationSpec; struct Waypoint;