diff --git a/src/base_station_base.h b/src/base_station_base.h index c2d3cee6cf..a34b3dd839 100644 --- a/src/base_station_base.h +++ b/src/base_station_base.h @@ -33,6 +33,11 @@ struct RoadStopSpecList { uint8 localidx; ///< Station ID within GRF of road stop }; +struct RoadStopTileData { + TileIndex tile; + uint8 random_bits; + uint8 animation_frame; +}; /** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */ struct StationRect : public Rect { @@ -86,8 +91,7 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { TileArea train_station; ///< Tile area the train 'station' part covers StationRect rect; ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions - std::vector custom_road_stop_tiles; ///< List of custom road stop tiles - std::vector custom_road_stop_data; ///< Custom road stop random bits (low) and animation byte (high) in same order as custom_road_stop_tiles + std::vector custom_roadstop_tile_data; ///< List of custom road stop tile data /** * Initialize the base station. @@ -192,30 +196,28 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { return (this->facilities & facilities) != 0; } - inline uint GetRoadStopData(TileIndex tile) const + inline byte GetRoadStopRandomBits(TileIndex tile) const { - for (size_t i = 0; i < this->custom_road_stop_tiles.size(); i++) { - if (this->custom_road_stop_tiles[i] == tile) return this->custom_road_stop_data[i]; + for (const RoadStopTileData &tile_data : this->custom_roadstop_tile_data) { + if (tile_data.tile == tile) return tile_data.random_bits; } return 0; } - inline byte GetRoadStopRandomBits(TileIndex tile) const - { - return GB(this->GetRoadStopData(tile), 0, 8); - } - inline byte GetRoadStopAnimationFrame(TileIndex tile) const { - return GB(this->GetRoadStopData(tile), 8, 8); + for (const RoadStopTileData &tile_data : this->custom_roadstop_tile_data) { + if (tile_data.tile == tile) return tile_data.animation_frame; + } + return 0; } private: - bool SetRoadStopTileData(TileIndex tile, byte data, byte offset); + bool SetRoadStopTileData(TileIndex tile, byte data, bool animation); public: - inline void SetRoadStopRandomBits(TileIndex tile, byte random_bits) { this->SetRoadStopTileData(tile, random_bits, 0); } - inline bool SetRoadStopAnimationFrame(TileIndex tile, byte frame) { return this->SetRoadStopTileData(tile, frame, 8); } + inline void SetRoadStopRandomBits(TileIndex tile, byte random_bits) { this->SetRoadStopTileData(tile, random_bits, false); } + inline bool SetRoadStopAnimationFrame(TileIndex tile, byte frame) { return this->SetRoadStopTileData(tile, frame, true); } void RemoveRoadStopTileData(TileIndex tile); static void PostDestructor(size_t index); diff --git a/src/newgrf_roadstop.cpp b/src/newgrf_roadstop.cpp index 664f1ff187..275f9ab988 100644 --- a/src/newgrf_roadstop.cpp +++ b/src/newgrf_roadstop.cpp @@ -402,8 +402,8 @@ void TriggerRoadStopAnimation(BaseStation *st, TileIndex trigger_tile, StationAn }; if (trigger == SAT_NEW_CARGO || trigger == SAT_CARGO_TAKEN || trigger == SAT_250_TICKS) { - for (TileIndex cur_tile : st->custom_road_stop_tiles) { - process_tile(cur_tile); + for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) { + process_tile(tile_data.tile); } } else { process_tile(trigger_tile); @@ -477,8 +477,8 @@ void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTri } }; if (trigger == RSRT_NEW_CARGO || trigger == RSRT_CARGO_TAKEN) { - for (TileIndex cur_tile : st->custom_road_stop_tiles) { - process_tile(cur_tile); + for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) { + process_tile(tile_data.tile); } } else { process_tile(tile); @@ -597,8 +597,8 @@ void DeallocateRoadStopSpecFromStation(BaseStation *st, byte specindex) if (specindex == 0) return; /* Check custom road stop tiles if the specindex is still in use */ - for (TileIndex tile : st->custom_road_stop_tiles) { - if (GetCustomRoadStopSpecIndex(tile) == specindex) { + for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) { + if (GetCustomRoadStopSpecIndex(tile_data.tile) == specindex) { return; } } diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 98b6819bd4..33a638d265 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -171,7 +171,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_ROAD_WAYPOINTS, XSCF_NULL, 1, 1, "road_waypoints", nullptr, nullptr, nullptr }, { XSLFI_MORE_STATION_TYPES, XSCF_NULL, 1, 1, "more_station_types", nullptr, nullptr, nullptr }, { XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr }, - { XSLFI_GRF_ROADSTOPS, XSCF_NULL, 1, 1, "grf_road_stops", nullptr, nullptr, nullptr }, + { XSLFI_GRF_ROADSTOPS, XSCF_NULL, 2, 2, "grf_road_stops", nullptr, nullptr, nullptr }, { XSLFI_INDUSTRY_ANIM_MASK, XSCF_IGNORABLE_ALL, 1, 1, "industry_anim_mask", nullptr, nullptr, nullptr }, { XSLFI_NEW_SIGNAL_STYLES, XSCF_NULL, 2, 2, "new_signal_styles", nullptr, nullptr, "XBST,NSID" }, { XSLFI_NO_TREE_COUNTER, XSCF_IGNORABLE_ALL, 1, 1, "no_tree_counter", nullptr, nullptr, nullptr }, diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 30b9e34163..7a2b8393b1 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -25,6 +25,9 @@ static byte _old_last_vehicle_type; static uint8 _num_specs; static uint8 _num_roadstop_specs; +static uint32 _num_roadstop_custom_tiles; +static std::vector _custom_road_stop_tiles; +static std::vector _custom_road_stop_data; /** * Update the buoy orders to be waypoint orders. @@ -414,8 +417,9 @@ static const SaveLoad _base_station_desc[] = { SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8), SLEG_VAR(_num_specs, SLE_UINT8), SLEG_CONDVAR_X(_num_roadstop_specs, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS)), - SLE_CONDVARVEC_X(BaseStation, custom_road_stop_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS)), - SLE_CONDVARVEC_X(BaseStation, custom_road_stop_data, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS)), + SLEG_CONDVARVEC_X(_custom_road_stop_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 1, 1)), + SLEG_CONDVARVEC_X(_custom_road_stop_data, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 1, 1)), + SLEG_CONDVAR_X(_num_roadstop_custom_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS, 2)), }; static OldPersistentStorage _old_st_persistent_storage; @@ -481,6 +485,12 @@ static const SaveLoad _waypoint_desc[] = { SLE_CONDVAR_X(Waypoint, road_waypoint_area.h, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS)), }; +static const SaveLoad _custom_roadstop_tile_data_desc[] = { + SLE_VAR(RoadStopTileData, tile, SLE_UINT32), + SLE_VAR(RoadStopTileData, random_bits, SLE_UINT8), + SLE_VAR(RoadStopTileData, animation_frame, SLE_UINT8), +}; + /** * Get the base station description to be used for SL_ST_INCLUDE * @return the base station description. @@ -515,6 +525,7 @@ static void RealSave_STNN(BaseStation *bst) { _num_specs = (uint8)bst->speclist.size(); _num_roadstop_specs = (uint8)bst->roadstop_speclist.size(); + _num_roadstop_custom_tiles = (uint32)bst->custom_roadstop_tile_data.size(); bool waypoint = (bst->facilities & FACIL_WAYPOINT) != 0; SlObjectSaveFiltered(bst, waypoint ? SaveLoadTable(_filtered_waypoint_desc) : SaveLoadTable(_filtered_station_desc)); @@ -575,6 +586,10 @@ static void RealSave_STNN(BaseStation *bst) for (uint i = 0; i < bst->roadstop_speclist.size(); i++) { SlObjectSaveFiltered(&bst->roadstop_speclist[i], _filtered_station_speclist_desc); } + + for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) { + SlObjectSaveFiltered(&bst->custom_roadstop_tile_data[i], _custom_roadstop_tile_data_desc); // _custom_roadstop_tile_data_desc has no conditionals + } } static void Save_STNN() @@ -595,6 +610,7 @@ static void Load_STNN() _num_flows = 0; _num_specs = 0; _num_roadstop_specs = 0; + _num_roadstop_custom_tiles = 0; const uint num_cargo = IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; ReadBuffer *buffer = ReadBuffer::GetCurrent(); @@ -714,6 +730,22 @@ static void Load_STNN() SlObjectLoadFiltered(&bst->roadstop_speclist[i], _filtered_station_speclist_desc); } } + + if (_num_roadstop_custom_tiles != 0) { + /* Allocate custom road stop tile data memory when loading a game */ + bst->custom_roadstop_tile_data.resize(_num_roadstop_custom_tiles); + for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) { + SlObjectLoadFiltered(&bst->custom_roadstop_tile_data[i], _custom_roadstop_tile_data_desc); // _custom_roadstop_tile_data_desc has no conditionals + } + } + + if (SlXvIsFeaturePresent(XSLFI_GRF_ROADSTOPS, 1, 1)) { + for (size_t i = 0; i < _custom_road_stop_tiles.size(); i++) { + bst->custom_roadstop_tile_data.push_back({ _custom_road_stop_tiles[i], (uint8)GB(_custom_road_stop_data[i], 0, 8), (uint8)GB(_custom_road_stop_data[i], 8, 8) }); + } + _custom_road_stop_tiles.clear(); + _custom_road_stop_data.clear(); + } } } diff --git a/src/station.cpp b/src/station.cpp index 4b0e08de03..7bccab4387 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -183,28 +183,30 @@ void BaseStation::PostDestructor(size_t index) InvalidateWindowData(WC_SELECT_STATION, 0, 0); } -bool BaseStation::SetRoadStopTileData(TileIndex tile, byte data, byte offset) +bool BaseStation::SetRoadStopTileData(TileIndex tile, byte data, bool animation) { - for (size_t i = 0; i < this->custom_road_stop_tiles.size(); i++) { - if (this->custom_road_stop_tiles[i] == tile) { - if (GB(this->custom_road_stop_data[i], offset, 8) == data) return false; - SB(this->custom_road_stop_data[i], offset, 8, data); + for (RoadStopTileData &tile_data : this->custom_roadstop_tile_data) { + if (tile_data.tile == tile) { + uint8 &value = animation ? tile_data.animation_frame : tile_data.random_bits; + if (value == data) return false; + value = data; return true; } } - this->custom_road_stop_tiles.push_back(tile); - this->custom_road_stop_data.push_back(((uint)data) << offset); + RoadStopTileData tile_data; + tile_data.tile = tile; + tile_data.animation_frame = animation ? data : 0; + tile_data.random_bits = animation ? 0 : data; + this->custom_roadstop_tile_data.push_back(tile_data); return data != 0; } void BaseStation::RemoveRoadStopTileData(TileIndex tile) { - for (size_t i = 0; i < this->custom_road_stop_tiles.size(); i++) { - if (this->custom_road_stop_tiles[i] == tile) { - this->custom_road_stop_tiles[i] = this->custom_road_stop_tiles.back(); - this->custom_road_stop_data[i] = this->custom_road_stop_data.back(); - this->custom_road_stop_tiles.pop_back(); - this->custom_road_stop_data.pop_back(); + for (RoadStopTileData &tile_data : this->custom_roadstop_tile_data) { + if (tile_data.tile == tile) { + tile_data = this->custom_roadstop_tile_data.back(); + this->custom_roadstop_tile_data.pop_back(); return; } }