OpenTTD Source 20250529-master-g10c159a79f
newgrf_station.cpp
Go to the documentation of this file.
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
10#include "stdafx.h"
11#include "debug.h"
12#include "station_base.h"
13#include "waypoint_base.h"
14#include "roadstop_base.h"
15#include "newgrf_badge.h"
16#include "newgrf_cargo.h"
17#include "newgrf_station.h"
18#include "newgrf_spritegroup.h"
19#include "newgrf_sound.h"
20#include "newgrf_railtype.h"
21#include "town.h"
22#include "newgrf_town.h"
23#include "company_func.h"
24#include "tunnelbridge_map.h"
27
28#include "table/strings.h"
29
30#include "newgrf_class_func.h"
31
32#include "safeguards.h"
33
34
35template <>
36/* static */ void StationClass::InsertDefaults()
37{
38 /* Set up initial data */
39 StationClass::Get(StationClass::Allocate(STATION_CLASS_LABEL_DEFAULT))->name = STR_STATION_CLASS_DFLT;
40 StationClass::Get(StationClass::Allocate(STATION_CLASS_LABEL_DEFAULT))->Insert(nullptr);
41 StationClass::Get(StationClass::Allocate(STATION_CLASS_LABEL_WAYPOINT))->name = STR_STATION_CLASS_WAYP;
42 StationClass::Get(StationClass::Allocate(STATION_CLASS_LABEL_WAYPOINT))->Insert(nullptr);
43}
44
45template <>
46bool StationClass::IsUIAvailable(uint) const
47{
48 return true;
49}
50
51/* Instantiate StationClass. */
53
54static const uint NUM_STATIONSSPECS_PER_STATION = 255;
55
61{
62 uint8_t res = 0;
67 return res;
68}
69
70enum TriggerArea : uint8_t {
71 TA_TILE,
72 TA_PLATFORM,
73 TA_WHOLE,
74};
75
77 ETileArea(const BaseStation *st, TileIndex tile, TriggerArea ta)
78 {
79 switch (ta) {
80 default: NOT_REACHED();
81
82 case TA_TILE:
83 this->tile = tile;
84 this->w = 1;
85 this->h = 1;
86 break;
87
88 case TA_PLATFORM: {
89 TileIndex start, end;
90 Axis axis = GetRailStationAxis(tile);
91 TileIndexDiff delta = TileOffsByAxis(axis);
92
93 for (end = tile; IsRailStationTile(end + delta) && IsCompatibleTrainStationTile(end + delta, tile); end += delta) { /* Nothing */ }
94 for (start = tile; IsRailStationTile(start - delta) && IsCompatibleTrainStationTile(start - delta, tile); start -= delta) { /* Nothing */ }
95
96 this->tile = start;
97 this->w = TileX(end) - TileX(start) + 1;
98 this->h = TileY(end) - TileY(start) + 1;
99 break;
100 }
101
102 case TA_WHOLE:
103 st->GetTileArea(this, Station::IsExpected(st) ? StationType::Rail : StationType::RailWaypoint);
104 break;
105 }
106 }
107};
108
109
122uint32_t GetPlatformInfo(Axis axis, uint8_t tile, int platforms, int length, int x, int y, bool centred)
123{
124 uint32_t retval = 0;
125
126 if (axis == AXIS_X) {
127 std::swap(platforms, length);
128 std::swap(x, y);
129 }
130
131 if (centred) {
132 x -= platforms / 2;
133 y -= length / 2;
134 x = Clamp(x, -8, 7);
135 y = Clamp(y, -8, 7);
136 SB(retval, 0, 4, y & 0xF);
137 SB(retval, 4, 4, x & 0xF);
138 } else {
139 SB(retval, 0, 4, std::min(15, y));
140 SB(retval, 4, 4, std::min(15, length - y - 1));
141 SB(retval, 8, 4, std::min(15, x));
142 SB(retval, 12, 4, std::min(15, platforms - x - 1));
143 }
144 SB(retval, 16, 4, std::min(15, length));
145 SB(retval, 20, 4, std::min(15, platforms));
146 SB(retval, 24, 8, tile);
147
148 return retval;
149}
150
151
160static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis)
161{
162 uint8_t orig_type = 0;
163 Axis orig_axis = AXIS_X;
164 StationID sid = GetStationIndex(tile);
165
166 if (check_type) orig_type = GetCustomStationSpecIndex(tile);
167 if (check_axis) orig_axis = GetRailStationAxis(tile);
168
169 for (;;) {
170 TileIndex new_tile = TileAdd(tile, delta);
171
172 if (!IsTileType(new_tile, MP_STATION) || GetStationIndex(new_tile) != sid) break;
173 if (!HasStationRail(new_tile)) break;
174 if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break;
175 if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break;
176
177 tile = new_tile;
178 }
179 return tile;
180}
181
182
183static uint32_t GetPlatformInfoHelper(TileIndex tile, bool check_type, bool check_axis, bool centred)
184{
185 int tx = TileX(tile);
186 int ty = TileY(tile);
187 int sx = TileX(FindRailStationEnd(tile, TileDiffXY(-1, 0), check_type, check_axis));
188 int sy = TileY(FindRailStationEnd(tile, TileDiffXY( 0, -1), check_type, check_axis));
189 int ex = TileX(FindRailStationEnd(tile, TileDiffXY( 1, 0), check_type, check_axis)) + 1;
190 int ey = TileY(FindRailStationEnd(tile, TileDiffXY( 0, 1), check_type, check_axis)) + 1;
191
192 tx -= sx; ex -= sx;
193 ty -= sy; ey -= sy;
194
195 return GetPlatformInfo(GetRailStationAxis(tile), GetStationGfx(tile), ex, ey, tx, ty, centred);
196}
197
198
199static uint32_t GetRailContinuationInfo(TileIndex tile)
200{
201 /* Tile offsets and exit dirs for X axis */
202 static const Direction x_dir[8] = { DIR_SW, DIR_NE, DIR_SE, DIR_NW, DIR_S, DIR_E, DIR_W, DIR_N };
204
205 /* Tile offsets and exit dirs for Y axis */
206 static const Direction y_dir[8] = { DIR_SE, DIR_NW, DIR_SW, DIR_NE, DIR_S, DIR_W, DIR_E, DIR_N };
208
209 Axis axis = GetRailStationAxis(tile);
210
211 /* Choose appropriate lookup table to use */
212 const Direction *dir = axis == AXIS_X ? x_dir : y_dir;
213 const DiagDirection *diagdir = axis == AXIS_X ? x_exits : y_exits;
214
215 uint32_t res = 0;
216 uint i;
217
218 for (i = 0; i < lengthof(x_dir); i++, dir++, diagdir++) {
219 TileIndex neighbour_tile = tile + TileOffsByDir(*dir);
220 TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(neighbour_tile, TRANSPORT_RAIL, 0));
221 if (trackbits != TRACK_BIT_NONE) {
222 /* If there is any track on the tile, set the bit in the second byte */
223 SetBit(res, i + 8);
224
225 /* With tunnels and bridges the tile has tracks, but they are not necessarily connected
226 * with the next tile because the ramp is not going in the right direction. */
227 if (IsTileType(neighbour_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(neighbour_tile) != *diagdir) {
228 continue;
229 }
230
231 /* If any track reaches our exit direction, set the bit in the lower byte */
232 if (trackbits & DiagdirReachesTracks(*diagdir)) SetBit(res, i);
233 }
234 }
235
236 return res;
237}
238
239
240/* Station Resolver Functions */
241/* virtual */ uint32_t StationScopeResolver::GetRandomBits() const
242{
243 return (this->st == nullptr ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16);
244}
245
246
247/* virtual */ uint32_t StationScopeResolver::GetRandomTriggers() const
248{
249 return this->st == nullptr ? 0 : this->st->waiting_random_triggers.base();
250}
251
252
259{
260 if (!this->town_scope.has_value()) {
261 Town *t = nullptr;
262 if (this->station_scope.st != nullptr) {
263 t = this->station_scope.st->town;
264 } else if (this->station_scope.tile != INVALID_TILE) {
265 t = ClosestTownFromTile(this->station_scope.tile, UINT_MAX);
266 }
267 if (t == nullptr) return nullptr;
268 this->town_scope.emplace(*this, t, this->station_scope.st == nullptr);
269 }
270 return &*this->town_scope;
271}
272
273/* virtual */ uint32_t StationScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
274{
275 if (this->st == nullptr) {
276 /* Station does not exist, so we're in a purchase list or the land slope check callback. */
277 switch (variable) {
278 case 0x40:
279 case 0x41:
280 case 0x46:
281 case 0x47:
282 case 0x49: return 0x2110000; // Platforms, tracks & position
283 case 0x42: return 0; // Rail type (XXX Get current type from GUI?)
284 case 0x43: return GetCompanyInfo(_current_company); // Station owner
285 case 0x44: return 2; // PBS status
286 case 0x67: // Land info of nearby tile
287 if (this->axis != INVALID_AXIS && this->tile != INVALID_TILE) {
288 TileIndex tile = this->tile;
289 if (parameter != 0) tile = GetNearbyTile(parameter, tile, true, this->axis); // only perform if it is required
290
291 Slope tileh = GetTileSlope(tile);
292 bool swap = (this->axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
293
294 return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
295 }
296 break;
297
298 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, this->statspec->badges, parameter);
299
300 case 0xFA: return ClampTo<uint16_t>(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Build date, clamped to a 16 bit value
301 }
302
303 available = false;
304 return UINT_MAX;
305 }
306
307 switch (variable) {
308 /* Calculated station variables */
309 case 0x40:
310 if (!this->cache.v40.has_value()) this->cache.v40 = GetPlatformInfoHelper(this->tile, false, false, false);
311 return *this->cache.v40;
312
313 case 0x41:
314 if (!this->cache.v41.has_value()) this->cache.v41 = GetPlatformInfoHelper(this->tile, true, false, false);
315 return *this->cache.v41;
316
317 case 0x42: return GetTerrainType(this->tile) | (GetReverseRailTypeTranslation(GetRailType(this->tile), this->statspec->grf_prop.grffile) << 8);
318 case 0x43: return GetCompanyInfo(this->st->owner); // Station owner
319 case 0x44: return HasStationReservation(this->tile) ? 7 : 4; // PBS status
320 case 0x45:
321 if (!this->cache.v45.has_value()) this->cache.v45 = GetRailContinuationInfo(this->tile);
322 return *this->cache.v45;
323
324 case 0x46:
325 if (!this->cache.v46.has_value()) this->cache.v46 = GetPlatformInfoHelper(this->tile, false, false, true);
326 return *this->cache.v46;
327
328 case 0x47:
329 if (!this->cache.v47.has_value()) this->cache.v47 = GetPlatformInfoHelper(this->tile, true, false, true);
330 return *this->cache.v47;
331
332 case 0x49:
333 if (!this->cache.v49.has_value()) this->cache.v49 = GetPlatformInfoHelper(this->tile, false, true, false);
334 return *this->cache.v49;
335
336 case 0x4A: // Animation frame of tile
337 return GetAnimationFrame(this->tile);
338
339 /* Variables which use the parameter */
340 /* Variables 0x60 to 0x65 and 0x69 are handled separately below */
341 case 0x66: { // Animation frame of nearby tile
342 TileIndex tile = this->tile;
343 if (parameter != 0) tile = GetNearbyTile(parameter, tile);
344 return this->st->TileBelongsToRailStation(tile) ? GetAnimationFrame(tile) : UINT_MAX;
345 }
346
347 case 0x67: { // Land info of nearby tile
348 Axis axis = GetRailStationAxis(this->tile);
349 TileIndex tile = this->tile;
350 if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required
351
352 Slope tileh = GetTileSlope(tile);
353 bool swap = (axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
354
355 return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
356 }
357
358 case 0x68: { // Station info of nearby tiles
359 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
360
361 if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
362
363 uint32_t grfid = this->st->speclist[GetCustomStationSpecIndex(this->tile)].grfid;
364 bool perpendicular = GetRailStationAxis(this->tile) != GetRailStationAxis(nearby_tile);
365 bool same_station = this->st->TileBelongsToRailStation(nearby_tile);
366 uint32_t res = GB(GetStationGfx(nearby_tile), 1, 2) << 12 | !!perpendicular << 11 | !!same_station << 10;
367
368 if (IsCustomStationSpecIndex(nearby_tile)) {
369 const auto &sm = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
370 res |= 1 << (sm.grfid != grfid ? 9 : 8) | ClampTo<uint8_t>(sm.localidx);
371 }
372 return res;
373 }
374
375 case 0x6A: { // GRFID of nearby station tiles
376 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
377
378 if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
379 if (!IsCustomStationSpecIndex(nearby_tile)) return 0;
380
381 const auto &sm = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
382 return sm.grfid;
383 }
384
385 case 0x6B: { // 16 bit Station ID of nearby tiles
386 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
387
388 if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
389 if (!IsCustomStationSpecIndex(nearby_tile)) return 0xFFFE;
390
391 uint32_t grfid = this->st->speclist[GetCustomStationSpecIndex(this->tile)].grfid;
392
393 const auto &sm = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
394 if (sm.grfid == grfid) {
395 return sm.localidx;
396 }
397
398 return 0xFFFE;
399 }
400
401 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, this->statspec->badges, parameter);
402
403 /* General station variables */
404 case 0x82: return 50;
405 case 0x84: return this->st->string_id;
406 case 0x86: return 0;
407 case 0xF0: return this->st->facilities.base();
408 case 0xFA: return ClampTo<uint16_t>(this->st->build_date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR);
409 }
410
411 return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
412}
413
414uint32_t Station::GetNewGRFVariable(const ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const
415{
416 switch (variable) {
417 case 0x48: { // Accepted cargo types
418 uint32_t value = GetAcceptanceMask(this);
419 return value;
420 }
421
422 case 0x8A: return this->had_vehicle_of_type;
423 case 0xF1: return (this->airport.tile != INVALID_TILE) ? this->airport.GetSpec()->ttd_airport_type : ATP_TTDP_LARGE;
424 case 0xF2: return (this->truck_stops != nullptr) ? this->truck_stops->status.base() : 0;
425 case 0xF3: return (this->bus_stops != nullptr) ? this->bus_stops->status.base() : 0;
426 case 0xF6: return this->airport.blocks.base();
427 case 0xF7: return GB(this->airport.blocks.base(), 8, 8);
428 }
429
430 /* Handle cargo variables with parameter, 0x60 to 0x65 and 0x69 */
431 if ((variable >= 0x60 && variable <= 0x65) || variable == 0x69) {
432 CargoType cargo = GetCargoTranslation(parameter, object.grffile);
433
434 if (!IsValidCargoType(cargo)) {
435 switch (variable) {
436 case 0x62: return 0xFFFFFFFF;
437 case 0x64: return 0xFF00;
438 default: return 0;
439 }
440 }
441 const GoodsEntry *ge = &this->goods[cargo];
442
443 switch (variable) {
444 case 0x60: return ge->HasData() ? std::min(ge->GetData().cargo.TotalCount(), 4095u) : 0;
445 case 0x61: return ge->HasVehicleEverTriedLoading() ? ge->time_since_pickup : 0;
446 case 0x62: return ge->HasRating() ? ge->rating : 0xFFFFFFFF;
447 case 0x63: return ge->HasData() ? ge->GetData().cargo.PeriodsInTransit() : 0;
448 case 0x64: return ge->HasVehicleEverTriedLoading() ? ge->last_speed | (ge->last_age << 8) : 0xFF00;
449 case 0x65: return ge->status.Test(GoodsEntry::State::Acceptance) ? (1U << 3) : 0;
450 case 0x69: return ge->ConvertState();
451 }
452 }
453
454 /* Handle cargo variables (deprecated) */
455 if (variable >= 0x8C && variable <= 0xEC) {
456 const GoodsEntry *g = &this->goods[GB(variable - 0x8C, 3, 4)];
457 switch (GB(variable - 0x8C, 0, 3)) {
458 case 0: return g->HasData() ? g->GetData().cargo.TotalCount() : 0;
459 case 1: return GB(g->HasData() ? std::min(g->GetData().cargo.TotalCount(), 4095u) : 0, 0, 4) | (g->status.Test(GoodsEntry::State::Acceptance) ? (1U << 7) : 0);
460 case 2: return g->time_since_pickup;
461 case 3: return g->rating;
462 case 4: return (g->HasData() ? g->GetData().cargo.GetFirstStation() : StationID::Invalid()).base();
463 case 5: return g->HasData() ? g->GetData().cargo.PeriodsInTransit() : 0;
464 case 6: return g->last_speed;
465 case 7: return g->last_age;
466 }
467 }
468
469 Debug(grf, 1, "Unhandled station variable 0x{:X}", variable);
470
471 available = false;
472 return UINT_MAX;
473}
474
475uint32_t Waypoint::GetNewGRFVariable(const ResolverObject &, uint8_t variable, [[maybe_unused]] uint8_t parameter, bool &available) const
476{
477 switch (variable) {
478 case 0x48: return 0; // Accepted cargo types
479 case 0x8A: return HVOT_WAYPOINT;
480 case 0xF1: return 0; // airport type
481 case 0xF2: return 0; // truck stop status
482 case 0xF3: return 0; // bus stop status
483 case 0xF6: return 0; // airport flags
484 case 0xF7: return 0; // airport flags cont.
485 }
486
487 /* Handle cargo variables with parameter, 0x60 to 0x65 */
488 if (variable >= 0x60 && variable <= 0x65) {
489 return 0;
490 }
491
492 /* Handle cargo variables (deprecated) */
493 if (variable >= 0x8C && variable <= 0xEC) {
494 switch (GB(variable - 0x8C, 0, 3)) {
495 case 3: return INITIAL_STATION_RATING;
496 case 4: return StationID::Invalid().base();
497 default: return 0;
498 }
499 }
500
501 Debug(grf, 1, "Unhandled station variable 0x{:X}", variable);
502
503 available = false;
504 return UINT_MAX;
505}
506
507/* virtual */ const SpriteGroup *StationResolverObject::ResolveReal(const RealSpriteGroup &group) const
508{
509 if (this->station_scope.st == nullptr || !Station::IsExpected(this->station_scope.st)) {
510 if (!group.loading.empty()) return group.loading[0];
511 return nullptr;
512 }
513
514 uint cargo = 0;
515 const Station *st = Station::From(this->station_scope.st);
516
517 switch (this->station_scope.cargo_type) {
518 case INVALID_CARGO:
521 cargo = 0;
522 break;
523
525 for (const GoodsEntry &ge : st->goods) {
526 if (!ge.HasData()) continue;
527 cargo += ge.GetData().cargo.TotalCount();
528 }
529 break;
530
531 default: {
532 const GoodsEntry &ge = st->goods[this->station_scope.cargo_type];
533 cargo = ge.HasData() ? ge.GetData().cargo.TotalCount() : 0;
534 break;
535 }
536 }
537
539 cargo = std::min(0xfffu, cargo);
540
541 if (cargo > this->station_scope.statspec->cargo_threshold) {
542 if (!group.loading.empty()) {
543 uint set = ((cargo - this->station_scope.statspec->cargo_threshold) * static_cast<uint>(group.loading.size())) / (4096 - this->station_scope.statspec->cargo_threshold);
544 return group.loading[set];
545 }
546 } else {
547 if (!group.loaded.empty()) {
548 uint set = (cargo * static_cast<uint>(group.loaded.size())) / (this->station_scope.statspec->cargo_threshold + 1);
549 return group.loaded[set];
550 }
551 }
552
553 if (!group.loading.empty()) return group.loading[0];
554 return nullptr;
555}
556
558{
559 return GSF_STATIONS;
560}
561
563{
565}
566
577 CallbackID callback, uint32_t callback_param1, uint32_t callback_param2)
578 : SpecializedResolverObject<StationRandomTriggers>(statspec->grf_prop.grffile, callback, callback_param1, callback_param2),
579 station_scope(*this, statspec, base_station, tile)
580{
582
583 if (this->station_scope.st == nullptr) {
584 /* No station, so we are in a purchase list */
586 this->root_spritegroup = statspec->grf_prop.GetSpriteGroup(ctype);
587 } else if (Station::IsExpected(this->station_scope.st)) {
588 const Station *st = Station::From(this->station_scope.st);
589 /* Pick the first cargo that we have waiting */
590 for (const auto &[cargo, spritegroup] : statspec->grf_prop.spritegroups) {
591 if (cargo < NUM_CARGO && st->goods[cargo].HasData() && st->goods[cargo].GetData().cargo.TotalCount() > 0) {
592 ctype = cargo;
593 this->root_spritegroup = spritegroup;
594 break;
595 }
596 }
597
598 if (this->root_spritegroup == nullptr) {
600 this->root_spritegroup = statspec->grf_prop.GetSpriteGroup(ctype);
601 }
602 }
603
604
605 if (this->root_spritegroup == nullptr) {
607 this->root_spritegroup = statspec->grf_prop.GetSpriteGroup(ctype);
608 }
609
610 /* Remember the cargo type we've picked */
611 this->station_scope.cargo_type = ctype;
612}
613
622SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint32_t var10)
623{
624 StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, var10);
625 const auto *group = object.Resolve<ResultSpriteGroup>();
626 if (group == nullptr || group->num_sprites == 0) return 0;
627 return group->sprite - SPR_RAIL_PLATFORM_Y_FRONT;
628}
629
630void GetCustomStationRelocation(SpriteLayoutProcessor &processor, const StationSpec *statspec, BaseStation *st, TileIndex tile)
631{
632 StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK);
633 for (uint8_t var10 : processor.Var10Values()) {
634 object.callback_param1 = var10;
635 const auto *group = object.Resolve<ResultSpriteGroup>();
636 if (group == nullptr || group->num_sprites == 0) continue;
637 processor.ProcessRegisters(object, var10, group->sprite - SPR_RAIL_PLATFORM_Y_FRONT);
638 }
639}
640
650SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint layout, uint edge_info)
651{
652 /* callback_param1 == 2 means we are resolving the foundation sprites. */
653 StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, 2, layout | (edge_info << 16));
654
655 const auto *group = object.Resolve<ResultSpriteGroup>();
656 /* Note: SpriteGroup::Resolve zeroes all registers, so register 0x100 is initialised to 0. (compatibility) */
657 uint32_t offset = static_cast<uint32_t>(object.GetRegister(0x100));
658 if (group == nullptr || group->num_sprites <= offset) return 0;
659
660 return group->sprite + offset;
661}
662
663
664uint16_t GetStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, BaseStation *st, TileIndex tile, std::span<int32_t> regs100)
665{
666 StationResolverObject object(statspec, st, tile, callback, param1, param2);
667 return object.ResolveCallback(regs100);
668}
669
680CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_tile, const StationSpec *statspec, Axis axis, uint8_t plat_len, uint8_t numtracks)
681{
682 TileIndex diff = cur_tile - north_tile;
683 Slope slope = GetTileSlope(cur_tile);
684
685 StationResolverObject object(statspec, nullptr, cur_tile, CBID_STATION_LAND_SLOPE_CHECK,
686 (slope << 4) | (slope ^ (axis == AXIS_Y && HasBit(slope, CORNER_W) != HasBit(slope, CORNER_E) ? SLOPE_EW : 0)),
687 (numtracks << 24) | (plat_len << 16) | (axis == AXIS_Y ? TileX(diff) << 8 | TileY(diff) : TileY(diff) << 8 | TileX(diff)));
688 object.station_scope.axis = axis;
689
690 std::array<int32_t, 16> regs100;
691 uint16_t cb_res = object.ResolveCallback(regs100);
692
693 /* Failed callback means success. */
694 if (cb_res == CALLBACK_FAILED) return CommandCost();
695
696 /* The meaning of bit 10 is inverted for a grf version < 8. */
697 if (statspec->grf_prop.grffile->grf_version < 8) ToggleBit(cb_res, 10);
698 return GetErrorMessageFromLocationCallbackResult(cb_res, regs100, statspec->grf_prop.grffile, STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
699}
700
701
709int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec)
710{
711 uint i;
712
713 if (statspec == nullptr || st == nullptr) return 0;
714
715 for (i = 1; i < st->speclist.size() && i < NUM_STATIONSSPECS_PER_STATION; i++) {
716 if (st->speclist[i].spec == nullptr && st->speclist[i].grfid == 0) break;
717 }
718
720 /* As final effort when the spec list is already full...
721 * try to find the same spec and return that one. This might
722 * result in slightly "wrong" (as per specs) looking stations,
723 * but it's fairly unlikely that one reaches the limit anyways.
724 */
725 for (i = 1; i < st->speclist.size() && i < NUM_STATIONSSPECS_PER_STATION; i++) {
726 if (st->speclist[i].spec == statspec) return i;
727 }
728
729 return -1;
730 }
731
732 if (exec) {
733 if (i >= st->speclist.size()) st->speclist.resize(i + 1);
734 st->speclist[i].spec = statspec;
735 st->speclist[i].grfid = statspec->grf_prop.grfid;
736 st->speclist[i].localidx = statspec->grf_prop.local_id;
737
739 }
740
741 return i;
742}
743
744
751void DeallocateSpecFromStation(BaseStation *st, uint8_t specindex)
752{
753 /* specindex of 0 (default) is never freeable */
754 if (specindex == 0) return;
755
756 ETileArea area = ETileArea(st, INVALID_TILE, TA_WHOLE);
757 /* Check all tiles over the station to check if the specindex is still in use */
758 for (TileIndex tile : area) {
759 if (st->TileBelongsToRailStation(tile) && GetCustomStationSpecIndex(tile) == specindex) {
760 return;
761 }
762 }
763
764 /* This specindex is no longer in use, so deallocate it */
765 st->speclist[specindex].spec = nullptr;
766 st->speclist[specindex].grfid = 0;
767 st->speclist[specindex].localidx = 0;
768
769 /* If this was the highest spec index, reallocate */
770 if (specindex == st->speclist.size() - 1) {
771 size_t num_specs;
772 for (num_specs = st->speclist.size() - 1; num_specs > 0; num_specs--) {
773 if (st->speclist[num_specs].grfid != 0) break;
774 }
775
776 if (num_specs > 0) {
777 st->speclist.resize(num_specs + 1);
778 } else {
779 st->speclist.clear();
780 st->cached_anim_triggers = {};
781 st->cached_cargo_triggers = 0;
782 return;
783 }
784 }
785
787}
788
799bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station)
800{
801 const DrawTileSprites *sprites = nullptr;
802 const RailTypeInfo *rti = GetRailTypeInfo(railtype);
804 uint tile = 2;
805
806 const StationSpec *statspec = StationClass::Get(sclass)->GetSpec(station);
807 if (statspec == nullptr) return false;
808
810 uint16_t callback = GetStationCallback(CBID_STATION_DRAW_TILE_LAYOUT, 0, 0, statspec, nullptr, INVALID_TILE);
811 if (callback != CALLBACK_FAILED) tile = callback & ~1;
812 }
813
814 uint32_t total_offset = rti->GetRailtypeSpriteOffset();
815 uint32_t relocation = 0;
816 uint32_t ground_relocation = 0;
817 const NewGRFSpriteLayout *layout = nullptr;
818 SpriteLayoutProcessor processor; // owns heap, borrowed by tmp_rail_layout and sprites
819 DrawTileSpriteSpan tmp_rail_layout;
820
821 if (statspec->renderdata.empty()) {
822 sprites = GetStationTileLayout(StationType::Rail, tile + axis);
823 } else {
824 layout = &statspec->renderdata[(tile < statspec->renderdata.size()) ? tile + axis : (uint)axis];
825 if (!layout->NeedsPreprocessing()) {
826 sprites = layout;
827 layout = nullptr;
828 }
829 }
830
831 if (layout != nullptr) {
832 /* Sprite layout which needs preprocessing */
833 bool separate_ground = statspec->flags.Test(StationSpecFlag::SeparateGround);
834 processor = SpriteLayoutProcessor(*layout, total_offset, rti->fallback_railtype, 0, 0, separate_ground);
835 GetCustomStationRelocation(processor, statspec, nullptr, INVALID_TILE);
836 tmp_rail_layout = processor.GetLayout();
837 sprites = &tmp_rail_layout;
838 total_offset = 0;
839 } else {
840 /* Simple sprite layout */
841 ground_relocation = relocation = GetCustomStationRelocation(statspec, nullptr, INVALID_TILE, 0);
843 ground_relocation = GetCustomStationRelocation(statspec, nullptr, INVALID_TILE, 1);
844 }
845 ground_relocation += rti->fallback_railtype;
846 }
847
848 SpriteID image = sprites->ground.sprite;
849 PaletteID pal = sprites->ground.pal;
850 RailTrackOffset overlay_offset;
851 if (rti->UsesOverlay() && SplitGroundSpriteForOverlay(nullptr, &image, &overlay_offset)) {
853 DrawSprite(image, PAL_NONE, x, y);
854 DrawSprite(ground + overlay_offset, PAL_NONE, x, y);
855 } else {
856 image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
857 if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
858 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
859 }
860
861 DrawRailTileSeqInGUI(x, y, sprites, total_offset, relocation, palette);
862
863 return true;
864}
865
866
867const StationSpec *GetStationSpec(TileIndex t)
868{
869 if (!IsCustomStationSpecIndex(t)) return nullptr;
870
871 const BaseStation *st = BaseStation::GetByTile(t);
872 uint specindex = GetCustomStationSpecIndex(t);
873 return specindex < st->speclist.size() ? st->speclist[specindex].spec : nullptr;
874}
875
877uint16_t GetAnimStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, BaseStation *st, TileIndex tile, int)
878{
879 return GetStationCallback(callback, param1, param2, statspec, st, tile);
880}
881
890
891void AnimateStationTile(TileIndex tile)
892{
893 const StationSpec *ss = GetStationSpec(tile);
894 if (ss == nullptr) return;
895
897}
898
899void TriggerStationAnimation(BaseStation *st, TileIndex trigger_tile, StationAnimationTrigger trigger, CargoType cargo_type)
900{
901 /* List of coverage areas for each animation trigger */
902 static const TriggerArea tas[] = {
903 TA_TILE, // Built
904 TA_WHOLE, // NewCargo
905 TA_WHOLE, // CargoTaken
906 TA_PLATFORM, // VehicleArrives
907 TA_PLATFORM, // VehicleDeparts
908 TA_PLATFORM, // VehicleLoads
909 TA_WHOLE, // AcceptanceTick
910 TA_TILE, // TileLoop
911 TA_PLATFORM, // PathReservation
912 };
913 static_assert(std::size(tas) == static_cast<size_t>(StationAnimationTrigger::End));
914
915 assert(st != nullptr);
916
917 /* Check the cached animation trigger bitmask to see if we need
918 * to bother with any further processing. */
919 if (!st->cached_anim_triggers.Test(trigger)) return;
920
921 uint16_t random_bits = Random();
922 ETileArea area = ETileArea(st, trigger_tile, tas[static_cast<size_t>(trigger)]);
923
924 /* Check all tiles over the station to check if the specindex is still in use */
925 for (TileIndex tile : area) {
926 if (st->TileBelongsToRailStation(tile)) {
927 const StationSpec *ss = GetStationSpec(tile);
928 if (ss != nullptr && ss->animation.triggers.Test(trigger)) {
929 uint8_t var18_extra = 0;
930 if (IsValidCargoType(cargo_type)) {
931 var18_extra |= ss->grf_prop.grffile->cargo_map[cargo_type] << 8;
932 }
933 StationAnimationBase::ChangeAnimationFrame(CBID_STATION_ANIMATION_TRIGGER, ss, st, tile, (random_bits << 16) | GB(Random(), 0, 16), to_underlying(trigger) | var18_extra);
934 }
935 }
936 }
937}
938
947{
948 /* List of coverage areas for each animation trigger */
949 static const TriggerArea tas[] = {
950 TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM
951 };
952
953 assert(st != nullptr);
954
955 /* Check the cached cargo trigger bitmask to see if we need
956 * to bother with any further processing.
957 * Note: cached_cargo_triggers must be non-zero even for cargo-independent triggers. */
958 if (st->cached_cargo_triggers == 0) return;
959 if (IsValidCargoType(cargo_type) && !HasBit(st->cached_cargo_triggers, cargo_type)) return;
960
961 uint32_t whole_reseed = 0;
962 ETileArea area = ETileArea(st, trigger_tile, tas[static_cast<size_t>(trigger)]);
963
964 /* Bitmask of completely empty cargo types to be matched. */
965 CargoTypes empty_mask{};
966 if (trigger == StationRandomTrigger::CargoTaken) {
967 empty_mask = GetEmptyMask(Station::From(st));
968 }
969
970 /* Store triggers now for var 5F */
971 st->waiting_random_triggers.Set(trigger);
972 StationRandomTriggers used_random_triggers;
973
974 /* Check all tiles over the station to check if the specindex is still in use */
975 for (TileIndex tile : area) {
976 if (st->TileBelongsToRailStation(tile)) {
977 const StationSpec *ss = GetStationSpec(tile);
978 if (ss == nullptr) continue;
979
980 /* Cargo taken "will only be triggered if all of those
981 * cargo types have no more cargo waiting." */
982 if (trigger == StationRandomTrigger::CargoTaken) {
983 if ((ss->cargo_triggers & ~empty_mask) != 0) continue;
984 }
985
986 if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) {
987 StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0);
988 object.SetWaitingRandomTriggers(st->waiting_random_triggers);
989
990 object.ResolveRerandomisation();
991
992 used_random_triggers.Set(object.GetUsedRandomTriggers());
993
994 uint32_t reseed = object.GetReseedSum();
995 if (reseed != 0) {
996 whole_reseed |= reseed;
997 reseed >>= 16;
998
999 /* Set individual tile random bits */
1000 uint8_t random_bits = GetStationTileRandomBits(tile);
1001 random_bits &= ~reseed;
1002 random_bits |= Random() & reseed;
1003 SetStationTileRandomBits(tile, random_bits);
1004
1005 MarkTileDirtyByTile(tile);
1006 }
1007 }
1008 }
1009 }
1010
1011 /* Update whole station random bits */
1012 st->waiting_random_triggers.Reset(used_random_triggers);
1013 if ((whole_reseed & 0xFFFF) != 0) {
1014 st->random_bits &= ~whole_reseed;
1015 st->random_bits |= Random() & whole_reseed;
1016 }
1017}
1018
1024{
1025 st->cached_anim_triggers = {};
1026 st->cached_cargo_triggers = 0;
1027
1028 /* Combine animation trigger bitmask for all station specs
1029 * of this station. */
1030 for (const auto &sm : GetStationSpecList<StationSpec>(st)) {
1031 if (sm.spec == nullptr) continue;
1032 st->cached_anim_triggers.Set(sm.spec->animation.triggers);
1033 st->cached_cargo_triggers |= sm.spec->cargo_triggers;
1034 }
1035}
1036
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
uint PeriodsInTransit() const
Returns average number of cargo aging periods in transit for a cargo entity.
Common return value for all commands.
Struct containing information relating to NewGRF classes for stations and airports.
StringID name
Name of this class.
bool IsUIAvailable(uint index) const
Check whether the spec will be available to the user at some point in time.
void Insert(Tspec *spec)
Insert a spec into the class, and update its index.
static NewGRFClass * Get(Tindex class_index)
Get a particular class.
static Tindex Allocate(uint32_t global_id)
Allocate a class with a given global class ID.
static void InsertDefaults()
Initialise the defaults.
const Tspec * GetSpec(uint index) const
Get a spec from the class at a given index.
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:118
uint8_t fallback_railtype
Original railtype number to use when drawing non-newgrf railtypes, or when drawing stations.
Definition rail.h:192
uint GetRailtypeSpriteOffset() const
Offset between the current railtype and normal rail.
Definition rail.h:288
Add dynamic register values to a sprite layout.
DrawTileSpriteSpan GetLayout() const
Returns the result spritelayout after preprocessing.
void ProcessRegisters(const struct ResolverObject &object, uint8_t resolved_var10, uint32_t resolved_sprite)
Evaluates the register modifiers and integrates them into the preprocessed sprite layout.
uint TotalCount() const
Returns total count of cargo at the station, including cargo which is already reserved for loading.
StationID GetFirstStation() const
Returns first station of the first cargo packet in this list.
static Date date
Current date in days (day counter).
static constexpr TimerGame< struct Calendar >::Date DAYS_TILL_ORIGINAL_BASE_YEAR
The date of the first day of the original base year.
PaletteID GetCompanyPalette(CompanyID company)
Get the palette for recolouring with a company colour.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Direction
Defines the 8 directions on the map.
@ DIR_SW
Southwest.
@ DIR_NW
Northwest.
@ DIR_N
North.
@ DIR_SE
Southeast.
@ DIR_S
South.
@ DIR_NE
Northeast.
@ DIR_W
West.
@ DIR_E
East.
Axis
Allow incrementing of DiagDirDiff variables.
@ INVALID_AXIS
Flag for an invalid Axis.
@ AXIS_X
The X axis.
@ AXIS_Y
The y axis.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_NW
Northwest.
@ DIAGDIR_SE
Southeast.
@ DIAGDIR_SW
Southwest.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:1024
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
@ Random
Randomise borders.
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:388
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:554
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
Definition map_func.h:456
TileIndexDiff TileOffsByDir(Direction dir)
Convert a Direction to a TileIndexDiff.
Definition map_func.h:583
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
GrfSpecFeature
Definition newgrf.h:69
@ ATP_TTDP_LARGE
Same as AT_LARGE.
Function implementations related to NewGRF animation.
uint32_t GetBadgeVariableResult(const GRFFile &grffile, std::span< const BadgeID > badges, uint32_t parameter)
Test for a matching badge in a list of badges, returning the number of matching bits.
Functions related to NewGRF badges.
StationCallbackMask
Callback masks for stations.
@ DrawTileLayout
Use callback to select a tile layout to use when drawing.
@ AnimationNextFrame
Use a custom next frame callback.
@ AnimationSpeed
Customize the animation speed of the station.
CallbackID
List of implemented NewGRF callbacks.
@ CBID_STATION_ANIMATION_TRIGGER
Called for periodically starting or stopping the animation.
@ CBID_STATION_DRAW_TILE_LAYOUT
Choose a tile layout to draw, instead of the standard range.
@ CBID_NO_CALLBACK
Set when using the callback resolve system, but not to resolve a callback.
@ CBID_STATION_ANIMATION_NEXT_FRAME
Called to determine station tile next animation frame.
@ CBID_STATION_ANIMATION_SPEED
Called to indicate how long the current animation frame should last.
@ CBID_RANDOM_TRIGGER
Set when calling a randomizing trigger (almost undocumented).
@ CBID_STATION_LAND_SLOPE_CHECK
Callback done for each tile of a station to check the slope.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
CargoType GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoType.
Cargo support for NewGRFs.
Implementation of the NewGRF class' functions.
CommandCost GetErrorMessageFromLocationCallbackResult(uint16_t cb_res, std::span< const int32_t > textstack, const GRFFile *grffile, StringID default_error)
Get the error message from a shape/location/slope check callback result.
uint32_t GetCompanyInfo(CompanyID owner, const Livery *l)
Returns company information like in vehicle var 43 or station var 43.
uint32_t GetNearbyTileInformation(TileIndex tile, bool grf_version8)
Common part of station var 0x67, house var 0x62, indtile var 0x60, industry var 0x62.
uint32_t GetTerrainType(TileIndex tile, TileContext context)
Function used by houses (and soon industries) to get information on type of "terrain" the tile it is ...
TileIndex GetNearbyTile(uint8_t parameter, TileIndex tile, bool signed_offsets, Axis axis)
Get the tile at the given offset.
@ Invalid
GRF is unusable with this version of OpenTTD.
uint8_t GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile)
Perform a reverse railtype lookup to get the GRF internal ID.
SpriteID GetCustomRailSprite(const RailTypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
NewGRF handling of rail types.
Functions related to NewGRF provided sounds.
Action 2 handling.
int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec)
Allocate a StationSpec to a Station.
uint32_t GetPlatformInfo(Axis axis, uint8_t tile, int platforms, int length, int x, int y, bool centred)
Evaluate a tile's position within a station, and return the result in a bit-stuffed format.
static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis)
Find the end of a railway station, from the tile, in the direction of delta.
SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint32_t var10)
Resolve sprites for drawing a station tile.
SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint layout, uint edge_info)
Resolve the sprites for custom station foundations.
void StationUpdateCachedTriggers(BaseStation *st)
Update the cached animation trigger bitmask for a station.
bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station)
Draw representation of a station tile for GUI purposes.
void DeallocateSpecFromStation(BaseStation *st, uint8_t specindex)
Deallocate a StationSpec from a Station.
void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger station randomisation.
static const uint NUM_STATIONSSPECS_PER_STATION
Maximum number of parts per station.
CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_tile, const StationSpec *statspec, Axis axis, uint8_t plat_len, uint8_t numtracks)
Check the slope of a tile of a new station.
uint16_t GetAnimStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, BaseStation *st, TileIndex tile, int)
Wrapper for animation control, see GetStationCallback.
Header file for NewGRF stations.
@ Cb141RandomBits
Callback 141 needs random bits.
@ SeparateGround
Use different sprite set for ground sprites.
@ DivByStationSize
Divide cargo amount by station size.
StationClassID
Functions to handle the town part of NewGRF towns.
@ Acceptance
A type of cargo is (no longer) accepted.
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:300
@ RTSG_GROUND
Main group of ground images.
Definition rail.h:43
RailTrackOffset
Offsets for sprites within an overlay/underlay set.
Definition rail.h:61
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition rail_map.h:115
RailType
Enumeration for all possible railtypes.
Definition rail_type.h:25
Base class for roadstops.
A number of safeguards to prevent using unsafe methods.
Slope
Enumeration for the slope-type.
Definition slope_type.h:48
@ SLOPE_EW
east and west corner are raised
Definition slope_type.h:59
void DrawRailTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32_t total_offset, uint32_t newgrf_offset, PaletteID default_palette)
Draw tile sprite sequence in GUI with railroad specifics.
Definition sprite.h:101
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:170
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition sprites.h:1551
Base classes/functions for stations.
CargoTypes GetEmptyMask(const Station *st)
Get a mask of the cargo types that are empty at the station.
const DrawTileSprites * GetStationTileLayout(StationType st, uint8_t gfx)
Get station tile layout for a station type and its station gfx.
CargoTypes GetAcceptanceMask(const Station *st)
Get a mask of the cargo types that the station accepts.
bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset)
Check whether a sprite is a track sprite, which can be replaced by a non-track ground sprite and a ra...
StationGfx GetStationGfx(Tile t)
Get the station graphics of this tile.
Definition station_map.h:68
bool IsCompatibleTrainStationTile(Tile test_tile, Tile station_tile)
Check if a tile is a valid continuation to a railstation tile.
uint8_t GetStationTileRandomBits(Tile t)
Get the random bits of a station tile.
bool IsRailStationTile(Tile t)
Is this tile a station tile and a rail station?
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
bool HasStationTileRail(Tile t)
Has this station tile a rail? In other words, is this station tile a rail station or rail waypoint?
uint GetCustomStationSpecIndex(Tile t)
Get the custom station spec for this tile.
void SetStationTileRandomBits(Tile t, uint8_t random_bits)
Set the random bits for a station tile.
Axis GetRailStationAxis(Tile t)
Get the rail direction of a rail station.
bool IsCustomStationSpecIndex(Tile t)
Is there a custom rail station spec on this tile?
bool HasStationRail(Tile t)
Has this station tile a rail? In other words, is this station tile a rail station or rail waypoint?
bool HasStationReservation(Tile t)
Get the reservation state of the rail station.
@ HVOT_WAYPOINT
Station is a waypoint (NewGRF only!)
StationRandomTrigger
Randomisation triggers for stations and roadstops.
@ CargoTaken
Trigger station when cargo is completely taken.
StationAnimationTrigger
Animation triggers for stations and roadstops.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
TTDPAirportType ttd_airport_type
ttdpatch airport type (Small/Large/Helipad/Oilrig)
AirportBlocks blocks
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
const AirportSpec * GetSpec() const
Get the AirportSpec that from the airport type of this airport.
Helper class for a unified approach to NewGRF animation.
static void AnimateTile(const StationSpec *spec, BaseStation *obj, TileIndex tile, bool random_animation, int extra_data=0)
Animate a single tile.
static void ChangeAnimationFrame(CallbackID cb, const StationSpec *spec, BaseStation *obj, TileIndex tile, uint32_t random_bits, uint32_t trigger, int extra_data=0)
Check a callback to determine what the next animation step is and execute that step.
Base class for all station-ish types.
virtual uint32_t GetNewGRFVariable(const struct ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const =0
Helper function to get a NewGRF variable that isn't implemented by the base class.
StringID string_id
Default name (town area) of station.
std::vector< SpecMapping< StationSpec > > speclist
List of rail station specs of this station.
StationFacilities facilities
The facilities that this station has.
TileArea train_station
Tile area the train 'station' part covers.
StationAnimationTriggers cached_anim_triggers
NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
Owner owner
The owner of this station.
virtual void GetTileArea(TileArea *ta, StationType type) const =0
Get the tile area for a given station type.
Town * town
The town this station is associated with.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
virtual bool TileBelongsToRailStation(TileIndex tile) const =0
Check whether a specific tile belongs to this station.
uint16_t random_bits
Random bits assigned to this station.
TimerGameCalendar::Date build_date
Date of construction.
StationRandomTriggers waiting_random_triggers
Waiting triggers (NewGRF), shared by all station parts/tiles, road stops, ... essentially useless and...
CargoTypes cached_cargo_triggers
NOSAVE: Combined cargo trigger bitmask.
static constexpr CargoType SG_PURCHASE
Used in purchase lists before an item exists.
static constexpr CargoType SG_DEFAULT
Default type used when no more-specific cargo matches.
static constexpr CargoType SG_DEFAULT_NA
Used only by stations and roads when no more-specific cargo matches.
Ground palette sprite of a tile, together with its sprite layout.
Definition sprite.h:58
Ground palette sprite of a tile, together with its sprite layout.
Definition sprite.h:43
PalSpriteID ground
Palette and sprite for the ground.
Definition sprite.h:44
const struct GRFFile * grffile
grf file that introduced this entity
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoType -> local ID)
Definition newgrf.h:137
StationCargoList cargo
The cargo packets of cargo waiting in this station.
Stores station stats for a single cargo.
bool HasRating() const
Does this cargo have a rating at this station?
uint8_t last_speed
Maximum speed (up to 255) of the last vehicle that tried to load this cargo.
uint8_t last_age
Age in years (up to 255) of the last vehicle that tried to load this cargo.
uint8_t time_since_pickup
Number of rating-intervals (up to 255) since the last vehicle tried to load this cargo.
States status
Status of this cargo, see State.
debug_inline const GoodsEntryData & GetData() const
Get optional cargo packet/flow data.
@ LastMonth
Set when cargo was delivered for final delivery last month.
@ Acceptance
Set when the station accepts the cargo currently for final deliveries.
@ EverAccepted
Set when a vehicle ever delivered cargo to the station for final delivery.
@ AcceptedBigtick
Set when cargo was delivered for final delivery during the current STATION_ACCEPTANCE_TICKS interval.
@ CurrentMonth
Set when cargo was delivered for final delivery this month.
bool HasVehicleEverTriedLoading() const
Reports whether a vehicle has ever tried to load the cargo at this station.
uint8_t rating
Station rating for this cargo.
uint8_t ConvertState() const
Convert GoodsEntry status to the form required for NewGRF variables.
debug_inline bool HasData() const
Test if this goods entry has optional cargo packet/flow data.
NewGRF supplied spritelayout.
bool NeedsPreprocessing() const
Tests whether this spritelayout needs preprocessing by SpriteLayoutProcessor, or whether it can be us...
Represents the covered area of e.g.
uint16_t w
The width of the area.
TileIndex tile
The base tile of the area.
uint16_t h
The height of the area.
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
std::vector< const SpriteGroup * > loaded
List of loaded groups (can be SpriteIDs or Callback results)
std::vector< const SpriteGroup * > loading
List of loading groups (can be SpriteIDs or Callback results)
Interface for SpriteGroup-s to access the gamestate.
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
RoadStopStatusFlags status
Current status of the Stop. Access using *Bay and *Busy functions.
ResolverObject & ro
Surrounding resolver object.
Specialization of ResolverObject with type-safe access to RandomTriggers.
static bool IsExpected(const BaseStation *st)
Helper for checking whether the given station is of this type.
static Station * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
Helper class for animation control.
Station resolver.
StationScopeResolver station_scope
The station scope resolver.
uint32_t GetDebugID() const override
Get an identifier for the item being resolved.
TownScopeResolver * GetTown()
Get the town scope associated with a station, if it exists.
std::optional< TownScopeResolver > town_scope
The town scope resolver (created on the first call).
StationResolverObject(const StationSpec *statspec, BaseStation *st, TileIndex tile, CallbackID callback=CBID_NO_CALLBACK, uint32_t callback_param1=0, uint32_t callback_param2=0)
Resolver for stations.
const SpriteGroup * ResolveReal(const RealSpriteGroup &group) const override
Get the real sprites of the grf.
GrfSpecFeature GetFeature() const override
Get the feature number being resolved for.
CargoType cargo_type
Type of cargo of the station.
struct BaseStation * st
Instance of the station.
uint32_t GetRandomTriggers() const override
Get the triggers.
uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const override
Get a variable value.
uint32_t GetRandomBits() const override
Get a few random bits.
const struct StationSpec * statspec
Station (type) specification.
Axis axis
Station axis, used only for the slope check callback.
TileIndex tile
Tile of the station.
Station specification.
uint16_t cargo_threshold
Cargo threshold for choosing between little and lots of cargo.
CargoGRFFileProps grf_prop
Link to NewGRF.
CargoTypes cargo_triggers
Bitmask of cargo types which cause trigger re-randomizing.
std::vector< NewGRFSpriteLayout > renderdata
Number of tile layouts.
StationCallbackMasks callback_mask
Bitmask of station callbacks that have to be called.
StationSpecFlags flags
Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by station size.
Station data structure.
RoadStop * bus_stops
All the road stops.
std::array< GoodsEntry, NUM_CARGO > goods
Goods at this station.
Airport airport
Tile area the airport covers.
RoadStop * truck_stops
All the truck stops.
Scope resolver for a town.
Definition newgrf_town.h:22
Town data structure.
Definition town.h:52
std::vector< ValueType > spritegroups
pointers to the different sprite groups of the entity
const SpriteGroup * GetSpriteGroup(Tkey index) const
Get the SpriteGroup at the specified index.
uint32_t GetNewGRFVariable(const struct ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const override
Helper function to get a NewGRF variable that isn't implemented by the base class.
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition tile_map.h:250
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
@ MP_TUNNELBRIDGE
Tunnel entry/exit and bridge heads.
Definition tile_type.h:57
Definition of the game-calendar-timer.
Base of the town class.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
TrackBits DiagdirReachesTracks(DiagDirection diagdir)
Returns all tracks that can be reached when entering a tile from a given (diagonal) direction.
Definition track_func.h:573
TrackBits TrackStatusToTrackBits(TrackStatus ts)
Returns the present-track-information of a TrackStatus.
Definition track_func.h:363
TrackBits
Allow incrementing of Track variables.
Definition track_type.h:35
@ TRACK_BIT_NONE
No track.
Definition track_type.h:36
@ TRANSPORT_RAIL
Transport by train.
Functions that have tunnels and bridges in common.
DiagDirection GetTunnelBridgeDirection(Tile t)
Get the direction pointing to the other end.
Base of waypoints.