summaryrefslogtreecommitdiff
path: root/src/station_cmd.cpp
diff options
context:
space:
mode:
authorpeter1138 <peter1138@openttd.org>2019-03-11 10:37:47 +0000
committerNiels Martin Hansen <nielsm@indvikleren.dk>2019-06-30 16:46:32 +0200
commitf538179878370b3bec8bf1575dc30c1377461ebc (patch)
tree890738c37245a49eb2a8ad52f4afb805baaa9d42 /src/station_cmd.cpp
parentf1c39153413b07a964dfde8fd9d6310f0da4987b (diff)
downloadopenttd-f538179878370b3bec8bf1575dc30c1377461ebc.tar.xz
Feature: Multi-tile docks and docking points.
Diffstat (limited to 'src/station_cmd.cpp')
-rw-r--r--src/station_cmd.cpp165
1 files changed, 139 insertions, 26 deletions
diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
index 9dbe356e7..a7d986676 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -56,6 +56,7 @@
#include "linkgraph/linkgraph_base.h"
#include "linkgraph/refresh.h"
#include "widgets/station_widget.h"
+#include "tunnelbridge_map.h"
#include "table/strings.h"
@@ -401,7 +402,7 @@ void Station::GetTileArea(TileArea *ta, StationType type) const
case STATION_DOCK:
case STATION_OILRIG:
- ta->tile = this->dock_tile;
+ *ta = this->docking_station;
break;
default: NOT_REACHED();
@@ -1459,16 +1460,14 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32
return cost;
}
-static void MakeRailStationAreaSmaller(BaseStation *st)
+static TileArea MakeStationAreaSmaller(BaseStation *st, TileArea ta, bool (*func)(BaseStation *, TileIndex))
{
- TileArea ta = st->train_station;
-
restart:
/* too small? */
if (ta.w != 0 && ta.h != 0) {
/* check the left side, x = constant, y changes */
- for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(0, i));) {
+ for (uint i = 0; !func(st, ta.tile + TileDiffXY(0, i));) {
/* the left side is unused? */
if (++i == ta.h) {
ta.tile += TileDiffXY(1, 0);
@@ -1478,7 +1477,7 @@ restart:
}
/* check the right side, x = constant, y changes */
- for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(ta.w - 1, i));) {
+ for (uint i = 0; !func(st, ta.tile + TileDiffXY(ta.w - 1, i));) {
/* the right side is unused? */
if (++i == ta.h) {
ta.w--;
@@ -1487,7 +1486,7 @@ restart:
}
/* check the upper side, y = constant, x changes */
- for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, 0));) {
+ for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, 0));) {
/* the left side is unused? */
if (++i == ta.w) {
ta.tile += TileDiffXY(0, 1);
@@ -1497,7 +1496,7 @@ restart:
}
/* check the lower side, y = constant, x changes */
- for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, ta.h - 1));) {
+ for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, ta.h - 1));) {
/* the left side is unused? */
if (++i == ta.w) {
ta.h--;
@@ -1508,7 +1507,28 @@ restart:
ta.Clear();
}
- st->train_station = ta;
+ return ta;
+}
+
+static bool TileBelongsToRailStation(BaseStation *st, TileIndex tile)
+{
+ return st->TileBelongsToRailStation(tile);
+}
+
+static void MakeRailStationAreaSmaller(BaseStation *st)
+{
+ st->train_station = MakeStationAreaSmaller(st, st->train_station, TileBelongsToRailStation);
+}
+
+static bool TileBelongsToShipStation(BaseStation *st, TileIndex tile)
+{
+ return IsDockTile(tile) && GetStationIndex(tile) == st->index;
+}
+
+static void MakeShipStationAreaSmaller(Station *st)
+{
+ st->ship_station = MakeStationAreaSmaller(st, st->ship_station, TileBelongsToShipStation);
+ UpdateStationDockingTiles(st);
}
/**
@@ -2553,10 +2573,9 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
if (ret.Failed()) return ret;
- if (st != nullptr && st->dock_tile != INVALID_TILE) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK);
-
if (flags & DC_EXEC) {
- st->dock_tile = tile;
+ st->ship_station.Add(tile);
+ st->ship_station.Add(tile + TileOffsByDiagDir(direction));
st->AddFacility(FACIL_DOCK, tile);
st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
@@ -2569,6 +2588,7 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
Company::Get(st->owner)->infrastructure.station += 2;
MakeDock(tile, st->owner, st->index, direction, wc);
+ UpdateStationDockingTiles(st);
st->AfterStationTileSetChange(true, STATION_DOCK);
}
@@ -2576,6 +2596,63 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
}
+void RemoveDockingTile(TileIndex t)
+{
+ for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
+ TileIndex tile = t + TileOffsByDiagDir(d);
+ if (!IsValidTile(tile)) continue;
+
+ if (IsTileType(tile, MP_STATION)) {
+ UpdateStationDockingTiles(Station::GetByTile(tile));
+ } else if (IsTileType(tile, MP_INDUSTRY)) {
+ UpdateStationDockingTiles(Industry::GetByTile(tile)->neutral_station);
+ }
+ }
+}
+
+/**
+ * Clear docking tile status from tiles around a removed dock, if the tile has
+ * no neighbours which would keep it as a docking tile.
+ * @param tile Ex-dock tile to check.
+ */
+void ClearDockingTilesCheckingNeighbours(TileIndex tile)
+{
+ assert(IsValidTile(tile));
+
+ /* Clear and maybe re-set docking tile */
+ for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
+ TileIndex docking_tile = tile + TileOffsByDiagDir(d);
+ if (!IsValidTile(docking_tile)) continue;
+
+ if (IsPossibleDockingTile(docking_tile)) {
+ SetDockingTile(docking_tile, false);
+ CheckForDockingTile(docking_tile);
+ }
+ }
+}
+
+/**
+ * Find the part of a dock that is land-based
+ * @param t Dock tile to find land part of
+ * @return tile of land part of dock
+ */
+static TileIndex FindDockLandPart(TileIndex t)
+{
+ assert(IsDockTile(t));
+
+ StationGfx gfx = GetStationGfx(t);
+ if (gfx < GFX_DOCK_BASE_WATER_PART) return t;
+
+ for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
+ TileIndex tile = t + TileOffsByDiagDir(d);
+ if (!IsValidTile(tile)) continue;
+ if (!IsDockTile(tile)) continue;
+ if (GetStationGfx(tile) < GFX_DOCK_BASE_WATER_PART && tile + TileOffsByDiagDir(GetDockDirection(tile)) == t) return tile;
+ }
+
+ return INVALID_TILE;
+}
+
/**
* Remove a dock
* @param tile TileIndex been queried
@@ -2588,9 +2665,10 @@ 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)));
+ if (!IsDockTile(tile)) return CMD_ERROR;
- TileIndex tile1 = st->dock_tile;
+ TileIndex tile1 = FindDockLandPart(tile);
+ if (tile1 == INVALID_TILE) return CMD_ERROR;
TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
ret = EnsureNoVehicleOnGround(tile1);
@@ -2605,26 +2683,34 @@ 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;
+ MakeShipStationAreaSmaller(st);
+ if (st->ship_station.tile == INVALID_TILE) {
+ st->ship_station.Clear();
+ st->docking_station.Clear();
+ st->facilities &= ~FACIL_DOCK;
+ }
Company::Get(st->owner)->infrastructure.station -= 2;
st->AfterStationTileSetChange(false, STATION_DOCK);
+ ClearDockingTilesCheckingNeighbours(tile1);
+ ClearDockingTilesCheckingNeighbours(tile2);
+
/* All ships that were going to our station, can't go to it anymore.
* Just clear the order, then automatically the next appropriate order
* will be selected and in case of no appropriate order it will just
* wander around the world. */
- Ship *s;
- FOR_ALL_SHIPS(s) {
- if (s->current_order.IsType(OT_LOADING) && s->tile == docking_location) {
- s->LeaveStation();
- }
+ if (!(st->facilities & FACIL_DOCK)) {
+ Ship *s;
+ FOR_ALL_SHIPS(s) {
+ if (s->current_order.IsType(OT_LOADING) && s->current_order.GetDestination() == st->index) {
+ s->LeaveStation();
+ }
- if (s->dest_tile == docking_location) {
- s->SetDestTile(0);
- s->current_order.Free();
+ if (s->current_order.IsType(OT_GOTO_STATION) && s->current_order.GetDestination() == st->index) {
+ s->SetDestTile(s->GetOrderStationLocation(st->index));
+ }
}
}
}
@@ -2873,7 +2959,7 @@ draw_default_foundation:
} else {
assert(IsDock(ti->tile));
TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
- WaterClass wc = GetWaterClass(water_tile);
+ WaterClass wc = HasTileWaterClass(water_tile) ? GetWaterClass(water_tile) : WATER_CLASS_INVALID;
if (wc == WATER_CLASS_SEA) {
DrawShoreTile(ti->tileh);
} else {
@@ -3991,6 +4077,32 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc
return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id);
}
+void UpdateStationDockingTiles(Station *st)
+{
+ st->docking_station.Clear();
+
+ /* For neutral stations, start with the industry area instead of dock area */
+ const TileArea *area = st->industry != nullptr ? &st->industry->location : &st->ship_station;
+
+ if (area->tile == INVALID_TILE) return;
+
+ int x = TileX(area->tile);
+ int y = TileY(area->tile);
+
+ /* Expand the area by a tile on each side while
+ * making sure that we remain inside the map. */
+ int x2 = min(x + area->w + 1, MapSizeX());
+ int x1 = max(x - 1, 0);
+
+ int y2 = min(y + area->h + 1, MapSizeY());
+ int y1 = max(y - 1, 0);
+
+ TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1));
+ TILE_AREA_LOOP(tile, ta) {
+ if (IsValidTile(tile) && IsPossibleDockingTile(tile)) CheckForDockingTile(tile);
+ }
+}
+
void BuildOilRig(TileIndex tile)
{
if (!Station::CanAllocateItem()) {
@@ -4014,9 +4126,10 @@ void BuildOilRig(TileIndex tile)
st->owner = OWNER_NONE;
st->airport.type = AT_OILRIG;
st->airport.Add(tile);
- st->dock_tile = tile;
+ st->ship_station.Add(tile);
st->facilities = FACIL_AIRPORT | FACIL_DOCK;
st->build_date = _date;
+ UpdateStationDockingTiles(st);
st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);