diff options
author | peter1138 <peter1138@openttd.org> | 2019-03-11 10:37:47 +0000 |
---|---|---|
committer | Niels Martin Hansen <nielsm@indvikleren.dk> | 2019-06-30 16:46:32 +0200 |
commit | f538179878370b3bec8bf1575dc30c1377461ebc (patch) | |
tree | 890738c37245a49eb2a8ad52f4afb805baaa9d42 /src/station_cmd.cpp | |
parent | f1c39153413b07a964dfde8fd9d6310f0da4987b (diff) | |
download | openttd-f538179878370b3bec8bf1575dc30c1377461ebc.tar.xz |
Feature: Multi-tile docks and docking points.
Diffstat (limited to 'src/station_cmd.cpp')
-rw-r--r-- | src/station_cmd.cpp | 165 |
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); |