Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2025-09-28 02:33:49 +05:00
926 changed files with 37901 additions and 27368 deletions
+86 -70
View File
@@ -37,6 +37,7 @@
#include "framerate_type.h"
#include "roadveh_cmd.h"
#include "road_cmd.h"
#include "newgrf_roadstop.h"
#include "table/strings.h"
@@ -106,7 +107,7 @@ static void GetRoadVehIcon(EngineID engine, EngineImageType image_type, VehicleS
const Engine *e = Engine::Get(engine);
uint8_t spritenum = e->u.road.image_index;
if (is_custom_sprite(spritenum)) {
if (IsCustomVehicleSpriteNum(spritenum)) {
GetCustomVehicleIcon(engine, DIR_W, image_type, result);
if (result->IsValid()) return;
@@ -121,8 +122,9 @@ void RoadVehicle::GetImage(Direction direction, EngineImageType image_type, Vehi
{
uint8_t spritenum = this->spritenum;
if (is_custom_sprite(spritenum)) {
GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result);
if (IsCustomVehicleSpriteNum(spritenum)) {
if (spritenum == CUSTOM_VEHICLE_SPRITENUM_REVERSED) direction = ReverseDir(direction);
GetCustomVehicleSprite(this, direction, image_type, result);
if (result->IsValid()) return;
spritenum = this->GetEngine()->original_image_index;
@@ -403,29 +405,56 @@ void RoadVehicle::MarkDirty()
void RoadVehicle::UpdateDeltaXY()
{
static const int8_t _delta_xy_table[8][10] = {
/* y_extent, x_extent, y_offs, x_offs, y_bb_offs, x_bb_offs, y_extent_shorten, x_extent_shorten, y_bb_offs_shorten, x_bb_offs_shorten */
{3, 3, -1, -1, 0, 0, -1, -1, -1, -1}, // N
{3, 7, -1, -3, 0, -1, 0, -1, 0, 0}, // NE
{3, 3, -1, -1, 0, 0, 1, -1, 1, -1}, // E
{7, 3, -3, -1, -1, 0, 0, 0, 1, 0}, // SE
{3, 3, -1, -1, 0, 0, 1, 1, 1, 1}, // S
{3, 7, -1, -3, 0, -1, 0, 0, 0, 1}, // SW
{3, 3, -1, -1, 0, 0, -1, 1, -1, 1}, // W
{7, 3, -3, -1, -1, 0, -1, 0, 0, 0}, // NW
};
/* Set common defaults. */
this->bounds = {{-1, -1, 0}, {3, 3, 6}, {}};
int shorten = VEHICLE_LENGTH - this->gcache.cached_veh_length;
if (!IsDiagonalDirection(this->direction)) shorten >>= 1;
if (!IsDiagonalDirection(this->direction)) {
static const Point _sign_table[] = {
/* x, y */
{-1, -1}, // DIR_N
{-1, 1}, // DIR_E
{ 1, 1}, // DIR_S
{ 1, -1}, // DIR_W
};
const int8_t *bb = _delta_xy_table[this->direction];
this->x_bb_offs = bb[5] + bb[9] * shorten;
this->y_bb_offs = bb[4] + bb[8] * shorten;;
this->x_offs = bb[3];
this->y_offs = bb[2];
this->x_extent = bb[1] + bb[7] * shorten;
this->y_extent = bb[0] + bb[6] * shorten;
this->z_extent = 6;
int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2;
/* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
this->bounds.offset.x -= half_shorten * _sign_table[DirToDiagDir(this->direction)].x;
this->bounds.offset.y -= half_shorten * _sign_table[DirToDiagDir(this->direction)].y;
} else {
/* Unlike trains, road vehicles do not have their offsets moved to the centre. */
switch (this->direction) {
/* Shorten southern corner of the bounding box according the vehicle length. */
case DIR_NE:
this->bounds.origin.x = -3;
this->bounds.extent.x = this->gcache.cached_veh_length;
this->bounds.offset.x = 1;
break;
case DIR_NW:
this->bounds.origin.y = -3;
this->bounds.extent.y = this->gcache.cached_veh_length;
this->bounds.offset.y = 1;
break;
/* Move northern corner of the bounding box down according to vehicle length. */
case DIR_SW:
this->bounds.origin.x = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length);
this->bounds.extent.x = this->gcache.cached_veh_length;
this->bounds.offset.x = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
break;
case DIR_SE:
this->bounds.origin.y = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length);
this->bounds.extent.y = this->gcache.cached_veh_length;
this->bounds.offset.y = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
break;
default:
NOT_REACHED();
}
}
}
/**
@@ -509,22 +538,6 @@ static bool RoadVehIsCrashed(RoadVehicle *v)
return true;
}
/**
* Check routine whether a road and a train vehicle have collided.
* @param v %Train vehicle to test.
* @param data Road vehicle to test.
* @return %Train vehicle if the vehicles collided, else \c nullptr.
*/
static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
{
const Vehicle *u = (Vehicle*)data;
return (v->type == VEH_TRAIN &&
abs(v->z_pos - u->z_pos) <= 6 &&
abs(v->x_pos - u->x_pos) <= 4 &&
abs(v->y_pos - u->y_pos) <= 4) ? v : nullptr;
}
uint RoadVehicle::Crash(bool flooded)
{
uint victims = this->GroundVehicleBase::Crash(flooded);
@@ -567,7 +580,9 @@ static bool RoadVehCheckTrainCrash(RoadVehicle *v)
if (!IsLevelCrossingTile(tile)) continue;
if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
if (HasVehicleNearTileXY(v->x_pos, v->y_pos, 4, [&u](const Vehicle *t) {
return t->type == VEH_TRAIN && abs(t->z_pos - u->z_pos) <= 6;
})) {
RoadVehCrash(v);
return true;
}
@@ -610,25 +625,23 @@ struct RoadVehFindData {
Direction dir;
};
static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
static void FindClosestBlockingRoadVeh(Vehicle *v, RoadVehFindData *rvf)
{
static const int8_t dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
static const int8_t dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
RoadVehFindData *rvf = (RoadVehFindData*)data;
int x_diff = v->x_pos - rvf->x;
int y_diff = v->y_pos - rvf->y;
/* Not a close Road vehicle when it's not a road vehicle, in the depot, or ourself. */
if (v->type != VEH_ROAD || v->IsInDepot() || rvf->veh->First() == v->First()) return nullptr;
if (v->type != VEH_ROAD || v->IsInDepot() || rvf->veh->First() == v->First()) return;
/* Not close when at a different height or when going in a different direction. */
if (abs(v->z_pos - rvf->veh->z_pos) >= 6 || v->direction != rvf->dir) return nullptr;
if (abs(v->z_pos - rvf->veh->z_pos) >= 6 || v->direction != rvf->dir) return;
/* We 'return' the closest vehicle, in distance and then VehicleID as tie-breaker. */
uint diff = abs(x_diff) + abs(y_diff);
if (diff > rvf->best_diff || (diff == rvf->best_diff && v->index > rvf->best->index)) return nullptr;
if (diff > rvf->best_diff || (diff == rvf->best_diff && v->index > rvf->best->index)) return;
auto IsCloseOnAxis = [](int dist, int diff) {
if (dist < 0) return diff > dist && diff <= 0;
@@ -639,8 +652,6 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
rvf->best = v;
rvf->best_diff = diff;
}
return nullptr;
}
static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
@@ -657,10 +668,16 @@ static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction d
rvf.best_diff = UINT_MAX;
if (front->state == RVSB_WORMHOLE) {
FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
for (Vehicle *u : VehiclesOnTile(v->tile)) {
FindClosestBlockingRoadVeh(u, &rvf);
}
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
FindClosestBlockingRoadVeh(u, &rvf);
}
} else {
FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
for (Vehicle *u : VehiclesNearTileXY(x, y, 8)) {
FindClosestBlockingRoadVeh(u, &rvf);
}
}
/* This code protects a roadvehicle from being blocked for ever
@@ -765,13 +782,6 @@ struct OvertakeData {
Trackdir trackdir;
};
static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
{
const OvertakeData *od = (OvertakeData*)data;
return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : nullptr;
}
/**
* Check if overtaking is possible on a piece of track
*
@@ -790,7 +800,9 @@ static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
/* Are there more vehicles on the tile except the two vehicles involved in overtaking */
return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake);
return HasVehicleOnTile(od->tile, [&](const Vehicle *v) {
return v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v;
});
}
static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
@@ -1162,7 +1174,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
}
}
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && VehicleEnterTile(v, gp.new_tile, gp.x, gp.y).Test(VehicleEnterTileState::EnteredWormhole)) {
/* Vehicle has just entered a bridge or tunnel */
v->x_pos = gp.x;
v->y_pos = gp.y;
@@ -1282,8 +1294,8 @@ again:
}
}
uint32_t r = VehicleEnterTile(v, tile, x, y);
if (HasBit(r, VETS_CANNOT_ENTER)) {
auto vets = VehicleEnterTile(v, tile, x, y);
if (vets.Test(VehicleEnterTileState::CannotEnter)) {
if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
v->cur_speed = 0;
return false;
@@ -1319,7 +1331,7 @@ again:
}
}
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
if (!vets.Test(VehicleEnterTileState::EnteredWormhole)) {
TileIndex old_tile = v->tile;
v->tile = tile;
@@ -1397,8 +1409,8 @@ again:
}
}
uint32_t r = VehicleEnterTile(v, v->tile, x, y);
if (HasBit(r, VETS_CANNOT_ENTER)) {
auto vets = VehicleEnterTile(v, v->tile, x, y);
if (vets.Test(VehicleEnterTileState::CannotEnter)) {
v->cur_speed = 0;
return false;
}
@@ -1453,6 +1465,8 @@ again:
v->last_station_visited = st->index;
RoadVehArrivesAt(v, st);
v->BeginLoading();
TriggerRoadStopRandomisation(st, v->tile, StationRandomTrigger::VehicleArrives);
TriggerRoadStopAnimation(st, v->tile, StationAnimationTrigger::VehicleArrives);
}
return false;
}
@@ -1515,6 +1529,8 @@ again:
if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
RoadVehArrivesAt(v, st);
v->BeginLoading();
TriggerRoadStopRandomisation(st, v->tile, StationRandomTrigger::VehicleArrives);
TriggerRoadStopAnimation(st, v->tile, StationAnimationTrigger::VehicleArrives);
return false;
}
} else {
@@ -1535,8 +1551,8 @@ again:
/* Check tile position conditions - i.e. stop position in depot,
* entry onto bridge or into tunnel */
uint32_t r = VehicleEnterTile(v, v->tile, x, y);
if (HasBit(r, VETS_CANNOT_ENTER)) {
auto vets = VehicleEnterTile(v, v->tile, x, y);
if (vets.Test(VehicleEnterTileState::CannotEnter)) {
v->cur_speed = 0;
return false;
}
@@ -1547,7 +1563,7 @@ again:
/* Move to next frame unless vehicle arrived at a stop position
* in a depot or entered a tunnel/bridge */
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
if (!vets.Test(VehicleEnterTileState::EnteredWormhole)) v->frame++;
v->x_pos = x;
v->y_pos = y;
v->UpdatePosition();
@@ -1696,7 +1712,7 @@ static void CheckIfRoadVehNeedsService(RoadVehicle *v)
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
}
/** Calandar day handler */
/** Calander day handler */
void RoadVehicle::OnNewCalendarDay()
{
if (!this->IsFrontEngine()) return;