mirror of https://github.com/OpenTTD/OpenTTD.git
Compare commits
5 Commits
df71444009
...
528fd61a81
Author | SHA1 | Date |
---|---|---|
Zac | 528fd61a81 | |
Peter Nelson | bf8de188ec | |
Peter Nelson | 72c55128d2 | |
Peter Nelson | a6d401debf | |
zacc | c1256d8211 |
|
@ -4846,7 +4846,6 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteR
|
|||
|
||||
uint32_t classid = buf->ReadDWord();
|
||||
rs->cls_id = RoadStopClass::Allocate(BSWAP32(classid));
|
||||
rs->spec_id = id + i;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -308,25 +308,15 @@ bool Convert8bitBooleanCallback(const struct GRFFile *grffile, uint16_t cbid, ui
|
|||
*/
|
||||
template <size_t Tcnt>
|
||||
struct GRFFilePropsBase {
|
||||
GRFFilePropsBase() : local_id(0), grffile(nullptr)
|
||||
{
|
||||
/* The lack of some compilers to provide default constructors complying to the specs
|
||||
* requires us to zero the stuff ourself. */
|
||||
memset(spritegroup, 0, sizeof(spritegroup));
|
||||
}
|
||||
|
||||
uint16_t local_id; ///< id defined by the grf file for this entity
|
||||
const struct GRFFile *grffile; ///< grf file that introduced this entity
|
||||
const struct SpriteGroup *spritegroup[Tcnt]; ///< pointer to the different sprites of the entity
|
||||
uint16_t local_id = 0; ///< id defined by the grf file for this entity
|
||||
const struct GRFFile *grffile = nullptr; ///< grf file that introduced this entity
|
||||
std::array<const struct SpriteGroup *, Tcnt> spritegroup{}; ///< pointers to the different sprites of the entity
|
||||
};
|
||||
|
||||
/** Data related to the handling of grf files. */
|
||||
struct GRFFileProps : GRFFilePropsBase<1> {
|
||||
/** Set all default data constructor for the props. */
|
||||
GRFFileProps(uint16_t subst_id = 0) :
|
||||
GRFFilePropsBase<1>(), subst_id(subst_id), override(subst_id)
|
||||
{
|
||||
}
|
||||
constexpr GRFFileProps(uint16_t subst_id = 0) : subst_id(subst_id), override(subst_id) {}
|
||||
|
||||
uint16_t subst_id;
|
||||
uint16_t override; ///< id of the entity been replaced by
|
||||
|
|
|
@ -53,7 +53,7 @@ const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, Eng
|
|||
void SetCustomEngineSprites(EngineID engine, uint8_t cargo, const SpriteGroup *group)
|
||||
{
|
||||
Engine *e = Engine::Get(engine);
|
||||
assert(cargo < lengthof(e->grf_prop.spritegroup));
|
||||
assert(cargo < std::size(e->grf_prop.spritegroup));
|
||||
|
||||
if (e->grf_prop.spritegroup[cargo] != nullptr) {
|
||||
GrfMsg(6, "SetCustomEngineSprites: engine {} cargo {} already has group -- replacing", engine, cargo);
|
||||
|
@ -1062,7 +1062,7 @@ VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle
|
|||
if (this->root_spritegroup == nullptr) {
|
||||
const Engine *e = Engine::Get(engine_type);
|
||||
CargoID cargo = v != nullptr ? v->cargo_type : SpriteGroupCargo::SG_PURCHASE;
|
||||
assert(cargo < lengthof(e->grf_prop.spritegroup));
|
||||
assert(cargo < std::size(e->grf_prop.spritegroup));
|
||||
this->root_spritegroup = e->grf_prop.spritegroup[cargo] != nullptr ? e->grf_prop.spritegroup[cargo] : e->grf_prop.spritegroup[SpriteGroupCargo::SG_DEFAULT];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,6 @@ struct RoadStopSpec {
|
|||
*/
|
||||
GRFFilePropsBase<NUM_CARGO + 3> grf_prop;
|
||||
RoadStopClassID cls_id; ///< The class to which this spec belongs.
|
||||
int spec_id; ///< The ID of this spec inside the class.
|
||||
StringID name; ///< Name of this stop
|
||||
|
||||
RoadStopAvailabilityType stop_type = ROADSTOPTYPE_ALL;
|
||||
|
|
|
@ -504,7 +504,7 @@ uint32_t Waypoint::GetNewGRFVariable(const ResolverObject &, uint8_t variable, [
|
|||
|
||||
/* virtual */ const SpriteGroup *StationResolverObject::ResolveReal(const RealSpriteGroup *group) const
|
||||
{
|
||||
if (this->station_scope.st == nullptr || this->station_scope.statspec->cls_id == STAT_CLASS_WAYP) {
|
||||
if (this->station_scope.st == nullptr || !Station::IsExpected(this->station_scope.st)) {
|
||||
return group->loading[0];
|
||||
}
|
||||
|
||||
|
|
|
@ -368,7 +368,7 @@ static int32_t NPFRoadPathCost(AyStar *, AyStarNode *current, OpenListNode *)
|
|||
/* When we're the first road stop in a 'queue' of them we increase
|
||||
* cost based on the fill percentage of the whole queue. */
|
||||
const RoadStop::Entry *entry = rs->GetEntry(dir);
|
||||
cost += entry->GetOccupied() * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
|
||||
cost += entry->GetOccupied(rs, dir) * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
|
||||
}
|
||||
} else {
|
||||
/* Increase cost for filled road stops */
|
||||
|
|
|
@ -75,11 +75,11 @@ protected:
|
|||
/* Increase the cost for drive-through road stops */
|
||||
cost += Yapf().PfGetSettings().road_stop_penalty;
|
||||
DiagDirection dir = TrackdirToExitdir(trackdir);
|
||||
if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) {
|
||||
/* When we're the first road stop in a 'queue' of them we increase
|
||||
* cost based on the fill percentage of the whole queue. */
|
||||
if (Yapf().PfDetectDestinationTile(tile, trackdir)){
|
||||
/* We've found the destination file so get the occupied
|
||||
* level from the Entry object. */
|
||||
const RoadStop::Entry *entry = rs->GetEntry(dir);
|
||||
cost += entry->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
|
||||
cost += entry->GetOccupied(rs, dir) * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
|
||||
}
|
||||
} else {
|
||||
/* Increase cost for filled road stops */
|
||||
|
|
152
src/roadstop.cpp
152
src/roadstop.cpp
|
@ -88,8 +88,6 @@ void RoadStop::MakeDriveThrough()
|
|||
if (south && rs_south->east != nullptr) { // (east != nullptr) == (west != nullptr)
|
||||
/* There more southern tiles too, they must 'join' us too */
|
||||
ClrBit(rs_south->status, RSSFB_BASE_ENTRY);
|
||||
this->east->occupied += rs_south->east->occupied;
|
||||
this->west->occupied += rs_south->west->occupied;
|
||||
|
||||
/* Free the now unneeded entry structs */
|
||||
delete rs_south->east;
|
||||
|
@ -175,12 +173,7 @@ void RoadStop::ClearDriveThrough()
|
|||
rs_north = RoadStop::GetByTile(north_tile, rst);
|
||||
}
|
||||
|
||||
/* We have to rebuild the entries because we cannot easily determine
|
||||
* how full each part is. So instead of keeping and maintaining a list
|
||||
* of vehicles and using that to 'rebuild' the occupied state we just
|
||||
* rebuild it from scratch as that removes lots of maintenance code
|
||||
* for the vehicle list and it's faster in real games as long as you
|
||||
* do not keep split and merge road stop every tick by the millions. */
|
||||
/* We have to rebuild the entries to determine the length of the roadstop. */
|
||||
rs_south_base->east->Rebuild(rs_south_base);
|
||||
rs_south_base->west->Rebuild(rs_south_base);
|
||||
|
||||
|
@ -219,9 +212,6 @@ void RoadStop::Leave(RoadVehicle *rv)
|
|||
/* Vehicle is leaving a road stop tile, mark bay as free */
|
||||
this->FreeBay(HasBit(rv->state, RVS_USING_SECOND_BAY));
|
||||
this->SetEntranceBusy(false);
|
||||
} else {
|
||||
/* Otherwise just leave the drive through's entry cache. */
|
||||
this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,9 +238,6 @@ bool RoadStop::Enter(RoadVehicle *rv)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
|
||||
this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv);
|
||||
|
||||
/* Indicate a drive-through stop */
|
||||
SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
|
||||
return true;
|
||||
|
@ -273,28 +260,6 @@ bool RoadStop::Enter(RoadVehicle *rv)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave the road stop
|
||||
* @param rv the vehicle that leaves the stop
|
||||
*/
|
||||
void RoadStop::Entry::Leave(const RoadVehicle *rv)
|
||||
{
|
||||
this->occupied -= rv->gcache.cached_total_length;
|
||||
assert(this->occupied >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter the road stop
|
||||
* @param rv the vehicle that enters the stop
|
||||
*/
|
||||
void RoadStop::Entry::Enter(const RoadVehicle *rv)
|
||||
{
|
||||
/* we cannot assert on this->occupied < this->length because of the
|
||||
* remote possibility that RVs are running through each other when
|
||||
* trying to prevention an infinite jam. */
|
||||
this->occupied += rv->gcache.cached_total_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the 'next' tile is still part of the road same drive through
|
||||
* stop 'rs' in the same direction for the same vehicle.
|
||||
|
@ -311,67 +276,88 @@ void RoadStop::Entry::Enter(const RoadVehicle *rv)
|
|||
IsDriveThroughStopTile(next);
|
||||
}
|
||||
|
||||
typedef std::list<const RoadVehicle *> RVList; ///< A list of road vehicles
|
||||
|
||||
/** Helper for finding RVs in a road stop. */
|
||||
struct RoadStopEntryRebuilderHelper {
|
||||
RVList vehicles; ///< The list of vehicles to possibly add to.
|
||||
DiagDirection dir; ///< The direction the vehicle has to face to be added.
|
||||
};
|
||||
|
||||
/**
|
||||
* Add road vehicles to the station's list if needed.
|
||||
* @param v the found vehicle
|
||||
* @param data the extra data used to make our decision
|
||||
* @return always nullptr
|
||||
*/
|
||||
Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data)
|
||||
{
|
||||
RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data;
|
||||
/* Not a RV or not in the right direction or crashed :( */
|
||||
if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return nullptr;
|
||||
|
||||
RoadVehicle *rv = RoadVehicle::From(v);
|
||||
/* Don't add ones not in a road stop */
|
||||
if (rv->state < RVSB_IN_ROAD_STOP) return nullptr;
|
||||
|
||||
/* Do not add duplicates! */
|
||||
for (const auto &it : rserh->vehicles) {
|
||||
if (rv == it) return nullptr;
|
||||
}
|
||||
|
||||
rserh->vehicles.push_back(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild, from scratch, the vehicles and other metadata on this stop.
|
||||
* @param rs the roadstop this entry is part of
|
||||
* @param side the side of the road stop to look at
|
||||
*/
|
||||
void RoadStop::Entry::Rebuild(const RoadStop *rs, int side)
|
||||
void RoadStop::Entry::Rebuild(const RoadStop *rs)
|
||||
{
|
||||
assert(HasBit(rs->status, RSSFB_BASE_ENTRY));
|
||||
|
||||
DiagDirection dir = GetRoadStopDir(rs->xy);
|
||||
if (side == -1) side = (rs->east == this);
|
||||
|
||||
RoadStopEntryRebuilderHelper rserh;
|
||||
rserh.dir = side ? dir : ReverseDiagDir(dir);
|
||||
|
||||
this->length = 0;
|
||||
TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
|
||||
for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
|
||||
this->length += TILE_SIZE;
|
||||
FindVehicleOnPos(tile, &rserh, FindVehiclesInRoadStop);
|
||||
}
|
||||
|
||||
this->occupied = 0;
|
||||
for (const auto &it : rserh.vehicles) {
|
||||
this->occupied += it->gcache.cached_total_length;
|
||||
}
|
||||
}
|
||||
|
||||
struct TileDataHelper
|
||||
{
|
||||
TileIndex tile; ///< The tile we are working on.
|
||||
DiagDirection dir; ///< The direction the tile is oriented following Trackdir.
|
||||
uint free = TILE_SIZE;
|
||||
};
|
||||
|
||||
/* Find the amount of free space in this tile, measured from the direction of entry. */
|
||||
Vehicle *FindTileFreeSpace(Vehicle *v, void *data)
|
||||
{
|
||||
TileDataHelper *tdh = (TileDataHelper*)data;
|
||||
|
||||
/* Exclude if not a RV, not travelling in the Trackdir direction */
|
||||
if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != tdh->dir) return nullptr;
|
||||
|
||||
RoadVehicle *rv = RoadVehicle::From(v);
|
||||
|
||||
uint veh_pos = DiagDirToAxis(tdh->dir) == AXIS_X ? rv->x_pos : rv->y_pos;
|
||||
uint tile_pos = DiagDirToAxis(tdh->dir) == AXIS_X ? TileX(tdh->tile) : TileY(tdh->tile);
|
||||
uint tile_free_space = TILE_SIZE;
|
||||
|
||||
switch (tdh->dir) {
|
||||
case DIAGDIR_NE:
|
||||
case DIAGDIR_NW:
|
||||
tile_free_space = veh_pos % tile_pos < TILE_SIZE / 2 ? TILE_SIZE / 2 : 0;
|
||||
tdh->free = std::min(tdh->free, tile_free_space);
|
||||
break;
|
||||
case DIAGDIR_SE:
|
||||
case DIAGDIR_SW:
|
||||
tile_free_space = veh_pos % tile_pos < TILE_SIZE / 2 ? 0 : TILE_SIZE / 2;
|
||||
tdh->free = std::min(tdh->free, tile_free_space);
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the amount of occupied space in this drive through stop.
|
||||
* @param rs the roadstop this entry is part of
|
||||
* @return the occupied space in tile units.
|
||||
*/
|
||||
int RoadStop::Entry::GetOccupied(const RoadStop *rs, const DiagDirection dir) const
|
||||
{
|
||||
const RoadStop::Entry *entry = rs->GetEntry(dir);
|
||||
|
||||
TileDataHelper tdh;
|
||||
tdh.dir = dir;
|
||||
|
||||
int free = 0;
|
||||
TileIndexDiff offset = TileOffsByDiagDir(dir);
|
||||
|
||||
for (TileIndex tile = rs->xy; RoadStop::IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
|
||||
tdh.tile = tile;
|
||||
FindVehicleOnPos(tile, &tdh, FindTileFreeSpace);
|
||||
free += tdh.free;
|
||||
|
||||
// Tile contains a vehicle - no need to keep calculating.
|
||||
if (tdh.free < TILE_SIZE) break;
|
||||
};
|
||||
|
||||
return entry->GetLength() - free;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the integrity of the data in this struct.
|
||||
|
@ -385,6 +371,6 @@ void RoadStop::Entry::CheckIntegrity(const RoadStop *rs) const
|
|||
assert(!IsDriveThroughRoadStopContinuation(rs->xy, rs->xy - abs(TileOffsByDiagDir(GetRoadStopDir(rs->xy)))));
|
||||
|
||||
Entry temp;
|
||||
temp.Rebuild(rs, rs->east == this);
|
||||
if (temp.length != this->length || temp.occupied != this->occupied) NOT_REACHED();
|
||||
temp.Rebuild(rs);
|
||||
if (temp.length != this->length) NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -32,13 +32,12 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
|
|||
struct Entry {
|
||||
private:
|
||||
int length; ///< The length of the stop in tile 'units'
|
||||
int occupied; ///< The amount of occupied stop in tile 'units'
|
||||
|
||||
public:
|
||||
friend struct RoadStop; ///< Oh yeah, the road stop may play with me.
|
||||
|
||||
/** Create an entry */
|
||||
Entry() : length(0), occupied(0) {}
|
||||
Entry() : length(0) {}
|
||||
|
||||
/**
|
||||
* Get the length of this drive through stop.
|
||||
|
@ -49,19 +48,9 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
|
|||
return this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of occupied space in this drive through stop.
|
||||
* @return the occupied space in tile units.
|
||||
*/
|
||||
inline int GetOccupied() const
|
||||
{
|
||||
return this->occupied;
|
||||
}
|
||||
|
||||
void Leave(const RoadVehicle *rv);
|
||||
void Enter(const RoadVehicle *rv);
|
||||
int GetOccupied(const RoadStop *rs, const DiagDirection dir) const;
|
||||
void CheckIntegrity(const RoadStop *rs) const;
|
||||
void Rebuild(const RoadStop *rs, int side = -1);
|
||||
void Rebuild(const RoadStop *rs);
|
||||
};
|
||||
|
||||
TileIndex xy; ///< Position on the map
|
||||
|
|
Loading…
Reference in New Issue