mirror of
https://github.com/OpenTTD/OpenTTD
synced 2025-12-10 15:02:06 +01:00
Fix #14631, Fix 1cb0cbcb6c: Waypoint customs spec not allocated properly on initial construction. (#14633)
Split AllocateSpecToStation/RoadStop into Allocate and Assign functions, allowing command tests to occur separately.
This commit is contained in:
@@ -561,20 +561,22 @@ const RoadStopSpec *GetRoadStopSpec(TileIndex t)
|
||||
|
||||
/**
|
||||
* Allocate a RoadStopSpec to a Station. This is called once per build operation.
|
||||
* @param statspec RoadStopSpec to allocate.
|
||||
* @param spec RoadStopSpec to allocate.
|
||||
* @param st Station to allocate it to.
|
||||
* @param exec Whether to actually allocate the spec.
|
||||
* @return Index within the Station's road stop spec list, or std::nullopt if the allocation failed.
|
||||
*/
|
||||
std::optional<uint8_t> AllocateSpecToRoadStop(const RoadStopSpec *statspec, BaseStation *st, bool exec)
|
||||
std::optional<uint8_t> AllocateSpecToRoadStop(const RoadStopSpec *spec, BaseStation *st)
|
||||
{
|
||||
uint i;
|
||||
|
||||
if (statspec == nullptr || st == nullptr) return 0;
|
||||
if (spec == nullptr) return 0;
|
||||
|
||||
/* If station doesn't exist yet then the first slot is available. */
|
||||
if (st == nullptr) return 1;
|
||||
|
||||
/* Try to find the same spec and return that one */
|
||||
for (i = 1; i < st->roadstop_speclist.size() && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
|
||||
if (st->roadstop_speclist[i].spec == statspec) return i;
|
||||
if (st->roadstop_speclist[i].spec == spec) return i;
|
||||
}
|
||||
|
||||
/* Try to find an unused spec slot */
|
||||
@@ -587,18 +589,27 @@ std::optional<uint8_t> AllocateSpecToRoadStop(const RoadStopSpec *statspec, Base
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (exec) {
|
||||
if (i >= st->roadstop_speclist.size()) st->roadstop_speclist.resize(i + 1);
|
||||
st->roadstop_speclist[i].spec = statspec;
|
||||
st->roadstop_speclist[i].grfid = statspec->grf_prop.grfid;
|
||||
st->roadstop_speclist[i].localidx = statspec->grf_prop.local_id;
|
||||
|
||||
RoadStopUpdateCachedTriggers(st);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a previously allocated RoadStopSpec specindex to a Station.
|
||||
* @param spec RoadStopSpec to assign..
|
||||
* @param st Station to allocate it to.
|
||||
* @param specindex Spec index of allocation.
|
||||
*/
|
||||
void AssignSpecToRoadStop(const RoadStopSpec *spec, BaseStation *st, uint8_t specindex)
|
||||
{
|
||||
if (specindex == 0) return;
|
||||
if (specindex >= st->roadstop_speclist.size()) st->roadstop_speclist.resize(specindex + 1);
|
||||
|
||||
st->roadstop_speclist[specindex].spec = spec;
|
||||
st->roadstop_speclist[specindex].grfid = spec->grf_prop.grfid;
|
||||
st->roadstop_speclist[specindex].localidx = spec->grf_prop.local_id;
|
||||
|
||||
RoadStopUpdateCachedTriggers(st);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocate a RoadStopSpec from a Station. Called when removing a single roadstop tile.
|
||||
* @param st Station to work with.
|
||||
|
||||
@@ -177,7 +177,8 @@ bool GetIfClassHasNewStopsByType(const RoadStopClass *roadstopclass, RoadStopTyp
|
||||
bool GetIfStopIsForType(const RoadStopSpec *roadstopspec, RoadStopType rs, RoadType roadtype);
|
||||
|
||||
const RoadStopSpec *GetRoadStopSpec(TileIndex t);
|
||||
std::optional<uint8_t> AllocateSpecToRoadStop(const RoadStopSpec *statspec, BaseStation *st, bool exec);
|
||||
std::optional<uint8_t> AllocateSpecToRoadStop(const RoadStopSpec *spec, BaseStation *st);
|
||||
void AssignSpecToRoadStop(const RoadStopSpec *spec, BaseStation *st, uint8_t specindex);
|
||||
void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex);
|
||||
void RoadStopUpdateCachedTriggers(BaseStation *st);
|
||||
|
||||
|
||||
@@ -692,16 +692,18 @@ CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_til
|
||||
|
||||
/**
|
||||
* Allocate a StationSpec to a Station. This is called once per build operation.
|
||||
* @param statspec StationSpec to allocate.
|
||||
* @param spec StationSpec to allocate.
|
||||
* @param st Station to allocate it to.
|
||||
* @param exec Whether to actually allocate the spec.
|
||||
* @return Index within the Station's station spec list, or std::nullopt if the allocation failed.
|
||||
*/
|
||||
std::optional<uint8_t> AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec)
|
||||
std::optional<uint8_t> AllocateSpecToStation(const StationSpec *spec, BaseStation *st)
|
||||
{
|
||||
uint i;
|
||||
|
||||
if (statspec == nullptr || st == nullptr) return 0;
|
||||
if (spec == nullptr) return 0;
|
||||
|
||||
/* If station doesn't exist yet then the first slot is available. */
|
||||
if (st == nullptr) return 1;
|
||||
|
||||
for (i = 1; i < st->speclist.size() && i < NUM_STATIONSSPECS_PER_STATION; i++) {
|
||||
if (st->speclist[i].spec == nullptr && st->speclist[i].grfid == 0) break;
|
||||
@@ -714,24 +716,32 @@ std::optional<uint8_t> AllocateSpecToStation(const StationSpec *statspec, BaseSt
|
||||
* but it's fairly unlikely that one reaches the limit anyways.
|
||||
*/
|
||||
for (i = 1; i < st->speclist.size() && i < NUM_STATIONSSPECS_PER_STATION; i++) {
|
||||
if (st->speclist[i].spec == statspec) return i;
|
||||
if (st->speclist[i].spec == spec) return i;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (exec) {
|
||||
if (i >= st->speclist.size()) st->speclist.resize(i + 1);
|
||||
st->speclist[i].spec = statspec;
|
||||
st->speclist[i].grfid = statspec->grf_prop.grfid;
|
||||
st->speclist[i].localidx = statspec->grf_prop.local_id;
|
||||
|
||||
StationUpdateCachedTriggers(st);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a previously allocated StationSpec specindex to a Station.
|
||||
* @param spec StationSpec to assign..
|
||||
* @param st Station to allocate it to.
|
||||
* @param specindex Spec index of allocation.
|
||||
*/
|
||||
void AssignSpecToStation(const StationSpec *spec, BaseStation *st, uint8_t specindex)
|
||||
{
|
||||
if (specindex == 0) return;
|
||||
if (specindex >= st->speclist.size()) st->speclist.resize(specindex + 1);
|
||||
|
||||
st->speclist[specindex].spec = spec;
|
||||
st->speclist[specindex].grfid = spec->grf_prop.grfid;
|
||||
st->speclist[specindex].localidx = spec->grf_prop.local_id;
|
||||
|
||||
StationUpdateCachedTriggers(st);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocate a StationSpec from a Station. Called when removing a single station tile.
|
||||
|
||||
@@ -215,7 +215,8 @@ SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseS
|
||||
uint16_t GetStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, BaseStation *st, TileIndex tile, std::span<int32_t> regs100 = {});
|
||||
CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_tile, const StationSpec *statspec, Axis axis, uint8_t plat_len, uint8_t numtracks);
|
||||
|
||||
std::optional<uint8_t> AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec);
|
||||
std::optional<uint8_t> AllocateSpecToStation(const StationSpec *spec, BaseStation *st);
|
||||
void AssignSpecToStation(const StationSpec *spec, BaseStation *st, uint8_t specindex);
|
||||
void DeallocateSpecFromStation(BaseStation *st, uint8_t specindex);
|
||||
bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station);
|
||||
|
||||
|
||||
@@ -136,7 +136,8 @@ void MoveWaypointsToBaseStations()
|
||||
SetRailStationReservation(tile, reserved);
|
||||
|
||||
if (wp.spec != nullptr) {
|
||||
auto specindex = AllocateSpecToStation(wp.spec, new_wp, true);
|
||||
auto specindex = AllocateSpecToStation(wp.spec, new_wp);
|
||||
if (specindex.has_value()) AssignSpecToStation(wp.spec, new_wp, *specindex);
|
||||
SetCustomStationSpecIndex(tile, specindex.value_or(0));
|
||||
}
|
||||
new_wp->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
|
||||
|
||||
@@ -1491,7 +1491,7 @@ CommandCost CmdBuildRailStation(DoCommandFlags flags, TileIndex tile_org, RailTy
|
||||
}
|
||||
|
||||
/* Check if we can allocate a custom stationspec to this station */
|
||||
auto specindex = AllocateSpecToStation(statspec, st, flags.Test(DoCommandFlag::Execute));
|
||||
auto specindex = AllocateSpecToStation(statspec, st);
|
||||
if (!specindex.has_value()) return CommandCost(STR_ERROR_TOO_MANY_STATION_SPECS);
|
||||
|
||||
if (statspec != nullptr) {
|
||||
@@ -1514,6 +1514,7 @@ CommandCost CmdBuildRailStation(DoCommandFlags flags, TileIndex tile_org, RailTy
|
||||
|
||||
st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
|
||||
|
||||
if (specindex.has_value()) AssignSpecToStation(statspec, st, *specindex);
|
||||
if (statspec != nullptr) {
|
||||
/* Include this station spec's animation trigger bitmask
|
||||
* in the station's cached copy. */
|
||||
@@ -2113,7 +2114,7 @@ CommandCost CmdBuildRoadStop(DoCommandFlags flags, TileIndex tile, uint8_t width
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
/* Check if we can allocate a custom stationspec to this station */
|
||||
auto specindex = AllocateSpecToRoadStop(roadstopspec, st, flags.Test(DoCommandFlag::Execute));
|
||||
auto specindex = AllocateSpecToRoadStop(roadstopspec, st);
|
||||
if (!specindex.has_value()) return CommandCost(STR_ERROR_TOO_MANY_STATION_SPECS);
|
||||
|
||||
if (roadstopspec != nullptr) {
|
||||
@@ -2127,6 +2128,7 @@ CommandCost CmdBuildRoadStop(DoCommandFlags flags, TileIndex tile, uint8_t width
|
||||
}
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
if (specindex.has_value()) AssignSpecToRoadStop(roadstopspec, st, *specindex);
|
||||
/* Check every tile in the area. */
|
||||
for (TileIndex cur_tile : roadstop_area) {
|
||||
/* Get existing road types and owners before any tile clearing */
|
||||
|
||||
@@ -271,7 +271,8 @@ CommandCost CmdBuildRailWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
||||
if (!Waypoint::CanAllocateItem()) return CommandCost(STR_ERROR_TOO_MANY_STATIONS_LOADING);
|
||||
}
|
||||
|
||||
auto specindex = AllocateSpecToStation(spec, wp, flags.Test(DoCommandFlag::Execute));
|
||||
/* Check if we can allocate a custom spec to this waypoint. */
|
||||
auto specindex = AllocateSpecToStation(spec, wp);
|
||||
if (!specindex.has_value()) return CommandCost(STR_ERROR_TOO_MANY_STATION_SPECS);
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
@@ -284,6 +285,7 @@ CommandCost CmdBuildRailWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
||||
wp->owner = GetTileOwner(start_tile);
|
||||
|
||||
wp->rect.BeforeAddRect(start_tile, width, height, StationRect::ADD_TRY);
|
||||
if (specindex.has_value()) AssignSpecToStation(spec, wp, *specindex);
|
||||
|
||||
wp->delete_ctr = 0;
|
||||
wp->facilities.Set(StationFacility::Train);
|
||||
@@ -391,8 +393,8 @@ CommandCost CmdBuildRoadWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
||||
if (!Waypoint::CanAllocateItem()) return CommandCost(STR_ERROR_TOO_MANY_STATIONS_LOADING);
|
||||
}
|
||||
|
||||
/* Check if we can allocate a custom roadstopspec to this station */
|
||||
auto specindex = AllocateSpecToRoadStop(roadstopspec, wp, flags.Test(DoCommandFlag::Execute));
|
||||
/* Check if we can allocate a custom spec to this waypoint. */
|
||||
auto specindex = AllocateSpecToRoadStop(roadstopspec, wp);
|
||||
if (!specindex.has_value()) return CommandCost(STR_ERROR_TOO_MANY_STATION_SPECS);
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
@@ -406,6 +408,7 @@ CommandCost CmdBuildRoadWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
||||
wp->owner = _current_company;
|
||||
|
||||
wp->rect.BeforeAddRect(start_tile, width, height, StationRect::ADD_TRY);
|
||||
if (specindex.has_value()) AssignSpecToRoadStop(roadstopspec, wp, *specindex);
|
||||
|
||||
if (roadstopspec != nullptr) {
|
||||
/* Include this road stop spec's animation trigger bitmask
|
||||
|
||||
Reference in New Issue
Block a user