Compare commits

...

17 Commits

Author SHA1 Message Date
e2961fc3bf Merge branch 'jgrpp' into cyka 2024-06-28 12:56:28 +02:00
Jonathan G Rennison
6b30ab5c2c Try all suitable free wagon chains in CmdMoveRailVehicle when no destination
If none usable, move to its own chain

Fixes issues when moving wagons off trains during template replacement
when remainders are kept

See: #707
2024-06-28 00:07:13 +01:00
Jonathan G Rennison
618ed0a0ce Use vehicle tile hash for finding wagons/engines in depots 2024-06-28 00:00:26 +01:00
Jonathan G Rennison
fced6d0eb2 Fix name of CountTrainsNeedingTemplateReplacement 2024-06-28 00:00:26 +01:00
Jonathan G Rennison
0addb29e35 Enable clicking on tunnel to show vehicles inside for road/tram tunnels
Use tile hash to enumerate vehicles
2024-06-27 22:23:06 +01:00
Jonathan G Rennison
4cb3b10f55 Add vehicle function to get first vehicle in tile hash for tile 2024-06-27 22:23:06 +01:00
Jonathan G Rennison
af11b76877 Reduce duplication when iterating shared orders for departure board 2024-06-27 21:19:54 +01:00
Jonathan G Rennison
93d2b6716e Fix missing parameter documentation for vehicle on pos functions 2024-06-27 20:48:52 +01:00
Jonathan G Rennison
991bde6600 Allow changing max tunnel length and max bridge heights in network games 2024-06-27 17:15:16 +01:00
Jonathan G Rennison
291ad74864 Fix wording of running costs per calendar year setting 2024-06-24 00:14:52 +01:00
83683ec40f More capacity 2024-06-10 00:37:08 +02:00
2e74a2c274 More faster loading 2024-06-09 22:51:03 +02:00
6ce3ebb7fd Fix issue in strgen 2024-06-09 22:51:03 +02:00
c2f9d89802 Update 2024-06-09 22:51:03 +02:00
4fb1a7c286 More catchment area 2024-06-09 22:51:03 +02:00
e8c1be6f9e More cargo 2024-06-09 22:51:03 +02:00
bc7bd2f4d5 Update gitignore 2024-06-09 18:07:24 +02:00
17 changed files with 147 additions and 66 deletions

3
.gitignore vendored
View File

@@ -7,3 +7,6 @@ docs/source/*
/out /out
/vcpkg_installed /vcpkg_installed
*.tmp *.tmp
.idea
cmake-build-release
cmake-build-debug

View File

@@ -164,11 +164,12 @@ protected:
CompanyMask companies = 0; CompanyMask companies = 0;
int unitnumber_max[4] = { -1, -1, -1, -1 }; int unitnumber_max[4] = { -1, -1, -1, -1 };
for (const Vehicle *v : Vehicle::IterateFrontOnly()) { for (const Vehicle *veh : Vehicle::IterateFrontOnly()) {
if (v->type < 4 && this->show_types[v->type] && v->IsPrimaryVehicle()) { if (veh->type < 4 && this->show_types[veh->type] && veh->IsPrimaryVehicle() && veh == veh->FirstShared()) {
for(const Order *order : v->Orders()) { for (const Order *order : veh->Orders()) {
if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT))
&& order->GetDestination() == this->station) { && order->GetDestination() == this->station) {
for (const Vehicle *v = veh; v != nullptr; v = v->NextShared()) {
this->vehicles.push_back(v); this->vehicles.push_back(v);
if (_settings_client.gui.departure_show_vehicle) { if (_settings_client.gui.departure_show_vehicle) {
@@ -188,6 +189,7 @@ protected:
if (_settings_client.gui.departure_show_company) { if (_settings_client.gui.departure_show_company) {
SetBit(companies, v->owner); SetBit(companies, v->owner);
} }
}
break; break;
} }
} }

View File

@@ -1585,7 +1585,7 @@ void PrepareUnload(Vehicle *front_v)
static uint GetLoadAmount(Vehicle *v) static uint GetLoadAmount(Vehicle *v)
{ {
const Engine *e = v->GetEngine(); const Engine *e = v->GetEngine();
uint load_amount = e->info.load_amount; uint load_amount = e->info.load_amount * 10;
/* The default loadamount for mail is 1/4 of the load amount for passengers */ /* The default loadamount for mail is 1/4 of the load amount for passengers */
bool air_mail = v->type == VEH_AIRCRAFT && !Aircraft::From(v)->IsNormalAircraft(); bool air_mail = v->type == VEH_AIRCRAFT && !Aircraft::From(v)->IsNormalAircraft();

View File

@@ -321,7 +321,7 @@ uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity, CargoI
capacity = (capacity + default_multiplier / 2) / default_multiplier; capacity = (capacity + default_multiplier / 2) / default_multiplier;
} }
return capacity; return capacity * 8;
} }
/** /**

View File

@@ -349,7 +349,7 @@ STR_CONFIG_SETTING_HIDE_DEFAULT_STOP_LOCATION_HELPTEXT :When enabled, h
STR_CONFIG_SHOW_RAIL_POLYLINE_TOOL :Show rail polyline tool: {STRING2} STR_CONFIG_SHOW_RAIL_POLYLINE_TOOL :Show rail polyline tool: {STRING2}
STR_CONFIG_SHOW_RAIL_POLYLINE_TOOL_HELPTEXT :When enabled, the rail construction toolbar includes a button to build using the polyline mode. STR_CONFIG_SHOW_RAIL_POLYLINE_TOOL_HELPTEXT :When enabled, the rail construction toolbar includes a button to build using the polyline mode.
STR_CONFIG_SHOW_VEHICLE_RUNNING_COSTS_CALENDAR_YEAR :Show vehicle running costs calendar year/period: {STRING2} STR_CONFIG_SHOW_VEHICLE_RUNNING_COSTS_CALENDAR_YEAR :Show vehicle running costs per calendar year/period: {STRING2}
STR_CONFIG_SHOW_VEHICLE_RUNNING_COSTS_CALENDAR_YEAR_HELPTEXT :When using a day length factor greater than one, show vehicle running costs per calendar year (in calendar mode) or per period (in wallclock mode) instead of per original year. STR_CONFIG_SHOW_VEHICLE_RUNNING_COSTS_CALENDAR_YEAR_HELPTEXT :When using a day length factor greater than one, show vehicle running costs per calendar year (in calendar mode) or per period (in wallclock mode) instead of per original year.
STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES :Enable signals on bridges/tunnels advanced modes: {STRING2} STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES :Enable signals on bridges/tunnels advanced modes: {STRING2}

View File

@@ -78,12 +78,12 @@ DECLARE_ENUM_AS_BIT_SET(StationHadVehicleOfType)
/** The different catchment areas used */ /** The different catchment areas used */
enum CatchmentArea { enum CatchmentArea {
CA_NONE = 0, ///< Catchment when the station has no facilities CA_NONE = 0, ///< Catchment when the station has no facilities
CA_BUS = 3, ///< Catchment for bus stops with "modified catchment" enabled CA_BUS = 6, ///< Catchment for bus stops with "modified catchment" enabled
CA_TRUCK = 3, ///< Catchment for truck stops with "modified catchment" enabled CA_TRUCK = 6, ///< Catchment for truck stops with "modified catchment" enabled
CA_TRAIN = 4, ///< Catchment for train stations with "modified catchment" enabled CA_TRAIN = 8, ///< Catchment for train stations with "modified catchment" enabled
CA_DOCK = 5, ///< Catchment for docks with "modified catchment" enabled CA_DOCK = 10, ///< Catchment for docks with "modified catchment" enabled
CA_UNMODIFIED = 4, ///< Catchment for all stations with "modified catchment" disabled CA_UNMODIFIED = 8, ///< Catchment for all stations with "modified catchment" disabled
MAX_CATCHMENT = 10, ///< Maximum catchment for airports with "modified catchment" enabled MAX_CATCHMENT = 10, ///< Maximum catchment for airports with "modified catchment" enabled
}; };

View File

@@ -10,6 +10,8 @@
* This file contains all the data for vehicles * This file contains all the data for vehicles
*/ */
#define SPEEDY_FACTOR 1.5
#ifndef ENGINES_H #ifndef ENGINES_H
#define ENGINES_H #define ENGINES_H
@@ -386,7 +388,7 @@ static const EngineInfo _orig_engine_info[] = {
* Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76 * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76
* Air drag value depends on the top speed of the vehicle. * Air drag value depends on the top speed of the vehicle.
*/ */
#define RVI(a, b, c, d, e, f, g, h, i, j, k) { a, b, c, j, j, d, e, f, g, h, k, i, 0, 0, 0, VE_DEFAULT, 0, 76, 0, 0, 0 } #define RVI(a, b, c, d, e, f, g, h, i, j, k) { a, b, c, j, j, d * SPEEDY_FACTOR, e * SPEEDY_FACTOR, f, g, h, k, i, 0, 0, 0, VE_DEFAULT, 0, 76, 0, 0, 0 }
#define M RAILVEH_MULTIHEAD #define M RAILVEH_MULTIHEAD
#define W RAILVEH_WAGON #define W RAILVEH_WAGON
#define G RAILVEH_SINGLEHEAD #define G RAILVEH_SINGLEHEAD
@@ -564,7 +566,7 @@ static const RailVehicleInfo _orig_rail_vehicle_info[] = {
* @param g sound effect * @param g sound effect
* @param h refittable * @param h refittable
*/ */
#define SVI(a, b, c, d, e, f, g, h) { a, b, c, d, e, f, g, h, VE_DEFAULT, 0, 0 } #define SVI(a, b, c, d, e, f, g, h) { a, b, c * SPEEDY_FACTOR, d * SPEEDY_FACTOR, e, f, g, h, VE_DEFAULT, 0, 0 }
static const ShipVehicleInfo _orig_ship_vehicle_info[] = { static const ShipVehicleInfo _orig_ship_vehicle_info[] = {
/* image_index max_speed sfx refittable /* image_index max_speed sfx refittable
* | cost_factor capacity | | * | cost_factor capacity | |
@@ -597,7 +599,7 @@ static const ShipVehicleInfo _orig_ship_vehicle_info[] = {
* @param h mail_capacity (bags) * @param h mail_capacity (bags)
* @param i passenger_capacity (persons) * @param i passenger_capacity (persons)
*/ */
#define AVI(a, b, c, d, e, f, g, h, i) { a, b, c, d, e, f, (g * 128) / 10, h, i, 0 } #define AVI(a, b, c, d, e, f, g, h, i) { a, b, c, d, e, f * SPEEDY_FACTOR, ((g * 128) / 10) * SPEEDY_FACTOR, h, i, 0 }
#define H AIR_HELI #define H AIR_HELI
#define P AIR_CTOL #define P AIR_CTOL
#define J AIR_CTOL | AIR_FAST #define J AIR_CTOL | AIR_FAST
@@ -668,7 +670,7 @@ static const AircraftVehicleInfo _orig_aircraft_vehicle_info[] = {
* Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76 * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76
* Air drag value depends on the top speed of the vehicle. * Air drag value depends on the top speed of the vehicle.
*/ */
#define ROV(a, b, c, d, e, f, g, h) { a, b, c, PR_RUNNING_ROADVEH, d, e, f, g, h, 76, 0, VE_DEFAULT, 0, ROADTYPE_ROAD } #define ROV(a, b, c, d, e, f, g, h) { a, b, c, PR_RUNNING_ROADVEH, d, e * SPEEDY_FACTOR, f, g, h * SPEEDY_FACTOR, 76, 0, VE_DEFAULT, 0, ROADTYPE_ROAD }
static const RoadVehicleInfo _orig_road_vehicle_info[] = { static const RoadVehicleInfo _orig_road_vehicle_info[] = {
/* image_index sfx max_speed power /* image_index sfx max_speed power
* | cost_factor | | capacity | * | cost_factor | | capacity |

View File

@@ -689,7 +689,6 @@ pre_cb = [](int32_t &new_value) -> bool { return CheckTTDPatchSettingFlag(0x0F
var = construction.max_bridge_height var = construction.max_bridge_height
type = SLE_UINT8 type = SLE_UINT8
from = SLV_194 from = SLV_194
flags = SF_NO_NETWORK
def = 12 def = 12
min = 1 min = 1
max = MAX_TILE_HEIGHT max = MAX_TILE_HEIGHT
@@ -703,7 +702,6 @@ cat = SC_EXPERT
var = construction.max_tunnel_length var = construction.max_tunnel_length
type = SLE_UINT16 type = SLE_UINT16
from = SLV_159 from = SLV_159
flags = SF_NO_NETWORK
def = 64 def = 64
min = 1 min = 1
max = 4096 max = 4096

View File

@@ -696,7 +696,7 @@ public:
/* Draw the number of trains that still need to be treated by the currently selected template replacement */ /* Draw the number of trains that still need to be treated by the currently selected template replacement */
if (tid != INVALID_TEMPLATE) { if (tid != INVALID_TEMPLATE) {
const TemplateVehicle *tv = TemplateVehicle::Get(tid); const TemplateVehicle *tv = TemplateVehicle::Get(tid);
const uint num_trains = CountsTrainsNeedingTemplateReplacement(g_id, tv); const uint num_trains = CountTrainsNeedingTemplateReplacement(g_id, tv);
SetDParam(0, num_trains > 0 ? TC_ORANGE : TC_GREY); SetDParam(0, num_trains > 0 ? TC_ORANGE : TC_GREY);
SetDParam(1, num_trains); SetDParam(1, num_trains);
draw_text(col2 + ScaleGUITrad(4), right - ScaleGUITrad(4), STR_TMPL_NUM_TRAINS_NEED_RPL, num_trains > 0 ? TC_BLACK : TC_GREY, SA_RIGHT); draw_text(col2 + ScaleGUITrad(4), right - ScaleGUITrad(4), STR_TMPL_NUM_TRAINS_NEED_RPL, num_trains > 0 ? TC_BLACK : TC_GREY, SA_RIGHT);

View File

@@ -321,7 +321,7 @@ void CopyWagonStatus(TemplateVehicle *from, Train *to)
to->cargo_subtype = from->cargo_subtype; to->cargo_subtype = from->cargo_subtype;
} }
uint CountsTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle *tv) uint CountTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle *tv)
{ {
uint count = 0; uint count = 0;
if (!tv) return count; if (!tv) return count;

View File

@@ -42,7 +42,7 @@ struct TemplateDepotVehicles {
Train* ContainsEngine(EngineID eid, Train *not_in); Train* ContainsEngine(EngineID eid, Train *not_in);
}; };
uint CountsTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle *tv); uint CountTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle *tv);
CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex tile); CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex tile);

View File

@@ -1504,19 +1504,24 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const
CheckConsistencyOfArticulatedVehicle(v); CheckConsistencyOfArticulatedVehicle(v);
/* Try to connect the vehicle to one of free chains of wagons. */ /* Try to connect the vehicle to one of free chains of wagons. */
for (Train *w : Train::IterateFrontOnly()) { std::vector<Train *> candidates;
if (w->tile == tile && ///< Same depot for (Train *w = Train::From(GetFirstVehicleOnPos(tile, VEH_TRAIN)); w != nullptr; w = w->HashTileNext()) {
w->IsFreeWagon() && ///< A free wagon chain if (w->IsFreeWagon() && ///< A free wagon chain
w->engine_type == e->index && ///< Same type w->engine_type == e->index && ///< Same type
w->First() != v && ///< Don't connect to ourself w->First() != v && ///< Don't connect to ourself
!(w->vehstatus & VS_CRASHED) && ///< Not crashed/flooded !(w->vehstatus & VS_CRASHED) && ///< Not crashed/flooded
w->owner == v->owner && ///< Same owner w->owner == v->owner) { ///< Same owner
!w->IsVirtual()) { ///< Not virtual candidates.push_back(w);
}
}
std::sort(candidates.begin(), candidates.end(), [](const Train *a, const Train *b) {
return a->index < b->index;
});
for (Train *w : candidates) {
if (DoCommand(0, v->index | 1 << 20, w->Last()->index, DC_EXEC, CMD_MOVE_RAIL_VEHICLE).Succeeded()) { if (DoCommand(0, v->index | 1 << 20, w->Last()->index, DC_EXEC, CMD_MOVE_RAIL_VEHICLE).Succeeded()) {
break; break;
} }
} }
}
InvalidateVehicleTickCaches(); InvalidateVehicleTickCaches();
} }
@@ -1528,16 +1533,20 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const
void NormalizeTrainVehInDepot(const Train *u) void NormalizeTrainVehInDepot(const Train *u)
{ {
assert(u->IsEngine()); assert(u->IsEngine());
for (const Train *v : Train::IterateFrontOnly()) { std::vector<Train *> candidates;
if (v->IsFreeWagon() && v->tile == u->tile && for (Train *v = Train::From(GetFirstVehicleOnPos(u->tile, VEH_TRAIN)); v != nullptr; v = v->HashTileNext()) {
if (v->IsFreeWagon() &&
v->track == TRACK_BIT_DEPOT && v->track == TRACK_BIT_DEPOT &&
v->owner == u->owner && v->owner == u->owner) {
!v->IsVirtual()) { candidates.push_back(v);
if (DoCommand(0, v->index | 1 << 20, u->index, DC_EXEC,
CMD_MOVE_RAIL_VEHICLE).Failed())
break;
} }
} }
std::sort(candidates.begin(), candidates.end(), [](const Train *a, const Train *b) {
return a->index < b->index;
});
for (Train *v : candidates) {
if (DoCommand(0, v->index | 1 << 20, u->index, DC_EXEC, CMD_MOVE_RAIL_VEHICLE).Failed()) break;
}
} }
static void AddRearEngineToMultiheadedTrain(Train *v) static void AddRearEngineToMultiheadedTrain(Train *v)
@@ -1670,23 +1679,32 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin
return CommandCost(); return CommandCost();
} }
static Train *FindGoodVehiclePos(const Train *src) static std::vector<Train *> FindGoodVehiclePosList(const Train *src)
{ {
EngineID eng = src->engine_type; EngineID eng = src->engine_type;
TileIndex tile = src->tile; TileIndex tile = src->tile;
for (Train *dst : Train::IterateFrontOnly()) { std::vector<Train *> candidates;
if (dst->IsFreeWagon() && dst->tile == tile && !(dst->vehstatus & VS_CRASHED) && dst->owner == src->owner && !dst->IsVirtual()) {
for (Train *dst = Train::From(GetFirstVehicleOnPos(tile, VEH_TRAIN)); dst != nullptr; dst = dst->HashTileNext()) {
if (dst->IsFreeWagon() && !(dst->vehstatus & VS_CRASHED) && dst->owner == src->owner) {
/* check so all vehicles in the line have the same engine. */ /* check so all vehicles in the line have the same engine. */
Train *t = dst; Train *t = dst;
while (t->engine_type == eng) { while (t->engine_type == eng) {
t = t->Next(); t = t->Next();
if (t == nullptr) return dst; if (t == nullptr) {
candidates.push_back(dst);
break;
}
} }
} }
} }
return nullptr; std::sort(candidates.begin(), candidates.end(), [](const Train *a, const Train *b) {
return a->index < b->index;
});
return candidates;
} }
/** Helper type for lists/vectors of trains */ /** Helper type for lists/vectors of trains */
@@ -2084,7 +2102,17 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32_t p1,
/* if nothing is selected as destination, try and find a matching vehicle to drag to. */ /* if nothing is selected as destination, try and find a matching vehicle to drag to. */
Train *dst; Train *dst;
if (d == INVALID_VEHICLE) { if (d == INVALID_VEHICLE) {
dst = (src->IsEngine() || (flags & DC_AUTOREPLACE)) ? nullptr : FindGoodVehiclePos(src); if (!src->IsEngine() && !src->IsVirtual() && !(flags & DC_AUTOREPLACE)) {
/* Try each possible destination target, if none succeed do not append to a free wagon chain */
std::vector<Train *> destination_candidates = FindGoodVehiclePosList(src);
for (Train *try_dest : destination_candidates) {
uint32_t try_p2 = p2;
SB(try_p2, 0, 20, try_dest->index);
CommandCost cost = CmdMoveRailVehicle(tile, flags, p1, try_p2, text);
if (cost.Succeeded()) return cost;
}
}
dst = nullptr;
} else { } else {
dst = Train::GetIfValid(d); dst = Train::GetIfValid(d);
if (dst == nullptr) return check_on_failure(CMD_ERROR); if (dst == nullptr) return check_on_failure(CMD_ERROR);
@@ -2100,7 +2128,7 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32_t p1,
src = src->GetFirstEnginePart(); src = src->GetFirstEnginePart();
if (dst != nullptr) { if (dst != nullptr) {
dst = dst->GetFirstEnginePart(); dst = dst->GetFirstEnginePart();
assert(HasBit(dst->subtype, GVSF_VIRTUAL) == HasBit(src->subtype, GVSF_VIRTUAL)); if (HasBit(dst->subtype, GVSF_VIRTUAL) != HasBit(src->subtype, GVSF_VIRTUAL)) return CMD_ERROR;
} }
/* don't move the same vehicle.. */ /* don't move the same vehicle.. */

View File

@@ -36,8 +36,8 @@ void CcBuildWagon(const CommandCost &result, TileIndex tile, uint32_t p1, uint32
/* find a locomotive in the depot. */ /* find a locomotive in the depot. */
const Vehicle *found = nullptr; const Vehicle *found = nullptr;
for (const Train *t : Train::IterateFrontOnly()) { for (const Train *t = Train::From(GetFirstVehicleOnPos(tile, VEH_TRAIN)); t != nullptr; t = t->HashTileNext()) {
if (t->IsFrontEngine() && t->tile == tile && t->IsStoppedInDepot() && !t->IsVirtual()) { if (t->IsFrontEngine() && t->IsStoppedInDepot()) {
if (found != nullptr) return; // must be exactly one. if (found != nullptr) return; // must be exactly one.
found = t; found = t;
} }

View File

@@ -2861,17 +2861,27 @@ static bool ClickTile_TunnelBridge(TileIndex tile)
/* Show vehicles found in tunnel. */ /* Show vehicles found in tunnel. */
if (IsTunnelTile(tile)) { if (IsTunnelTile(tile)) {
int count = 0;
TileIndex tile_end = GetOtherTunnelBridgeEnd(tile); TileIndex tile_end = GetOtherTunnelBridgeEnd(tile);
for (const Train *t : Train::IterateFrontOnly()) { VehicleType veh_type = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL ? VEH_TRAIN : VEH_ROAD;
if (!t->IsFrontEngine()) continue;
if (tile == t->tile || tile_end == t->tile) { std::vector<const Vehicle *> candidates;
ShowVehicleViewWindow(t); for (TileIndex test_tile : { tile, tile_end }) {
count++; for (const Vehicle *v = GetFirstVehicleOnPos(test_tile, veh_type); v != nullptr; v = v->HashTileNext()) {
if (v->IsFrontEngine()) candidates.push_back(v);
} }
if (count > 19) break; // no more than 20 windows open
} }
if (count > 0) return true; std::sort(candidates.begin(), candidates.end(), [&](const Vehicle *a, const Vehicle *b) {
return a->index < b->index;
});
/* No more than 20 windows open */
if (candidates.size() > 20) candidates.resize(20);
for (const Vehicle *v : candidates) {
ShowVehicleViewWindow(v);
}
if (!candidates.empty()) return true;
} }
return false; return false;
} }

View File

@@ -556,6 +556,7 @@ Vehicle *VehicleFromPosXY(int x, int y, VehicleType type, void *data, VehicleFro
* Helper function for FindVehicleOnPos/HasVehicleOnPos. * Helper function for FindVehicleOnPos/HasVehicleOnPos.
* @note Do not call this function directly! * @note Do not call this function directly!
* @param tile The location on the map * @param tile The location on the map
* @param type The vehicle type
* @param data Arbitrary data passed to \a proc. * @param data Arbitrary data passed to \a proc.
* @param proc The proc that determines whether a vehicle will be "found". * @param proc The proc that determines whether a vehicle will be "found".
* @param find_first Whether to return on the first found or iterate over * @param find_first Whether to return on the first found or iterate over
@@ -580,6 +581,25 @@ Vehicle *VehicleFromPos(TileIndex tile, VehicleType type, void *data, VehicleFro
return nullptr; return nullptr;
} }
/**
* Returns the first vehicle on a specific location, this should be iterated using Vehicle::HashTileNext.
* @note Use #GetFirstVehicleOnPos when you have the intention that all vehicles should be iterated over using Vehicle::HashTileNext. The iteration order is non-deterministic.
* @param tile The location on the map
* @param type The vehicle type
* @return First vehicle or nullptr.
*/
Vehicle *GetFirstVehicleOnPos(TileIndex tile, VehicleType type)
{
VehicleTypeTileHash &vhash = _vehicle_tile_hashes[type];
auto iter = vhash.find(tile);
if (iter != vhash.end()) {
return Vehicle::Get(iter->second);
} else {
return nullptr;
}
}
/** /**
* Callback that returns 'real' vehicles lower or at height \c *(int*)data . * Callback that returns 'real' vehicles lower or at height \c *(int*)data .
* @param v Vehicle to examine. * @param v Vehicle to examine.

View File

@@ -793,6 +793,12 @@ public:
return v; return v;
} }
/**
* Get the next vehicle in the tile hash chain.
* @return the next vehicle in the tile hash chain or nullptr when there isn't a next vehicle.
*/
inline Vehicle *HashTileNext() const { return this->hash_tile_next; }
/** /**
* Get the vehicle at offset \a n of this vehicle chain. * Get the vehicle at offset \a n of this vehicle chain.
* @param n Offset from the current vehicle. * @param n Offset from the current vehicle.
@@ -1495,6 +1501,12 @@ struct SpecializedVehicle : public Vehicle {
*/ */
inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); } inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
/**
* Get the next vehicle in the tile hash chain.
* @return the next vehicle in the tile hash chain or nullptr when there isn't a next vehicle.
*/
inline T *HashTileNext() const { return (T *)this->Vehicle::HashTileNext(); }
/** /**
* Tests whether given index is a valid index for vehicle of this type * Tests whether given index is a valid index for vehicle of this type
* @param index tested index * @param index tested index

View File

@@ -55,6 +55,7 @@ uint CountVehiclesInChain(const Vehicle *v);
* @note Use this function when you have the intention that all vehicles * @note Use this function when you have the intention that all vehicles
* should be iterated over. * should be iterated over.
* @param tile The location on the map * @param tile The location on the map
* @param type The vehicle type
* @param data Arbitrary data passed to \a proc. * @param data Arbitrary data passed to \a proc.
* @param proc The proc that determines whether a vehicle will be "found". * @param proc The proc that determines whether a vehicle will be "found".
*/ */
@@ -70,6 +71,7 @@ inline void FindVehicleOnPos(TileIndex tile, VehicleType type, void *data, Vehic
* @note Use #FindVehicleOnPos when you have the intention that all vehicles * @note Use #FindVehicleOnPos when you have the intention that all vehicles
* should be iterated over. * should be iterated over.
* @param tile The location on the map * @param tile The location on the map
* @param type The vehicle type
* @param data Arbitrary data passed to \a proc. * @param data Arbitrary data passed to \a proc.
* @param proc The \a proc that determines whether a vehicle will be "found". * @param proc The \a proc that determines whether a vehicle will be "found".
* @return True if proc returned non-nullptr. * @return True if proc returned non-nullptr.
@@ -80,6 +82,8 @@ inline bool HasVehicleOnPos(TileIndex tile, VehicleType type, void *data, Vehicl
return VehicleFromPos(tile, type, data, proc, true) != nullptr; return VehicleFromPos(tile, type, data, proc, true) != nullptr;
} }
Vehicle *GetFirstVehicleOnPos(TileIndex tile, VehicleType type);
/** /**
* Find a vehicle from a specific location. It will call proc for ALL vehicles * Find a vehicle from a specific location. It will call proc for ALL vehicles
* on the tile and YOU must make SURE that the "best one" is stored in the * on the tile and YOU must make SURE that the "best one" is stored in the
@@ -91,6 +95,7 @@ inline bool HasVehicleOnPos(TileIndex tile, VehicleType type, void *data, Vehicl
* should be iterated over. * should be iterated over.
* @param x The X location on the map * @param x The X location on the map
* @param y The Y location on the map * @param y The Y location on the map
* @param type The vehicle type
* @param data Arbitrary data passed to proc * @param data Arbitrary data passed to proc
* @param proc The proc that determines whether a vehicle will be "found". * @param proc The proc that determines whether a vehicle will be "found".
*/ */
@@ -107,6 +112,7 @@ inline void FindVehicleOnPosXY(int x, int y, VehicleType type, void *data, Vehic
* should be iterated over. * should be iterated over.
* @param x The X location on the map * @param x The X location on the map
* @param y The Y location on the map * @param y The Y location on the map
* @param type The vehicle type
* @param data Arbitrary data passed to proc * @param data Arbitrary data passed to proc
* @param proc The proc that determines whether a vehicle will be "found". * @param proc The proc that determines whether a vehicle will be "found".
* @return True if proc returned non-nullptr. * @return True if proc returned non-nullptr.