Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Multi-tile depots #9577

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cbd39b3
Change: Add a depot for each airport that has a hangar.
J0anJosep Feb 19, 2024
20619ff
Change: Go to hangar orders store the DepotID instead of the StationID.
J0anJosep Aug 25, 2023
eee1a37
Change: Set the DepotID as the window number of WC_VEHICLE_DEPOT wind…
J0anJosep Aug 25, 2023
b842347
Change: Refactor some code in build_vehicle_gui.
J0anJosep Feb 19, 2024
5e2a733
Change: Set DepotID related window numbers to WC_BUILD_VEHICLE windows.
J0anJosep Aug 25, 2023
31df33f
Change: OrderBackups are indexed through DepotID instead of TileIndex.
J0anJosep Aug 25, 2023
b4273dd
Change: Move some bits in water tiles for alignment purposes.
J0anJosep May 10, 2023
a196fd6
Codechange: Add and use GetWaterTileClass.
J0anJosep Mar 27, 2021
cf1f68b
Change: Change rail depot type value in order to align bits.
J0anJosep May 10, 2023
06c883a
Codechange: Use bit alignment for detecting road, rail and water depots.
J0anJosep Dec 27, 2020
902197c
Prepare: Add some members to depot struct.
J0anJosep Apr 8, 2024
c04dfe2
Change: BuildDepotVehicleList through a DepotId instead of a TileIndex.
J0anJosep Apr 22, 2023
aaae344
Add: Settings for controlling depot spread.
J0anJosep Aug 25, 2023
0199f4b
Feature: Add a window for joining depots.
J0anJosep Aug 25, 2023
d63ab43
Feature: Highlight tiles of a depot and adjacent depot tiles when bui…
J0anJosep Aug 25, 2023
91aadfe
Add: Add new viewport place methods for rectangles with one side with…
J0anJosep Mar 31, 2021
f5cd247
Feature: Allow building depots by drag and drop and joining them if t…
J0anJosep Apr 8, 2024
abecea8
Add: Allow removing company rail depots in an area.
J0anJosep Aug 26, 2023
7ff6b24
Add: Adapt pathfinding in YAPF and NPF for depots.
J0anJosep Mar 4, 2023
30aea15
Change: Adapt some functions that located the depot with its tile.
J0anJosep May 10, 2023
8549cee
Change: Add additional rules for placing trains in depots according t…
J0anJosep Apr 1, 2021
fade935
Feature: Allow vehicle replacements even if new road or rail type is …
J0anJosep Aug 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 14 additions & 14 deletions docs/landscape.html
Expand Up @@ -520,7 +520,7 @@ <h3><a name="Landscape">Landscape</a></h3>
<li>m2 bit 11: opposite track is reserved, too</li>
</ul>
</li>
<li>m5 bit 7 set, bit 6 set: railway depot
<li>m5 bit 7 set, bit 6 clear: railway depot
<ul>
<li>m2: Depot index</li>
<li>m5 bits 1..0: exit towards
Expand Down Expand Up @@ -1030,55 +1030,55 @@ <h3><a name="Landscape">Landscape</a></h3>
</tr>

<tr>
<td nowrap valign=top><tt>10</tt>..<tt>1B</tt>&nbsp; </td>
<td nowrap valign=top><tt>40</tt>..<tt>4B</tt>&nbsp; </td>
<td align=left>canal locks
<table>
<tr>
<td nowrap valign=top><tt>10</tt>&nbsp; </td>
<td nowrap valign=top><tt>40</tt>&nbsp; </td>
<td align=left>middle part, (SW-NE direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>11</tt>&nbsp; </td>
<td nowrap valign=top><tt>41</tt>&nbsp; </td>
<td align=left>middle part, (NW-SE direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>12</tt>&nbsp; </td>
<td nowrap valign=top><tt>42</tt>&nbsp; </td>
<td align=left>middle part, (NE-SW direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>13</tt>&nbsp; </td>
<td nowrap valign=top><tt>43</tt>&nbsp; </td>
<td align=left>middle part, (SE-NW direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>14</tt>&nbsp; </td>
<td nowrap valign=top><tt>44</tt>&nbsp; </td>
<td align=left>lower part, (SW-NE direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>15</tt>&nbsp; </td>
<td nowrap valign=top><tt>45</tt>&nbsp; </td>
<td align=left>lower part, (NW-SE direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>16</tt>&nbsp; </td>
<td nowrap valign=top><tt>46</tt>&nbsp; </td>
<td align=left>lower part, (NE-SW direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>17</tt>&nbsp; </td>
<td nowrap valign=top><tt>47</tt>&nbsp; </td>
<td align=left>lower part, (SE-NW direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>18</tt>&nbsp; </td>
<td nowrap valign=top><tt>48</tt>&nbsp; </td>
<td align=left>upper part, (SW-NE direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>19</tt>&nbsp; </td>
<td nowrap valign=top><tt>49</tt>&nbsp; </td>
<td align=left>upper part, (NW-SE direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>1A</tt>&nbsp; </td>
<td nowrap valign=top><tt>4A</tt>&nbsp; </td>
<td align=left>upper part, (NE-SW direction)</td>
</tr>
<tr>
<td nowrap valign=top><tt>1B</tt>&nbsp; </td>
<td nowrap valign=top><tt>4B</tt>&nbsp; </td>
<td align=left>upper part, (SE-NW direction)</td>
</tr>
</table>
Expand Down
10 changes: 5 additions & 5 deletions docs/landscape_grid.html
Expand Up @@ -118,7 +118,7 @@ <h3 style="font-weight: bold;">Landscape</h3>
<td class="bits"><span class="pool" title="Depot index on pool">XXXX XXXX XXXX XXXX</span></td>
<td class="bits"><span class="free">OOOO</span> <span class="free">OOOO</span></td>
<td class="bits"><span class="free">OOOO</span> <span class="used" title="Ground type: fences, snow, desert (fences on depot are not valid)">XXXX</span></td>
<td class="bits"><span class="used" title="Rail tile type: rail, rail with signals, depot">11</span><span class="free">O</span><span class="used" title="PBS reservation">X</span> <span class="free">OO</span><span class="used" title="Depot exit direction">XX</span></td>
<td class="bits"><span class="used" title="Rail tile type: rail, rail with signals, depot">1O</span><span class="free">O</span><span class="used" title="PBS reservation">X</span> <span class="free">OO</span><span class="used" title="Depot exit direction">XX</span></td>
</tr>
<tr>
<td rowspan=3>2</td>
Expand Down Expand Up @@ -241,26 +241,26 @@ <h3 style="font-weight: bold;">Landscape</h3>
<td class="bits" rowspan=3><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits" rowspan=4><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Water tile type: coast, clear, lock, depot">O<span class="usable">OO</span>O</span> <span class="free">OOO</span><span class="used" title="Sea shore flag">X</span></td>
<td class="bits"><span class="used" title="Water tile type: coast or water (00), lock (01), depot (10)">OO</span><span class="free">OO OOO</span><span class="used" title="Sea shore flag">X</span></td>
<td class="bits" rowspan=4><span class="free">OOOO OOOO</span></td>
<td class="bits" rowspan=4><span class="free">OOOO OOOO</td>
<td class="bits" rowspan=4><span class="free">OOOO OOOO OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">canal, river</td>
<td class="bits"><span class="used" title="Canal/river random bits">XXXX XXXX</span></td>
<td class="bits"><span class="used" title="Water tile type: coast, clear, lock, depot">O<span class="usable">OO</span>O</span> <span class="free">OOOO</span></td>
<td class="bits"><span class="used" title="Water tile type: coast or water (00), lock (01), depot (10)">OO</span><span class="free">OO OOOO</span></td>
</tr>
<tr>
<td class="caption">lock</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Water tile type: coast, clear, lock, depot">O<span class="usable">OO</span>1</span> <span class="used" title="Lock part">XX</span> <span class="used" title="Lock orientation m5[1..0]">XX</span></td>
<td class="bits"><span class="used" title="Water tile type: coast or water (00), lock (01), depot (10)">O1</span><span class="free">OO</span><span class="used" title="Lock part">XX</span> <span class="used" title="Lock orientation m5[1..0]">XX</span></td>
</tr>
<tr>
<td class="caption">shipdepot</td>
<td class="bits"><span class="pool" title="Depot index on pool">XXXX XXXX XXXX XXXX</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Water tile type: coast, clear, lock, depot">1<span class="usable">OOO</span></span> <span class="free">OO</span><span class="used" title="Depot axis">X</span> <span class="used" title="Depot part">X</span></td>
<td class="bits"><span class="used" title="Water tile type: coast or water (00), lock (01), depot (10)">1O</span><span class="free">OOOO</span><span class="used" title="Depot axis">X</span> <span class="used" title="Depot part">X</span></td>
</tr>
<tr>
<td rowspan=2>8</td>
Expand Down
35 changes: 13 additions & 22 deletions src/aircraft_cmd.cpp
Expand Up @@ -41,6 +41,7 @@
#include "framerate_type.h"
#include "aircraft_cmd.h"
#include "vehicle_cmd.h"
#include "depot_base.h"

#include "table/strings.h"

Expand Down Expand Up @@ -136,7 +137,7 @@ static StationID FindNearestHangar(const Aircraft *v)
if (v->current_order.IsType(OT_GOTO_STATION) ||
(v->current_order.IsType(OT_GOTO_DEPOT) && (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0)) {
last_dest = Station::GetIfValid(v->last_station_visited);
next_dest = Station::GetIfValid(v->current_order.GetDestination());
next_dest = Station::GetIfValid(GetTargetDestination(v->current_order, true));
} else {
last_dest = GetTargetAirportIfValid(v);
next_dest = Station::GetIfValid(v->GetNextStoppingStation().value);
Expand Down Expand Up @@ -407,9 +408,10 @@ ClosestDepot Aircraft::FindClosestDepot()
if (station == INVALID_STATION) return ClosestDepot();

st = Station::Get(station);
assert(st->airport.hangar != nullptr);
}

return ClosestDepot(st->xy, st->index);
return ClosestDepot(st->xy, st->airport.hangar->index);
}

static void CheckIfAircraftNeedsService(Aircraft *v)
Expand All @@ -424,13 +426,13 @@ static void CheckIfAircraftNeedsService(Aircraft *v)
* we don't want to consider going to a depot too. */
if (!v->current_order.IsType(OT_GOTO_DEPOT) && !v->current_order.IsType(OT_GOTO_STATION)) return;

const Station *st = Station::Get(v->current_order.GetDestination());
const Station *st = Station::Get(GetTargetDestination(v->current_order, true));

assert(st != nullptr);

/* only goto depot if the target airport has a depot */
if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) {
v->current_order.MakeGoToDepot(st->index, ODTFB_SERVICE);
v->current_order.MakeGoToDepot(st->airport.hangar->index, ODTFB_SERVICE);
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
} else if (v->current_order.IsType(OT_GOTO_DEPOT)) {
v->current_order.MakeDummy();
Expand Down Expand Up @@ -892,7 +894,7 @@ static bool AircraftController(Aircraft *v)
/* Jump into our "holding pattern" state machine if possible */
if (v->pos >= afc->nofelements) {
v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, DIR_N);
} else if (v->targetairport != v->current_order.GetDestination()) {
} else if (v->targetairport != GetTargetDestination(v->current_order, true)) {
/* If not possible, just get out of here fast */
v->state = FLYING;
UpdateAircraftCache(v);
Expand Down Expand Up @@ -1449,7 +1451,7 @@ static void AircraftLandAirplane(Aircraft *v)
void AircraftNextAirportPos_and_Order(Aircraft *v)
{
if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT)) {
v->targetairport = v->current_order.GetDestination();
v->targetairport = GetTargetDestination(v->current_order, true);
}

const Station *st = GetTargetAirportIfValid(v);
Expand Down Expand Up @@ -1488,7 +1490,7 @@ void AircraftLeaveHangar(Aircraft *v, Direction exit_dir)
VehicleServiceInDepot(v);
v->LeaveUnbunchingDepot();
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
if (IsHangarTile(v->tile)) InvalidateWindowData(WC_VEHICLE_DEPOT, GetDepotIndex(v->tile));
SetWindowClassesDirty(WC_AIRCRAFT_LIST);
}

Expand Down Expand Up @@ -1539,7 +1541,7 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
return;

/* We are leaving a hangar, but have to go to the exact same one; re-enter */
if (v->current_order.IsType(OT_GOTO_DEPOT) && v->current_order.GetDestination() == v->targetairport) {
if (v->current_order.IsType(OT_GOTO_DEPOT) && GetTargetDestination(v->current_order, true) == v->targetairport) {
VehicleEnterDepot(v);
return;
}
Expand All @@ -1548,7 +1550,7 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return;

/* We are already at the target airport, we need to find a terminal */
if (v->current_order.GetDestination() == v->targetairport) {
if (GetTargetDestination(v->current_order, true) == v->targetairport) {
/* FindFreeTerminal:
* 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */
if (v->subtype == AIR_HELICOPTER) {
Expand Down Expand Up @@ -1599,7 +1601,7 @@ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *
case OT_GOTO_STATION: // ready to fly to another airport
break;
case OT_GOTO_DEPOT: // visit hangar for servicing, sale, etc.
go_to_hangar = v->current_order.GetDestination() == v->targetairport;
go_to_hangar = GetTargetDestination(v->current_order, true) == v->targetairport;
break;
case OT_CONDITIONAL:
/* In case of a conditional order we just have to wait a tick
Expand Down Expand Up @@ -2103,7 +2105,7 @@ static bool AircraftEventHandler(Aircraft *v, int loop)
/* Check the distance to the next destination. This code works because the target
* airport is only updated after take off and not on the ground. */
Station *cur_st = Station::GetIfValid(v->targetairport);
Station *next_st = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination()) : nullptr;
Station *next_st = Station::GetIfValid(GetTargetDestination(v->current_order, true));

if (cur_st != nullptr && cur_st->airport.tile != INVALID_TILE && next_st != nullptr && next_st->airport.tile != INVALID_TILE) {
uint dist = DistanceSquare(cur_st->airport.tile, next_st->airport.tile);
Expand Down Expand Up @@ -2169,18 +2171,7 @@ void UpdateAirplanesOnNewStation(const Station *st)
if (!v->IsNormalAircraft() || v->targetairport != st->index) continue;
assert(v->state == FLYING);

Order *o = &v->current_order;
/* The aircraft is heading to a hangar, but the new station doesn't have one,
* or the aircraft can't land on the new station. Cancel current order. */
if (o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && o->GetDestination() == st->index &&
(!st->airport.HasHangar() || !CanVehicleUseStation(v, st))) {
o->MakeDummy();
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
}
v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation);
UpdateAircraftCache(v);
}

/* Heliports don't have a hangar. Invalidate all go to hangar orders from all aircraft. */
if (!st->airport.HasHangar()) RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, st->index, true);
}
21 changes: 16 additions & 5 deletions src/autoreplace_cmd.cpp
Expand Up @@ -71,19 +71,26 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company)
switch (type) {
case VEH_TRAIN: {
/* make sure the railtypes are compatible */
if ((GetRailTypeInfo(e_from->u.rail.railtype)->compatible_railtypes & GetRailTypeInfo(e_to->u.rail.railtype)->compatible_railtypes) == 0) return false;
if (!_settings_game.depot.allow_no_comp_railtype_replacements &&
(GetRailTypeInfo(e_from->u.rail.railtype)->compatible_railtypes & GetRailTypeInfo(e_to->u.rail.railtype)->compatible_railtypes) == 0) {
return false;
}

/* make sure we do not replace wagons with engines or vice versa */
if ((e_from->u.rail.railveh_type == RAILVEH_WAGON) != (e_to->u.rail.railveh_type == RAILVEH_WAGON)) return false;
break;
}

case VEH_ROAD:
/* make sure the roadtypes are compatible */
if ((GetRoadTypeInfo(e_from->u.road.roadtype)->powered_roadtypes & GetRoadTypeInfo(e_to->u.road.roadtype)->powered_roadtypes) == ROADTYPES_NONE) return false;
if (!_settings_game.depot.allow_no_comp_roadtype_replacements) {
/* make sure the roadtypes are compatible */
if ((GetRoadTypeInfo(e_from->u.road.roadtype)->powered_roadtypes & GetRoadTypeInfo(e_to->u.road.roadtype)->powered_roadtypes) == ROADTYPES_NONE) {
return false;
}

/* make sure that we do not replace a tram with a normal road vehicles or vice versa */
if (HasBit(e_from->info.misc_flags, EF_ROAD_TRAM) != HasBit(e_to->info.misc_flags, EF_ROAD_TRAM)) return false;
/* make sure that we do not replace a tram with a normal road vehicles or vice versa */
if (HasBit(e_from->info.misc_flags, EF_ROAD_TRAM) != HasBit(e_to->info.misc_flags, EF_ROAD_TRAM)) return false;
}
break;

case VEH_AIRCRAFT:
Expand Down Expand Up @@ -519,6 +526,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
{
Vehicle *old_head = *chain;
assert(old_head->IsPrimaryVehicle());
TileIndex tile = old_head->tile;

CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, (Money)0);

Expand Down Expand Up @@ -661,6 +669,9 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
if ((flags & DC_EXEC) != 0) CheckCargoCapacity(new_head);
}

assert(IsValidTile(tile));
if (!HasCompatibleDepotTile(tile, Train::From(new_head))) cost.MakeError(STR_ERROR_UNABLE_TO_FIND_APPROPRIATE_DEPOT_TILE);

/* If we are not in DC_EXEC undo everything, i.e. rearrange old vehicles.
* We do this from back to front, so that the head of the temporary vehicle chain does not change all the time.
* Note: The vehicle attach callback is disabled here :) */
Expand Down