1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
8 /** @file base_station_base.h Base classes/functions for base stations. */
9 
10 #ifndef BASE_STATION_BASE_H
11 #define BASE_STATION_BASE_H
12 
13 #include "core/pool_type.hpp"
14 #include "command_type.h"
15 #include "viewport_type.h"
16 #include "station_map.h"
17 
18 typedef Pool<BaseStation, StationID, 32, 64000> StationPool;
19 extern StationPool _station_pool;
20 
21 struct StationSpecList {
22 	const StationSpec *spec;
23 	uint32 grfid;      ///< GRF ID of this custom station
24 	uint8  localidx;   ///< Station ID within GRF of station
25 };
26 
27 
28 /** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */
29 struct StationRect : public Rect {
30 	enum StationRectMode
31 	{
32 		ADD_TEST = 0,
33 		ADD_TRY,
34 		ADD_FORCE
35 	};
36 
37 	StationRect();
38 	void MakeEmpty();
39 	bool PtInExtendedRect(int x, int y, int distance = 0) const;
40 	bool IsEmpty() const;
41 	CommandCost BeforeAddTile(TileIndex tile, StationRectMode mode);
42 	CommandCost BeforeAddRect(TileIndex tile, int w, int h, StationRectMode mode);
43 	bool AfterRemoveTile(BaseStation *st, TileIndex tile);
44 	bool AfterRemoveRect(BaseStation *st, TileArea ta);
45 
46 	static bool ScanForStationTiles(StationID st_id, int left_a, int top_a, int right_a, int bottom_a);
47 
48 	StationRect& operator = (const Rect &src);
49 };
50 
51 /** Base class for all station-ish types */
52 struct BaseStation : StationPool::PoolItem<&_station_pool> {
53 	TileIndex xy;                   ///< Base tile of the station
54 	TrackedViewportSign sign;       ///< NOSAVE: Dimensions of sign
55 	byte delete_ctr;                ///< Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is deleted.
56 
57 	std::string name;               ///< Custom name
58 	StringID string_id;             ///< Default name (town area) of station
59 	mutable std::string cached_name; ///< NOSAVE: Cache of the resolved name of the station, if not using a custom name
60 
61 	Town *town;                     ///< The town this station is associated with
62 	Owner owner;                    ///< The owner of this station
63 	StationFacility facilities;     ///< The facilities that this station has
64 
65 	uint8 num_specs;                ///< Number of specs in the speclist
66 	StationSpecList *speclist;      ///< List of station specs of this station
67 
68 	Date build_date;                ///< Date of construction
69 
70 	uint16 random_bits;             ///< Random bits assigned to this station
71 	byte waiting_triggers;          ///< Waiting triggers (NewGRF) for this station
72 	uint8 cached_anim_triggers;     ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
73 	CargoTypes cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask
74 
75 	TileArea train_station;         ///< Tile area the train 'station' part covers
76 	StationRect rect;               ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions
77 
78 	/**
79 	 * Initialize the base station.
80 	 * @param tile The location of the station sign
81 	 */
BaseStationBaseStation82 	BaseStation(TileIndex tile) :
83 		xy(tile),
84 		train_station(INVALID_TILE, 0, 0)
85 	{
86 	}
87 
88 	virtual ~BaseStation();
89 
90 	/**
91 	 * Check whether a specific tile belongs to this station.
92 	 * @param tile the tile to check
93 	 * @return true if the tile belongs to this station
94 	 */
95 	virtual bool TileBelongsToRailStation(TileIndex tile) const = 0;
96 
97 	/**
98 	 * Helper function to get a NewGRF variable that isn't implemented by the base class.
99 	 * @param object the resolver object related to this query
100 	 * @param variable that is queried
101 	 * @param parameter parameter for that variable
102 	 * @param available will return false if ever the variable asked for does not exist
103 	 * @return the value stored in the corresponding variable
104 	 */
105 	virtual uint32 GetNewGRFVariable(const struct ResolverObject &object, byte variable, byte parameter, bool *available) const = 0;
106 
107 	/**
108 	 * Update the coordinated of the sign (as shown in the viewport).
109 	 */
110 	virtual void UpdateVirtCoord() = 0;
111 
GetCachedNameBaseStation112 	inline const char *GetCachedName() const
113 	{
114 		if (!this->name.empty()) return this->name.c_str();
115 		if (this->cached_name.empty()) this->FillCachedName();
116 		return this->cached_name.c_str();
117 	}
118 
MoveSignBaseStation119 	virtual void MoveSign(TileIndex new_xy)
120 	{
121 		this->xy = new_xy;
122 		this->UpdateVirtCoord();
123 	}
124 
125 	/**
126 	 * Get the tile area for a given station type.
127 	 * @param ta tile area to fill.
128 	 * @param type the type of the area
129 	 */
130 	virtual void GetTileArea(TileArea *ta, StationType type) const = 0;
131 
132 
133 	/**
134 	 * Obtain the length of a platform
135 	 * @pre tile must be a rail station tile
136 	 * @param tile A tile that contains the platform in question
137 	 * @return The length of the platform
138 	 */
139 	virtual uint GetPlatformLength(TileIndex tile) const = 0;
140 
141 	/**
142 	 * Determines the REMAINING length of a platform, starting at (and including)
143 	 * the given tile.
144 	 * @param tile the tile from which to start searching. Must be a rail station tile
145 	 * @param dir The direction in which to search.
146 	 * @return The platform length
147 	 */
148 	virtual uint GetPlatformLength(TileIndex tile, DiagDirection dir) const = 0;
149 
150 	/**
151 	 * Get the base station belonging to a specific tile.
152 	 * @param tile The tile to get the base station from.
153 	 * @return the station associated with that tile.
154 	 */
GetByTileBaseStation155 	static inline BaseStation *GetByTile(TileIndex tile)
156 	{
157 		return BaseStation::Get(GetStationIndex(tile));
158 	}
159 
160 	/**
161 	 * Check whether the base station currently is in use; in use means
162 	 * that it is not scheduled for deletion and that it still has some
163 	 * facilities left.
164 	 * @return true if still in use
165 	 */
IsInUseBaseStation166 	inline bool IsInUse() const
167 	{
168 		return (this->facilities & ~FACIL_WAYPOINT) != 0;
169 	}
170 
171 	static void PostDestructor(size_t index);
172 
173 private:
174 	void FillCachedName() const;
175 };
176 
177 /**
178  * Class defining several overloaded accessors so we don't
179  * have to cast base stations that often
180  */
181 template <class T, bool Tis_waypoint>
182 struct SpecializedStation : public BaseStation {
183 	static const StationFacility EXPECTED_FACIL = Tis_waypoint ? FACIL_WAYPOINT : FACIL_NONE; ///< Specialized type
184 
185 	/**
186 	 * Set station type correctly
187 	 * @param tile The base tile of the station.
188 	 */
189 	inline SpecializedStation<T, Tis_waypoint>(TileIndex tile) :
BaseStationSpecializedStation190 			BaseStation(tile)
191 	{
192 		this->facilities = EXPECTED_FACIL;
193 	}
194 
195 	/**
196 	 * Helper for checking whether the given station is of this type.
197 	 * @param st the station to check.
198 	 * @return true if the station is the type we expect it to be.
199 	 */
IsExpectedSpecializedStation200 	static inline bool IsExpected(const BaseStation *st)
201 	{
202 		return (st->facilities & FACIL_WAYPOINT) == EXPECTED_FACIL;
203 	}
204 
205 	/**
206 	 * Tests whether given index is a valid index for station of this type
207 	 * @param index tested index
208 	 * @return is this index valid index of T?
209 	 */
IsValidIDSpecializedStation210 	static inline bool IsValidID(size_t index)
211 	{
212 		return BaseStation::IsValidID(index) && IsExpected(BaseStation::Get(index));
213 	}
214 
215 	/**
216 	 * Gets station with given index
217 	 * @return pointer to station with given index casted to T *
218 	 */
GetSpecializedStation219 	static inline T *Get(size_t index)
220 	{
221 		return (T *)BaseStation::Get(index);
222 	}
223 
224 	/**
225 	 * Returns station if the index is a valid index for this station type
226 	 * @return pointer to station with given index if it's a station of this type
227 	 */
GetIfValidSpecializedStation228 	static inline T *GetIfValid(size_t index)
229 	{
230 		return IsValidID(index) ? Get(index) : nullptr;
231 	}
232 
233 	/**
234 	 * Get the station belonging to a specific tile.
235 	 * @param tile The tile to get the station from.
236 	 * @return the station associated with that tile.
237 	 */
GetByTileSpecializedStation238 	static inline T *GetByTile(TileIndex tile)
239 	{
240 		return GetIfValid(GetStationIndex(tile));
241 	}
242 
243 	/**
244 	 * Converts a BaseStation to SpecializedStation with type checking.
245 	 * @param st BaseStation pointer
246 	 * @return pointer to SpecializedStation
247 	 */
FromSpecializedStation248 	static inline T *From(BaseStation *st)
249 	{
250 		assert(IsExpected(st));
251 		return (T *)st;
252 	}
253 
254 	/**
255 	 * Converts a const BaseStation to const SpecializedStation with type checking.
256 	 * @param st BaseStation pointer
257 	 * @return pointer to SpecializedStation
258 	 */
FromSpecializedStation259 	static inline const T *From(const BaseStation *st)
260 	{
261 		assert(IsExpected(st));
262 		return (const T *)st;
263 	}
264 
265 	/**
266 	 * Returns an iterable ensemble of all valid stations of type T
267 	 * @param from index of the first station to consider
268 	 * @return an iterable ensemble of all valid stations of type T
269 	 */
270 	static Pool::IterateWrapper<T> Iterate(size_t from = 0) { return Pool::IterateWrapper<T>(from); }
271 };
272 
273 #endif /* BASE_STATION_BASE_H */
274