OpenTTD Source 20260421-master-gc2fbc6fdeb
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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 <>
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 <>
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;
63 if (this->status.Test(GoodsEntry::State::EverAccepted)) SetBit(res, 0);
64 if (this->status.Test(GoodsEntry::State::LastMonth)) SetBit(res, 1);
65 if (this->status.Test(GoodsEntry::State::CurrentMonth)) SetBit(res, 2);
66 if (this->status.Test(GoodsEntry::State::AcceptedBigtick)) SetBit(res, 3);
67 return res;
68}
69
70enum TriggerArea : uint8_t {
71 TA_TILE,
72 TA_PLATFORM,
73 TA_WHOLE,
74};
75
83TileArea GetRailTileArea(const BaseStation *st, TileIndex tile, TriggerArea ta)
84{
85 switch (ta) {
86 default: NOT_REACHED();
87
88 case TA_TILE:
89 return {tile, 1, 1};
90
91 case TA_PLATFORM: {
92 TileIndex start, end;
93 Axis axis = GetRailStationAxis(tile);
94 TileIndexDiff delta = TileOffsByAxis(axis);
95
96 for (end = tile; IsRailStationTile(end + delta) && IsCompatibleTrainStationTile(end + delta, tile); end += delta) { /* Nothing */ }
97 for (start = tile; IsRailStationTile(start - delta) && IsCompatibleTrainStationTile(start - delta, tile); start -= delta) { /* Nothing */ }
98
99 return TileArea(start, TileX(end) - TileX(start) + 1, TileY(end) - TileY(start) + 1);
100 }
101
102 case TA_WHOLE:
104 }
105}
106
107
127uint32_t GetPlatformInfo(Axis axis, uint8_t tile, int platforms, int length, int x, int y, bool centred)
128{
129 uint32_t retval = 0;
130
131 if (axis == AXIS_X) {
132 std::swap(platforms, length);
133 std::swap(x, y);
134 }
135
136 if (centred) {
137 x -= platforms / 2;
138 y -= length / 2;
139 x = Clamp(x, -8, 7);
140 y = Clamp(y, -8, 7);
141 SB(retval, 0, 4, y & 0xF);
142 SB(retval, 4, 4, x & 0xF);
143 } else {
144 SB(retval, 0, 4, std::min(15, y));
145 SB(retval, 4, 4, std::min(15, length - y - 1));
146 SB(retval, 8, 4, std::min(15, x));
147 SB(retval, 12, 4, std::min(15, platforms - x - 1));
148 }
149 SB(retval, 16, 4, std::min(15, length));
150 SB(retval, 20, 4, std::min(15, platforms));
151 SB(retval, 24, 8, tile);
152
153 return retval;
154}
155
156
165static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis)
166{
167 uint8_t orig_type = 0;
168 Axis orig_axis = AXIS_X;
169 StationID sid = GetStationIndex(tile);
170
171 if (check_type) orig_type = GetCustomStationSpecIndex(tile);
172 if (check_axis) orig_axis = GetRailStationAxis(tile);
173
174 for (;;) {
175 TileIndex new_tile = TileAdd(tile, delta);
176
177 if (!IsTileType(new_tile, TileType::Station) || GetStationIndex(new_tile) != sid) break;
178 if (!HasStationRail(new_tile)) break;
179 if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break;
180 if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break;
181
182 tile = new_tile;
183 }
184 return tile;
185}
186
187
188static uint32_t GetPlatformInfoHelper(TileIndex tile, bool check_type, bool check_axis, bool centred)
189{
190 int tx = TileX(tile);
191 int ty = TileY(tile);
192 int sx = TileX(FindRailStationEnd(tile, TileDiffXY(-1, 0), check_type, check_axis));
193 int sy = TileY(FindRailStationEnd(tile, TileDiffXY( 0, -1), check_type, check_axis));
194 int ex = TileX(FindRailStationEnd(tile, TileDiffXY( 1, 0), check_type, check_axis)) + 1;
195 int ey = TileY(FindRailStationEnd(tile, TileDiffXY( 0, 1), check_type, check_axis)) + 1;
196
197 tx -= sx; ex -= sx;
198 ty -= sy; ey -= sy;
199
200 return GetPlatformInfo(GetRailStationAxis(tile), GetStationGfx(tile), ex, ey, tx, ty, centred);
201}
202
203
204static uint32_t GetRailContinuationInfo(TileIndex tile)
205{
206 /* Tile offsets and exit dirs for X axis */
207 static const Direction x_dir[8] = { DIR_SW, DIR_NE, DIR_SE, DIR_NW, DIR_S, DIR_E, DIR_W, DIR_N };
209
210 /* Tile offsets and exit dirs for Y axis */
211 static const Direction y_dir[8] = { DIR_SE, DIR_NW, DIR_SW, DIR_NE, DIR_S, DIR_W, DIR_E, DIR_N };
213
214 Axis axis = GetRailStationAxis(tile);
215
216 /* Choose appropriate lookup table to use */
217 const Direction *dir = axis == AXIS_X ? x_dir : y_dir;
218 const DiagDirection *diagdir = axis == AXIS_X ? x_exits : y_exits;
219
220 uint32_t res = 0;
221 uint i;
222
223 for (i = 0; i < lengthof(x_dir); i++, dir++, diagdir++) {
224 TileIndex neighbour_tile = tile + TileOffsByDir(*dir);
226 if (trackbits != TRACK_BIT_NONE) {
227 /* If there is any track on the tile, set the bit in the second byte */
228 SetBit(res, i + 8);
229
230 /* With tunnels and bridges the tile has tracks, but they are not necessarily connected
231 * with the next tile because the ramp is not going in the right direction. */
232 if (IsTileType(neighbour_tile, TileType::TunnelBridge) && GetTunnelBridgeDirection(neighbour_tile) != *diagdir) {
233 continue;
234 }
235
236 /* If any track reaches our exit direction, set the bit in the lower byte */
237 if (trackbits & DiagdirReachesTracks(*diagdir)) SetBit(res, i);
238 }
239 }
240
241 return res;
242}
243
244
245/* Station Resolver Functions */
246/* virtual */ uint32_t StationScopeResolver::GetRandomBits() const
247{
248 return (this->st == nullptr ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16);
249}
250
251
252/* virtual */ uint32_t StationScopeResolver::GetRandomTriggers() const
253{
254 if (this->st == nullptr) return 0;
255
256 StationRandomTriggers triggers = st->waiting_random_triggers;
257
258 auto it = this->st->tile_waiting_random_triggers.find(this->tile);
259 if (it != std::end(this->st->tile_waiting_random_triggers)) triggers.Set(it->second);
260
261 return triggers.base();
262}
263
264
271{
272 if (!this->town_scope.has_value()) {
273 Town *t = nullptr;
274 if (this->station_scope.st != nullptr) {
275 t = this->station_scope.st->town;
276 } else if (this->station_scope.tile != INVALID_TILE) {
277 t = ClosestTownFromTile(this->station_scope.tile, UINT_MAX);
278 }
279 if (t == nullptr) return nullptr;
280 this->town_scope.emplace(*this, t, this->station_scope.st == nullptr);
281 }
282 return &*this->town_scope;
283}
284
285/* virtual */ uint32_t StationScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
286{
287 if (this->st == nullptr) {
288 /* Station does not exist, so we're in a purchase list or the land slope check callback. */
289 switch (variable) {
290 case 0x40:
291 case 0x41:
292 case 0x46:
293 case 0x47:
294 case 0x49: return 0x2110000; // Platforms, tracks & position
295 case 0x42: return 0; // Rail type (XXX Get current type from GUI?)
296 case 0x43: return GetCompanyInfo(_current_company); // Station owner
297 case 0x44: return 2; // PBS status
298 case 0x67: // Land info of nearby tile
299 if (this->axis != INVALID_AXIS && this->tile != INVALID_TILE) {
300 TileIndex tile = this->tile;
301 if (parameter != 0) tile = GetNearbyTile(parameter, tile, true, this->axis); // only perform if it is required
302
303 Slope tileh = GetTileSlope(tile);
304 bool swap = (this->axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
305
306 return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
307 }
308 break;
309
310 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, this->statspec->badges, parameter);
311
312 case 0xFA: return ClampTo<uint16_t>(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Build date, clamped to a 16 bit value
313 }
314
315 available = false;
316 return UINT_MAX;
317 }
318
319 switch (variable) {
320 /* Calculated station variables */
321 case 0x40:
322 if (!this->cache.v40.has_value()) this->cache.v40 = GetPlatformInfoHelper(this->tile, false, false, false);
323 return *this->cache.v40;
324
325 case 0x41:
326 if (!this->cache.v41.has_value()) this->cache.v41 = GetPlatformInfoHelper(this->tile, true, false, false);
327 return *this->cache.v41;
328
329 case 0x42: return GetTerrainType(this->tile) | (GetReverseRailTypeTranslation(GetRailType(this->tile), this->statspec->grf_prop.grffile) << 8);
330 case 0x43: return GetCompanyInfo(this->st->owner); // Station owner
331 case 0x44: return HasStationReservation(this->tile) ? 7 : 4; // PBS status
332 case 0x45:
333 if (!this->cache.v45.has_value()) this->cache.v45 = GetRailContinuationInfo(this->tile);
334 return *this->cache.v45;
335
336 case 0x46:
337 if (!this->cache.v46.has_value()) this->cache.v46 = GetPlatformInfoHelper(this->tile, false, false, true);
338 return *this->cache.v46;
339
340 case 0x47:
341 if (!this->cache.v47.has_value()) this->cache.v47 = GetPlatformInfoHelper(this->tile, true, false, true);
342 return *this->cache.v47;
343
344 case 0x49:
345 if (!this->cache.v49.has_value()) this->cache.v49 = GetPlatformInfoHelper(this->tile, false, true, false);
346 return *this->cache.v49;
347
348 case 0x4A: // Animation frame of tile
349 return GetAnimationFrame(this->tile);
350
351 /* Variables which use the parameter */
352 /* Variables 0x60 to 0x65 and 0x69 are handled separately below */
353 case 0x66: { // Animation frame of nearby tile
354 TileIndex tile = this->tile;
355 if (parameter != 0) tile = GetNearbyTile(parameter, tile);
356 return this->st->TileBelongsToRailStation(tile) ? GetAnimationFrame(tile) : UINT_MAX;
357 }
358
359 case 0x67: { // Land info of nearby tile
360 Axis axis = GetRailStationAxis(this->tile);
361 TileIndex tile = this->tile;
362 if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required
363
364 Slope tileh = GetTileSlope(tile);
365 bool swap = (axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
366
367 return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
368 }
369
370 case 0x68: { // Station info of nearby tiles
371 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
372
373 if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
374
375 uint32_t grfid = this->st->speclist[GetCustomStationSpecIndex(this->tile)].grfid;
376 bool perpendicular = GetRailStationAxis(this->tile) != GetRailStationAxis(nearby_tile);
377 bool same_station = this->st->TileBelongsToRailStation(nearby_tile);
378 uint32_t res = GB(GetStationGfx(nearby_tile), 1, 2) << 12 | !!perpendicular << 11 | !!same_station << 10;
379
380 if (IsCustomStationSpecIndex(nearby_tile)) {
381 const auto &sm = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
382 res |= 1 << (sm.grfid != grfid ? 9 : 8) | ClampTo<uint8_t>(sm.localidx);
383 }
384 return res;
385 }
386
387 case 0x6A: { // GRFID of nearby station tiles
388 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
389
390 if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
391 if (!IsCustomStationSpecIndex(nearby_tile)) return 0;
392
393 const auto &sm = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
394 return sm.grfid;
395 }
396
397 case 0x6B: { // 16 bit Station ID of nearby tiles
398 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
399
400 if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
401 if (!IsCustomStationSpecIndex(nearby_tile)) return 0xFFFE;
402
403 uint32_t grfid = this->st->speclist[GetCustomStationSpecIndex(this->tile)].grfid;
404
405 const auto &sm = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
406 if (sm.grfid == grfid) {
407 return sm.localidx;
408 }
409
410 return 0xFFFE;
411 }
412
413 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, this->statspec->badges, parameter);
414
415 /* General station variables */
416 case 0x82: return 50;
417 case 0x84: return this->st->string_id;
418 case 0x86: return 0;
419 case 0xF0: return this->st->facilities.base();
420 case 0xFA: return ClampTo<uint16_t>(this->st->build_date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR);
421 }
422
423 return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
424}
425
426uint32_t Station::GetNewGRFVariable(const ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const
427{
428 switch (variable) {
429 case 0x48: { // Accepted cargo types
430 uint32_t value = GetAcceptanceMask(this);
431 return value;
432 }
433
434 case 0x8A: return this->had_vehicle_of_type;
435 case 0xF1: return (this->airport.tile != INVALID_TILE) ? this->airport.GetSpec()->ttd_airport_type : ATP_TTDP_LARGE;
436 case 0xF2: return (this->truck_stops != nullptr) ? this->truck_stops->status.base() : 0;
437 case 0xF3: return (this->bus_stops != nullptr) ? this->bus_stops->status.base() : 0;
438 case 0xF6: return this->airport.blocks.base();
439 case 0xF7: return GB(this->airport.blocks.base(), 8, 8);
440 }
441
442 /* Handle cargo variables with parameter, 0x60 to 0x65 and 0x69 */
443 if ((variable >= 0x60 && variable <= 0x65) || variable == 0x69) {
444 CargoType cargo = GetCargoTranslation(parameter, object.grffile);
445
446 if (!IsValidCargoType(cargo)) {
447 switch (variable) {
448 case 0x62: return 0xFFFFFFFF;
449 case 0x64: return 0xFF00;
450 default: return 0;
451 }
452 }
453 const GoodsEntry *ge = &this->goods[cargo];
454
455 switch (variable) {
456 case 0x60: return std::min(ge->TotalCount(), 4095u);
457 case 0x61: return ge->HasVehicleEverTriedLoading() ? ge->time_since_pickup : 0;
458 case 0x62: return ge->HasRating() ? ge->rating : 0xFFFFFFFF;
459 case 0x63: return ge->HasData() ? ge->GetData().cargo.PeriodsInTransit() : 0;
460 case 0x64: return ge->HasVehicleEverTriedLoading() ? ge->last_speed | (ge->last_age << 8) : 0xFF00;
461 case 0x65: return ge->status.Test(GoodsEntry::State::Acceptance) ? (1U << 3) : 0;
462 case 0x69: return ge->ConvertState();
463 }
464 }
465
466 /* Handle cargo variables (deprecated) */
467 if (variable >= 0x8C && variable <= 0xEC) {
468 const GoodsEntry *g = &this->goods[GB(variable - 0x8C, 3, 4)];
469 switch (GB(variable - 0x8C, 0, 3)) {
470 case 0: return g->TotalCount();
471 case 1: return GB(std::min(g->TotalCount(), 4095u), 0, 4) | (g->status.Test(GoodsEntry::State::Acceptance) ? (1U << 7) : 0);
472 case 2: return g->time_since_pickup;
473 case 3: return g->rating;
474 case 4: return (g->HasData() ? g->GetData().cargo.GetFirstStation() : StationID::Invalid()).base();
475 case 5: return g->HasData() ? g->GetData().cargo.PeriodsInTransit() : 0;
476 case 6: return g->last_speed;
477 case 7: return g->last_age;
478 }
479 }
480
481 Debug(grf, 1, "Unhandled station variable 0x{:X}", variable);
482
483 available = false;
484 return UINT_MAX;
485}
486
487uint32_t Waypoint::GetNewGRFVariable(const ResolverObject &, uint8_t variable, [[maybe_unused]] uint8_t parameter, bool &available) const
488{
489 switch (variable) {
490 case 0x48: return 0; // Accepted cargo types
491 case 0x8A: return HVOT_WAYPOINT;
492 case 0xF1: return 0; // airport type
493 case 0xF2: return 0; // truck stop status
494 case 0xF3: return 0; // bus stop status
495 case 0xF6: return 0; // airport flags
496 case 0xF7: return 0; // airport flags cont.
497 }
498
499 /* Handle cargo variables with parameter, 0x60 to 0x65 and 0x69. */
500 if ((variable >= 0x60 && variable <= 0x65) || variable == 0x69) {
501 return 0;
502 }
503
504 /* Handle cargo variables (deprecated) */
505 if (variable >= 0x8C && variable <= 0xEC) {
506 switch (GB(variable - 0x8C, 0, 3)) {
507 case 3: return INITIAL_STATION_RATING;
508 case 4: return StationID::Invalid().base();
509 default: return 0;
510 }
511 }
512
513 Debug(grf, 1, "Unhandled station variable 0x{:X}", variable);
514
515 available = false;
516 return UINT_MAX;
517}
518
519/* virtual */ const SpriteGroup *StationResolverObject::ResolveReal(const RealSpriteGroup &group) const
520{
521 if (this->station_scope.st == nullptr || !Station::IsExpected(this->station_scope.st)) {
522 if (!group.loading.empty()) return group.loading[0];
523 return nullptr;
524 }
525
526 uint cargo = 0;
527 const Station *st = Station::From(this->station_scope.st);
528
529 switch (this->station_scope.cargo_type) {
530 case INVALID_CARGO:
533 cargo = 0;
534 break;
535
537 for (const GoodsEntry &ge : st->goods) {
538 cargo += ge.TotalCount();
539 }
540 break;
541
542 default: {
543 const GoodsEntry &ge = st->goods[this->station_scope.cargo_type];
544 cargo = ge.TotalCount();
545 break;
546 }
547 }
548
549 if (this->station_scope.statspec->flags.Test(StationSpecFlag::DivByStationArea)) {
550 uint area = 0;
551 for (const TileIndex &tile : st->train_station) {
552 if (st->TileBelongsToRailStation(tile)) ++area;
553 }
554 cargo /= area;
555 } else if (this->station_scope.statspec->flags.Test(StationSpecFlag::DivByStationSize)) {
556 cargo /= (st->train_station.w + st->train_station.h); // Old code that uses half of the perimeter as the station size, compatible with TTDPatch.
557 }
558 cargo = std::min(0xfffu, cargo);
559
560 if (cargo > this->station_scope.statspec->cargo_threshold) {
561 if (!group.loading.empty()) {
562 uint set = ((cargo - this->station_scope.statspec->cargo_threshold) * static_cast<uint>(group.loading.size())) / (4096 - this->station_scope.statspec->cargo_threshold);
563 return group.loading[set];
564 }
565 } else {
566 if (!group.loaded.empty()) {
567 uint set = (cargo * static_cast<uint>(group.loaded.size())) / (this->station_scope.statspec->cargo_threshold + 1);
568 return group.loaded[set];
569 }
570 }
571
572 if (!group.loading.empty()) return group.loading[0];
573 return nullptr;
574}
575
580
582{
583 return this->station_scope.statspec->grf_prop.local_id;
584}
585
597 : SpecializedResolverObject<StationRandomTriggers>(statspec->grf_prop.grffile, callback, callback_param1, callback_param2),
598 station_scope(*this, statspec, base_station, tile)
599{
601
602 if (this->station_scope.st == nullptr) {
603 /* No station, so we are in a purchase list */
604 ctype = CargoGRFFileProps::SG_PURCHASE;
605 } else if (Station::IsExpected(this->station_scope.st)) {
606 const Station *st = Station::From(this->station_scope.st);
607 /* Pick the first cargo that we have waiting */
608 for (const auto &[cargo, spritegroup] : statspec->grf_prop.spritegroups) {
609 if (cargo < NUM_CARGO && st->goods[cargo].TotalCount() > 0) {
610 ctype = cargo;
611 break;
612 }
613 }
614 }
615
616 this->root_spritegroup = this->station_scope.statspec->grf_prop.GetSpriteGroup(ctype);
617 if (this->root_spritegroup == nullptr) {
619 this->root_spritegroup = this->station_scope.statspec->grf_prop.GetSpriteGroup(ctype);
620 }
621
622 /* Remember the cargo type we've picked */
623 this->station_scope.cargo_type = ctype;
624}
625
634SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint32_t var10)
635{
636 StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, var10);
637 const auto *group = object.Resolve<ResultSpriteGroup>();
638
639 /* A zero-length ResultSpriteGroup is valid because the output value is an offset, not a sprite ID within the ResultSpriteGroup. */
640 if (group == nullptr) return 0;
641 return group->sprite - SPR_RAIL_PLATFORM_Y_FRONT;
642}
643
644void GetCustomStationRelocation(SpriteLayoutProcessor &processor, const StationSpec *statspec, BaseStation *st, TileIndex tile)
645{
646 StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK);
647 for (uint8_t var10 : processor.Var10Values()) {
648 object.callback_param1 = var10;
649 const auto *group = object.Resolve<ResultSpriteGroup>();
650
651 /* ProcessRegisters must be called no matter the type of the sprite resolve result or whether it is valid.
652 * The sprite offset is only used for layouts with the SPRITE_MODIFIER_CUSTOM_SPRITE flag, however other aspects of layouts
653 * such as register operations must still be processed even if this flag is not set and the sprite offset is never used.
654 * A zero-length ResultSpriteGroup is valid because the output value is an offset, not a sprite ID within the ResultSpriteGroup. */
655 processor.ProcessRegisters(object, var10, group != nullptr ? group->sprite - SPR_RAIL_PLATFORM_Y_FRONT : 0);
656 }
657}
658
668SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint layout, uint edge_info)
669{
670 /* callback_param1 == 2 means we are resolving the foundation sprites. */
671 StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, 2, layout | (edge_info << 16));
672
673 const auto *group = object.Resolve<ResultSpriteGroup>();
674 /* Note: SpriteGroup::Resolve zeroes all registers, so register 0x100 is initialised to 0. (compatibility) */
675 uint32_t offset = static_cast<uint32_t>(object.GetRegister(0x100));
676 if (group == nullptr || group->num_sprites <= offset) return 0;
677
678 return group->sprite + offset;
679}
680
681
682uint16_t GetStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, BaseStation *st, TileIndex tile, std::span<int32_t> regs100)
683{
684 StationResolverObject object(statspec, st, tile, callback, param1, param2);
685 return object.ResolveCallback(regs100);
686}
687
698CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_tile, const StationSpec *statspec, Axis axis, uint8_t plat_len, uint8_t numtracks)
699{
700 TileIndex diff = cur_tile - north_tile;
701 Slope slope = GetTileSlope(cur_tile);
702
703 StationResolverObject object(statspec, nullptr, cur_tile, CBID_STATION_LAND_SLOPE_CHECK,
704 (slope << 4) | (slope ^ (axis == AXIS_Y && HasBit(slope, CORNER_W) != HasBit(slope, CORNER_E) ? SLOPE_EW : 0)),
705 (numtracks << 24) | (plat_len << 16) | (axis == AXIS_Y ? TileX(diff) << 8 | TileY(diff) : TileY(diff) << 8 | TileX(diff)));
706 object.station_scope.axis = axis;
707
708 std::array<int32_t, 16> regs100;
709 uint16_t cb_res = object.ResolveCallback(regs100);
710
711 /* Failed callback means success. */
712 if (cb_res == CALLBACK_FAILED) return CommandCost();
713
714 /* The meaning of bit 10 is inverted for a grf version < 8. */
715 if (statspec->grf_prop.grffile->grf_version < 8) ToggleBit(cb_res, 10);
716 return GetErrorMessageFromLocationCallbackResult(cb_res, regs100, statspec->grf_prop.grffile, STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
717}
718
719
726std::optional<uint8_t> AllocateSpecToStation(const StationSpec *spec, BaseStation *st)
727{
728 uint i;
729
730 if (spec == nullptr) return 0;
731
732 /* If station doesn't exist yet then the first slot is available. */
733 if (st == nullptr) return 1;
734
735 for (i = 1; i < st->speclist.size() && i < NUM_STATIONSSPECS_PER_STATION; i++) {
736 if (st->speclist[i].spec == nullptr && st->speclist[i].grfid == 0) break;
737 }
738
740 /* As final effort when the spec list is already full...
741 * try to find the same spec and return that one. This might
742 * result in slightly "wrong" (as per specs) looking stations,
743 * but it's fairly unlikely that one reaches the limit anyways.
744 */
745 for (i = 1; i < st->speclist.size() && i < NUM_STATIONSSPECS_PER_STATION; i++) {
746 if (st->speclist[i].spec == spec) return i;
747 }
748
749 return std::nullopt;
750 }
751
752 return i;
753}
754
761void AssignSpecToStation(const StationSpec *spec, BaseStation *st, uint8_t specindex)
762{
763 if (specindex == 0) return;
764 if (specindex >= st->speclist.size()) st->speclist.resize(specindex + 1);
765
766 st->speclist[specindex].spec = spec;
767 st->speclist[specindex].grfid = spec->grf_prop.grfid;
768 st->speclist[specindex].localidx = spec->grf_prop.local_id;
769
771}
772
778void DeallocateSpecFromStation(BaseStation *st, uint8_t specindex)
779{
780 /* specindex of 0 (default) is never freeable */
781 if (specindex == 0) return;
782
783 /* Check all tiles over the station to check if the specindex is still in use */
784 for (TileIndex tile : GetRailTileArea(st, INVALID_TILE, TA_WHOLE)) {
785 if (st->TileBelongsToRailStation(tile) && GetCustomStationSpecIndex(tile) == specindex) {
786 return;
787 }
788 }
789
790 /* This specindex is no longer in use, so deallocate it */
791 st->speclist[specindex].spec = nullptr;
792 st->speclist[specindex].grfid = 0;
793 st->speclist[specindex].localidx = 0;
794
795 /* If this was the highest spec index, reallocate */
796 if (specindex == st->speclist.size() - 1) {
797 size_t num_specs;
798 for (num_specs = st->speclist.size() - 1; num_specs > 0; num_specs--) {
799 if (st->speclist[num_specs].grfid != 0) break;
800 }
801
802 if (num_specs > 0) {
803 st->speclist.resize(num_specs + 1);
804 } else {
805 st->speclist.clear();
806 st->cached_anim_triggers = {};
807 st->cached_cargo_triggers = 0;
808 return;
809 }
810 }
811
813}
814
825bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station)
826{
827 const DrawTileSprites *sprites = nullptr;
828 const RailTypeInfo *rti = GetRailTypeInfo(railtype);
830 uint tile = 2;
831
832 const StationSpec *statspec = StationClass::Get(sclass)->GetSpec(station);
833 if (statspec == nullptr) return false;
834
836 uint16_t callback = GetStationCallback(CBID_STATION_DRAW_TILE_LAYOUT, 0, 0, statspec, nullptr, INVALID_TILE);
837 if (callback != CALLBACK_FAILED) tile = callback & ~1;
838 }
839
840 uint32_t total_offset = rti->GetRailtypeSpriteOffset();
841 uint32_t relocation = 0;
842 uint32_t ground_relocation = 0;
843 const NewGRFSpriteLayout *layout = nullptr;
844 SpriteLayoutProcessor processor; // owns heap, borrowed by tmp_rail_layout and sprites
845 DrawTileSpriteSpan tmp_rail_layout;
846
847 if (statspec->renderdata.empty()) {
848 sprites = GetStationTileLayout(StationType::Rail, tile + axis);
849 } else {
850 layout = &statspec->renderdata[(tile < statspec->renderdata.size()) ? tile + axis : (uint)axis];
851 if (!layout->NeedsPreprocessing()) {
852 sprites = layout;
853 layout = nullptr;
854 }
855 }
856
857 if (layout != nullptr) {
858 /* Sprite layout which needs preprocessing */
859 bool separate_ground = statspec->flags.Test(StationSpecFlag::SeparateGround);
860 processor = SpriteLayoutProcessor(*layout, total_offset, rti->fallback_railtype, 0, 0, separate_ground);
861 GetCustomStationRelocation(processor, statspec, nullptr, INVALID_TILE);
862 tmp_rail_layout = processor.GetLayout();
863 sprites = &tmp_rail_layout;
864 total_offset = 0;
865 } else {
866 /* Simple sprite layout */
867 ground_relocation = relocation = GetCustomStationRelocation(statspec, nullptr, INVALID_TILE, 0);
869 ground_relocation = GetCustomStationRelocation(statspec, nullptr, INVALID_TILE, 1);
870 }
871 ground_relocation += rti->fallback_railtype;
872 }
873
874 SpriteID image = sprites->ground.sprite;
875 PaletteID pal = sprites->ground.pal;
876 RailTrackOffset overlay_offset;
877 if (rti->UsesOverlay() && SplitGroundSpriteForOverlay(nullptr, &image, &overlay_offset)) {
879 DrawSprite(image, PAL_NONE, x, y);
880 DrawSprite(ground + overlay_offset, PAL_NONE, x, y);
881 } else {
882 image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
883 if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
884 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
885 }
886
887 DrawRailTileSeqInGUI(x, y, sprites, total_offset, relocation, palette);
888
889 return true;
890}
891
892
893const StationSpec *GetStationSpec(TileIndex t)
894{
895 if (!IsCustomStationSpecIndex(t)) return nullptr;
896
897 const BaseStation *st = BaseStation::GetByTile(t);
898 uint specindex = GetCustomStationSpecIndex(t);
899 return specindex < st->speclist.size() ? st->speclist[specindex].spec : nullptr;
900}
901
912uint16_t GetAnimStationCallback(CallbackID callback, uint32_t param1, uint32_t param2, const StationSpec *statspec, BaseStation *st, TileIndex tile, int)
913{
914 return GetStationCallback(callback, param1, param2, statspec, st, tile);
915}
916
925
926void AnimateStationTile(TileIndex tile)
927{
928 const StationSpec *ss = GetStationSpec(tile);
929 if (ss == nullptr) return;
930
932}
933
934void TriggerStationAnimation(BaseStation *st, TileIndex trigger_tile, StationAnimationTrigger trigger, CargoType cargo_type)
935{
936 /* List of coverage areas for each animation trigger */
937 static const TriggerArea tas[] = {
938 TA_TILE, // Built
939 TA_WHOLE, // NewCargo
940 TA_WHOLE, // CargoTaken
941 TA_PLATFORM, // VehicleArrives
942 TA_PLATFORM, // VehicleDeparts
943 TA_PLATFORM, // VehicleLoads
944 TA_WHOLE, // AcceptanceTick
945 TA_TILE, // TileLoop
946 TA_PLATFORM, // PathReservation
947 };
948 static_assert(std::size(tas) == static_cast<size_t>(StationAnimationTrigger::End));
949
950 assert(st != nullptr);
951
952 /* Check the cached animation trigger bitmask to see if we need
953 * to bother with any further processing. */
954 if (!st->cached_anim_triggers.Test(trigger)) return;
955
956 uint16_t random_bits = Random();
957
958 /* Check all tiles over the station to check if the specindex is still in use */
959 for (TileIndex tile : GetRailTileArea(st, trigger_tile, tas[static_cast<size_t>(trigger)])) {
960 if (st->TileBelongsToRailStation(tile)) {
961 const StationSpec *ss = GetStationSpec(tile);
962 if (ss != nullptr && ss->animation.triggers.Test(trigger)) {
963 uint8_t var18_extra = 0;
964 if (IsValidCargoType(cargo_type)) {
965 var18_extra |= ss->grf_prop.grffile->cargo_map[cargo_type] << 8;
966 }
967 StationAnimationBase::ChangeAnimationFrame(CBID_STATION_ANIMATION_TRIGGER, ss, st, tile, (random_bits << 16) | GB(Random(), 0, 16), to_underlying(trigger) | var18_extra);
968 }
969 }
970 }
971}
972
981{
982 /* List of coverage areas for each animation trigger */
983 static constexpr TriggerArea tas[] = {
984 TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM
985 };
986
987 assert(st != nullptr);
988
989 /* Check the cached cargo trigger bitmask to see if we need
990 * to bother with any further processing.
991 * Note: cached_cargo_triggers must be non-zero even for cargo-independent triggers. */
992 if (st->cached_cargo_triggers == 0) return;
993 if (IsValidCargoType(cargo_type) && !HasBit(st->cached_cargo_triggers, cargo_type)) return;
994
995 uint32_t whole_reseed = 0;
996
997 /* Bitmask of completely empty cargo types to be matched. */
998 CargoTypes empty_mask{};
999 if (trigger == StationRandomTrigger::CargoTaken) {
1000 empty_mask = GetEmptyMask(Station::From(st));
1001 }
1002
1003 /* Store triggers now for var 5F */
1004 TriggerArea ta = tas[to_underlying(trigger)];
1005 if (ta == TA_WHOLE) st->waiting_random_triggers.Set(trigger);
1006 StationRandomTriggers used_random_triggers;
1007
1008 /* Check all tiles over the station to check if the specindex is still in use */
1009 for (TileIndex tile : GetRailTileArea(st, trigger_tile, ta)) {
1010 if (st->TileBelongsToRailStation(tile)) {
1011 /* Store triggers now for var 5F */
1012 st->tile_waiting_random_triggers[tile].Set(trigger);
1013
1014 const StationSpec *ss = GetStationSpec(tile);
1015 if (ss == nullptr) continue;
1016
1017 /* Cargo taken "will only be triggered if all of those
1018 * cargo types have no more cargo waiting." */
1019 if (trigger == StationRandomTrigger::CargoTaken) {
1020 if ((ss->cargo_triggers & ~empty_mask) != 0) continue;
1021 }
1022
1023 if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) {
1024 StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0);
1025 object.SetWaitingRandomTriggers(st->waiting_random_triggers | st->tile_waiting_random_triggers[tile]);
1026
1027 object.ResolveRerandomisation();
1028
1029 st->tile_waiting_random_triggers[tile].Reset(object.GetUsedRandomTriggers());
1030 used_random_triggers.Set(object.GetUsedRandomTriggers());
1031
1032 uint32_t reseed = object.GetReseedSum();
1033 if (reseed != 0) {
1034 whole_reseed |= reseed;
1035 reseed >>= 16;
1036
1037 /* Set individual tile random bits */
1038 uint8_t random_bits = GetStationTileRandomBits(tile);
1039 random_bits &= ~reseed;
1040 random_bits |= Random() & reseed;
1041 SetStationTileRandomBits(tile, random_bits);
1042
1043 MarkTileDirtyByTile(tile);
1044 }
1045 }
1046 }
1047 }
1048
1049 /* Update whole station random bits */
1050 st->waiting_random_triggers.Reset(used_random_triggers);
1051 if ((whole_reseed & 0xFFFF) != 0) {
1052 st->random_bits &= ~whole_reseed;
1053 st->random_bits |= Random() & whole_reseed;
1054 }
1055}
1056
1062{
1063 st->cached_anim_triggers = {};
1064 st->cached_cargo_triggers = 0;
1065
1066 /* Combine animation trigger bitmask for all station specs
1067 * of this station. */
1068 for (const auto &sm : GetStationSpecList<StationSpec>(st)) {
1069 if (sm.spec == nullptr) continue;
1070 st->cached_anim_triggers.Set(sm.spec->animation.triggers);
1071 st->cached_cargo_triggers |= sm.spec->cargo_triggers;
1072 }
1073}
1074
std::vector< SpecMapping< T > > & GetStationSpecList(BaseStation *bst)
Get spec mapping list for each supported custom spec type.
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.
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 SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
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:21
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:108
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.
static StationClassID Allocate(uint32_t global_id)
const Tspec * GetSpec(uint index) const
Get a spec from the class at a given index.
void Insert(Tspec *spec)
Insert a spec into the class, and update its index.
static NewGRFClass * Get(StationClassID class_index)
StringID name
Name of this class.
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:115
uint8_t fallback_railtype
Original railtype number to use when drawing non-newgrf railtypes, or when drawing stations.
Definition rail.h:190
uint GetRailtypeSpriteOffset() const
Offset between the current railtype and normal rail.
Definition rail.h:287
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.
SetBitIterator< uint8_t, uint32_t > Var10Values() const
Get values for variable 10 to resolve sprites for.
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
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:21
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:1038
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, RoadTramType sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:392
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:559
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:429
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:419
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
Definition map_func.h:461
TileIndexDiff TileOffsByDir(Direction dir)
Convert a Direction to a TileIndexDiff.
Definition map_func.h:588
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
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
GrfSpecFeature
Definition newgrf.h:72
@ Stations
Stations feature.
Definition newgrf.h:77
@ 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.
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, RailSpriteType 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.
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 AssignSpecToStation(const StationSpec *spec, BaseStation *st, uint8_t specindex)
Assign a previously allocated StationSpec specindex to a Station.
void DeallocateSpecFromStation(BaseStation *st, uint8_t specindex)
Deallocate a StationSpec from a Station.
TileArea GetRailTileArea(const BaseStation *st, TileIndex tile, TriggerArea ta)
Get the tile area of a rail station with trigger area type.
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)
Perform the station callback in the context of the AnimationBase callback.
std::optional< uint8_t > AllocateSpecToStation(const StationSpec *spec, BaseStation *st)
Allocate a StationSpec to a Station.
Header file for NewGRF stations.
@ Cb141RandomBits
Callback 141 needs random bits.
@ DivByStationArea
Divide cargo amount by station area.
@ SeparateGround
Use different sprite set for ground sprites.
@ DivByStationSize
Divide cargo amount by station size (perimeter).
PoolID< uint16_t, struct StationClassIDTag, UINT16_MAX, UINT16_MAX > StationClassID
Class IDs for stations.
Functions to handle the town part of NewGRF towns.
@ Ground
Main group of ground images.
Definition rail.h:43
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:301
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
@ Invalid
Invalid marker.
Definition road_type.h:41
Base class for roadstops.
A number of safeguards to prevent using unsafe methods.
Slope
Enumeration for the slope-type.
Definition slope_type.h:47
@ SLOPE_EW
east and west corner are raised
Definition slope_type.h:58
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:122
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:207
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition sprites.h:1559
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?
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?
bool HasStationReservation(Tile t)
Get the reservation state of the rail station.
@ HVOT_WAYPOINT
Station is a waypoint (NewGRF only!).
@ Rail
Railways/train station.
@ RailWaypoint
Waypoint for trains.
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
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)
static void ChangeAnimationFrame(CallbackID cb, const StationSpec *spec, BaseStation *obj, TileIndex tile, uint32_t random_bits, uint32_t trigger, int extra_data=0)
Base class for all station-ish types.
std::vector< SpecMapping< StationSpec > > speclist
List of rail station specs of this station.
virtual TileArea GetTileArea(StationType type) const =0
Get the tile area for a given station type.
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.
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.
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:76
Ground palette sprite of a tile, together with its sprite layout.
Definition sprite.h:55
PalSpriteID ground
Palette and sprite for the ground.
Definition sprite.h:56
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:140
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.
uint TotalCount() const
Returns total count of cargo at the station, including cargo which is already reserved for loading.
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.
@ 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.
const GoodsEntryData & GetData() const
Get optional cargo packet/flow data.
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.
bool HasData() const
Test if this goods entry has optional cargo packet/flow data.
uint8_t ConvertState() const
Convert GoodsEntry status to the form required for NewGRF variables.
NewGRF supplied spritelayout.
bool NeedsPreprocessing() const
Tests whether this spritelayout needs preprocessing by SpriteLayoutProcessor, or whether it can be us...
uint16_t w
The width 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
'Real' sprite groups contain a list of other result or callback sprite groups.
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.
uint32_t callback_param2
Second parameter (var 18) of the callback.
CallbackID callback
Callback being resolved.
uint32_t callback_param1
First parameter (var 10) of the callback.
A result sprite group returns the first SpriteID and the number of sprites in the set.
ResolverObject & ro
Surrounding resolver object.
Specialization of ResolverObject with type-safe access to RandomTriggers.
static bool IsExpected(const BaseStation *st)
static Station * From(BaseStation *st)
Common wrapper for all the different sprite group types.
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.
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.
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.
bool TileBelongsToRailStation(TileIndex tile) const override
Check whether a specific tile belongs to 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:63
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.
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition tile_map.h:250
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
@ TunnelBridge
Tunnel entry/exit and bridge heads.
Definition tile_type.h:58
@ Station
A tile of a station or airport.
Definition tile_type.h:54
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
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:578
TrackBits TrackStatusToTrackBits(TrackStatus ts)
Returns the present-track-information of a TrackStatus.
Definition track_func.h:365
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.