OpenTTD Source 20260206-master-g4d4e37dbf1
newgrf_roadstop.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 "roadstop_base.h"
14#include "newgrf_badge.h"
15#include "newgrf_roadstop.h"
16#include "newgrf_cargo.h"
17#include "newgrf_roadtype.h"
18#include "gfx_type.h"
19#include "company_func.h"
20#include "road.h"
21#include "window_type.h"
23#include "town.h"
24#include "tile_cmd.h"
25#include "viewport_func.h"
27#include "newgrf_sound.h"
28
29#include "table/strings.h"
30
31#include "newgrf_class_func.h"
32
33#include "safeguards.h"
34
35template <>
37{
38 /* Set up initial data */
39 RoadStopClass::Get(RoadStopClass::Allocate(ROADSTOP_CLASS_LABEL_DEFAULT))->name = STR_STATION_CLASS_DFLT;
40 RoadStopClass::Get(RoadStopClass::Allocate(ROADSTOP_CLASS_LABEL_DEFAULT))->Insert(nullptr);
41 RoadStopClass::Get(RoadStopClass::Allocate(ROADSTOP_CLASS_LABEL_WAYPOINT))->name = STR_STATION_CLASS_WAYP;
42 RoadStopClass::Get(RoadStopClass::Allocate(ROADSTOP_CLASS_LABEL_WAYPOINT))->Insert(nullptr);
43}
44
45template <>
47{
48 return true;
49}
50
51/* Instantiate RoadStopClass. */
53
54static const uint NUM_ROADSTOPSPECS_PER_STATION = 63;
55
57{
58 if (this->st == nullptr) return 0;
59
60 uint32_t bits = this->st->random_bits;
61 if (this->tile != INVALID_TILE && Station::IsExpected(this->st)) {
62 bits |= Station::From(this->st)->GetRoadStopRandomBits(this->tile) << 16;
63 }
64 return bits;
65}
66
68{
69 if (this->st == nullptr) return 0;
70
71 StationRandomTriggers triggers = st->waiting_random_triggers;
72
73 auto it = this->st->tile_waiting_random_triggers.find(this->tile);
74 if (it != std::end(this->st->tile_waiting_random_triggers)) triggers.Set(it->second);
75
76 return triggers.base();
77}
78
79uint32_t RoadStopScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
80{
81 auto get_road_type_variable = [&](RoadTramType rtt) -> uint32_t {
82 RoadType rt;
83 if (this->tile == INVALID_TILE) {
84 rt = (GetRoadTramType(this->roadtype) == rtt) ? this->roadtype : INVALID_ROADTYPE;
85 } else {
86 rt = GetRoadType(this->tile, rtt);
87 }
88 if (rt == INVALID_ROADTYPE) {
89 return 0xFFFFFFFF;
90 } else {
91 return GetReverseRoadTypeTranslation(rt, this->roadstopspec->grf_prop.grffile);
92 }
93 };
94
95 switch (variable) {
96 /* View/rotation */
97 case 0x40: return this->view;
98
99 /* Stop type: 0: bus, 1: truck, 2: waypoint */
100 case 0x41:
101 if (this->type == StationType::Bus) return 0;
102 if (this->type == StationType::Truck) return 1;
103 return 2;
104
105 /* Terrain type */
106 case 0x42: return this->tile == INVALID_TILE ? 0 : (GetTileSlope(this->tile) << 8 | GetTerrainType(this->tile, TCX_NORMAL));
107
108 /* Road type */
109 case 0x43: return get_road_type_variable(RTT_ROAD);
110
111 /* Tram type */
112 case 0x44: return get_road_type_variable(RTT_TRAM);
113
114 /* Town zone and Manhattan distance of closest town */
115 case 0x45: {
116 if (this->tile == INVALID_TILE) return to_underlying(HouseZone::TownEdge) << 16;
117 const Town *t = (this->st == nullptr) ? ClosestTownFromTile(this->tile, UINT_MAX) : this->st->town;
118 return t != nullptr ? (to_underlying(GetTownRadiusGroup(t, this->tile)) << 16 | ClampTo<uint16_t>(DistanceManhattan(this->tile, t->xy))) : to_underlying(HouseZone::TownEdge) << 16;
119 }
120
121 /* Get square of Euclidean distance of closest town */
122 case 0x46: {
123 if (this->tile == INVALID_TILE) return 0;
124 const Town *t = (this->st == nullptr) ? ClosestTownFromTile(this->tile, UINT_MAX) : this->st->town;
125 return t != nullptr ? DistanceSquare(this->tile, t->xy) : 0;
126 }
127
128 /* Company information */
129 case 0x47: return GetCompanyInfo(this->st == nullptr ? _current_company : this->st->owner);
130
131 /* Animation frame */
132 case 0x49: return this->tile == INVALID_TILE ? 0 : this->st->GetRoadStopAnimationFrame(this->tile);
133
134 /* Misc info */
135 case 0x50: {
136 uint32_t result = 0;
137 if (this->tile == INVALID_TILE) {
138 SetBit(result, 4);
139 }
140 return result;
141 }
142
143 /* Variables which use the parameter */
144 /* Variables 0x60 to 0x65 and 0x69 are handled separately below */
145
146 /* Animation frame of nearby tile */
147 case 0x66: {
148 if (this->tile == INVALID_TILE) return UINT_MAX;
149 TileIndex tile = this->tile;
150 if (parameter != 0) tile = GetNearbyTile(parameter, tile);
151 return (IsAnyRoadStopTile(tile) && GetStationIndex(tile) == this->st->index) ? this->st->GetRoadStopAnimationFrame(tile) : UINT_MAX;
152 }
153
154 /* Land info of nearby tile */
155 case 0x67: {
156 if (this->tile == INVALID_TILE) return 0;
157 TileIndex tile = this->tile;
158 if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required
159 return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8);
160 }
161
162 /* Road stop info of nearby tiles */
163 case 0x68: {
164 if (this->tile == INVALID_TILE) return 0xFFFFFFFF;
165 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
166
167 if (!IsAnyRoadStopTile(nearby_tile)) return 0xFFFFFFFF;
168
169 uint32_t grfid = this->st->roadstop_speclist[GetCustomRoadStopSpecIndex(this->tile)].grfid;
170 bool same_orientation = GetStationGfx(this->tile) == GetStationGfx(nearby_tile);
171 bool same_station = GetStationIndex(nearby_tile) == this->st->index;
172 uint32_t res = GetStationGfx(nearby_tile) << 12 | !same_orientation << 11 | !!same_station << 10;
173 StationType type = GetStationType(nearby_tile);
174 if (type == StationType::Truck) res |= (1 << 16);
175 if (type == StationType::RoadWaypoint) res |= (2 << 16);
176 if (type == this->type) SetBit(res, 20);
177
178 if (IsCustomRoadStopSpecIndex(nearby_tile)) {
179 const auto &sm = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
180 res |= 1 << (sm.grfid != grfid ? 9 : 8) | ClampTo<uint8_t>(sm.localidx);
181 }
182 return res;
183 }
184
185 /* GRFID of nearby road stop tiles */
186 case 0x6A: {
187 if (this->tile == INVALID_TILE) return 0xFFFFFFFF;
188 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
189
190 if (!IsAnyRoadStopTile(nearby_tile)) return 0xFFFFFFFF;
191 if (!IsCustomRoadStopSpecIndex(nearby_tile)) return 0;
192
193 const auto &sm = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
194 return sm.grfid;
195 }
196
197 /* 16 bit road stop ID of nearby tiles */
198 case 0x6B: {
199 if (this->tile == INVALID_TILE) return 0xFFFFFFFF;
200 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
201
202 if (!IsAnyRoadStopTile(nearby_tile)) return 0xFFFFFFFF;
203 if (!IsCustomRoadStopSpecIndex(nearby_tile)) return 0xFFFE;
204
205 uint32_t grfid = this->st->roadstop_speclist[GetCustomRoadStopSpecIndex(this->tile)].grfid;
206
207 const auto &sm = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
208 if (sm.grfid == grfid) {
209 return sm.localidx;
210 }
211
212 return 0xFFFE;
213 }
214
215 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, this->roadstopspec->badges, parameter);
216
217 case 0xF0: return this->st == nullptr ? 0 : this->st->facilities.base(); // facilities
218
219 case 0xFA: return ClampTo<uint16_t>((this->st == nullptr ? TimerGameCalendar::date : this->st->build_date) - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // build date
220 }
221
222 if (this->st != nullptr) return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
223
224 available = false;
225 return UINT_MAX;
226}
227
228RoadStopResolverObject::RoadStopResolverObject(const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, RoadType roadtype, StationType type, uint8_t view,
229 CallbackID callback, uint32_t param1, uint32_t param2)
230 : SpecializedResolverObject<StationRandomTriggers>(roadstopspec->grf_prop.grffile, callback, param1, param2), roadstop_scope(*this, st, roadstopspec, tile, roadtype, type, view)
231{
233
234 if (st == nullptr) {
235 /* No station, so we are in a purchase list */
237 } else if (Station::IsExpected(st)) {
238 const Station *station = Station::From(st);
239 /* Pick the first cargo that we have waiting */
240 for (const auto &[cargo, spritegroup] : roadstopspec->grf_prop.spritegroups) {
241 if (cargo < NUM_CARGO && station->goods[cargo].TotalCount() > 0) {
242 ctype = cargo;
243 this->root_spritegroup = spritegroup;
244 break;
245 }
246 }
247 }
248
249 this->root_spritegroup = this->roadstop_scope.roadstopspec->grf_prop.GetSpriteGroup(ctype);
250 if (this->root_spritegroup == nullptr) {
252 this->root_spritegroup = this->roadstop_scope.roadstopspec->grf_prop.GetSpriteGroup(ctype);
253 }
254
255 /* Remember the cargo type we've picked */
256 this->roadstop_scope.cargo_type = ctype;
257}
258
259TownScopeResolver *RoadStopResolverObject::GetTown()
260{
261 if (!this->town_scope.has_value()) {
262 Town *t;
263 if (this->roadstop_scope.st != nullptr) {
264 t = this->roadstop_scope.st->town;
265 } else {
266 t = ClosestTownFromTile(this->roadstop_scope.tile, UINT_MAX);
267 }
268 if (t == nullptr) return nullptr;
269 this->town_scope.emplace(*this, t, this->roadstop_scope.st == nullptr);
270 }
271 return &*this->town_scope;
272}
273
274uint16_t GetRoadStopCallback(CallbackID callback, uint32_t param1, uint32_t param2, const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, RoadType roadtype, StationType type, uint8_t view, std::span<int32_t> regs100)
275{
276 RoadStopResolverObject object(roadstopspec, st, tile, roadtype, type, view, callback, param1, param2);
277 return object.ResolveCallback(regs100);
278}
279
290void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec, StationType type, int view)
291{
292 assert(roadtype != INVALID_ROADTYPE);
293 assert(spec != nullptr);
294
295 const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype);
296 RoadStopResolverObject object(spec, nullptr, INVALID_TILE, roadtype, type, view);
297 const auto *group = object.Resolve<TileLayoutSpriteGroup>();
298 if (group == nullptr) return;
299 auto processor = group->ProcessRegisters(object, nullptr);
300 auto dts = processor.GetLayout();
301
303
304 SpriteID image = dts.ground.sprite;
305 PaletteID pal = dts.ground.pal;
306
307 RoadStopDrawModes draw_mode;
308 if (spec->flags.Test(RoadStopSpecFlag::DrawModeRegister)) {
309 draw_mode = static_cast<RoadStopDrawModes>(object.GetRegister(0x100));
310 } else {
311 draw_mode = spec->draw_mode;
312 }
313
314 if (type == StationType::RoadWaypoint) {
315 DrawSprite(SPR_ROAD_PAVED_STRAIGHT_X, PAL_NONE, x, y);
316 if (draw_mode.Test(RoadStopDrawMode::WaypGround) && GB(image, 0, SPRITE_WIDTH) != 0) {
317 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
318 }
319 } else if (GB(image, 0, SPRITE_WIDTH) != 0) {
320 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
321 }
322
323 if (view >= 4) {
324 /* Drive-through stop */
325 uint sprite_offset = 5 - view;
326
327 /* Road underlay takes precedence over tram */
328 if (type == StationType::RoadWaypoint || draw_mode.Test(RoadStopDrawMode::Overlay)) {
329 if (rti->UsesOverlay()) {
331 DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
332
334 if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
335 } else if (RoadTypeIsTram(roadtype)) {
336 DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
337 }
338 }
339 } else {
340 /* Bay stop */
341 if (draw_mode.Test(RoadStopDrawMode::Road) && rti->UsesOverlay()) {
343 DrawSprite(ground + view, PAL_NONE, x, y);
344 }
345 }
346
347 DrawCommonTileSeqInGUI(x, y, &dts, 0, 0, palette, true);
348}
349
350std::optional<SpriteLayoutProcessor> GetRoadStopLayout(TileInfo *ti, const RoadStopSpec *spec, BaseStation *st, StationType type, int view, std::span<int32_t> regs100)
351{
352 RoadStopResolverObject object(spec, st, ti->tile, INVALID_ROADTYPE, type, view);
353 auto group = object.Resolve<TileLayoutSpriteGroup>();
354 if (group == nullptr) return std::nullopt;
355 for (uint i = 0; i < regs100.size(); ++i) {
356 regs100[i] = object.GetRegister(0x100 + i);
357 }
358 return group->ProcessRegisters(object, nullptr);
359}
360
362uint16_t GetAnimRoadStopCallback(CallbackID callback, uint32_t param1, uint32_t param2, const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, int)
363{
364 return GetRoadStopCallback(callback, param1, param2, roadstopspec, st, tile, INVALID_ROADTYPE, GetStationType(tile), GetStationGfx(tile));
365}
366
368 static uint8_t Get(BaseStation *st, TileIndex tile) { return st->GetRoadStopAnimationFrame(tile); }
369 static bool Set(BaseStation *st, TileIndex tile, uint8_t frame) { return st->SetRoadStopAnimationFrame(tile, frame); }
370};
371
380
381void AnimateRoadStopTile(TileIndex tile)
382{
383 const RoadStopSpec *ss = GetRoadStopSpec(tile);
384 if (ss == nullptr) return;
385
387}
388
389void TriggerRoadStopAnimation(BaseStation *st, TileIndex trigger_tile, StationAnimationTrigger trigger, CargoType cargo_type)
390{
391 assert(st != nullptr);
392
393 /* Check the cached animation trigger bitmask to see if we need
394 * to bother with any further processing. */
395 if (!st->cached_roadstop_anim_triggers.Test(trigger)) return;
396
397 uint16_t random_bits = Random();
398 auto process_tile = [&](TileIndex cur_tile) {
399 const RoadStopSpec *ss = GetRoadStopSpec(cur_tile);
400 if (ss != nullptr && ss->animation.triggers.Test(trigger)) {
401 uint8_t var18_extra = 0;
402 if (IsValidCargoType(cargo_type)) {
403 var18_extra |= ss->grf_prop.grffile->cargo_map[cargo_type] << 8;
404 }
405 RoadStopAnimationBase::ChangeAnimationFrame(CBID_STATION_ANIMATION_TRIGGER, ss, st, cur_tile, (random_bits << 16) | GB(Random(), 0, 16), to_underlying(trigger) | var18_extra);
406 }
407 };
408
410 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
411 process_tile(tile_data.tile);
412 }
413 } else {
414 process_tile(trigger_tile);
415 }
416}
417
427{
428 enum TriggerArea : uint8_t {
429 TA_TILE,
430 TA_PLATFORM,
431 TA_WHOLE,
432 };
433
434 /* List of coverage areas for each animation trigger */
435 static constexpr TriggerArea tas[] = {
436 TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM
437 };
438
439 assert(st != nullptr);
440
441 /* Check the cached cargo trigger bitmask to see if we need
442 * to bother with any further processing.
443 * Note: cached_roadstop_cargo_triggers must be non-zero even for cargo-independent triggers. */
444 if (st->cached_roadstop_cargo_triggers == 0) return;
445 if (IsValidCargoType(cargo_type) && !HasBit(st->cached_roadstop_cargo_triggers, cargo_type)) return;
446
447 TriggerArea ta = tas[to_underlying(trigger)];
448 if (ta == TA_WHOLE) st->waiting_random_triggers.Set(trigger);
449 StationRandomTriggers used_random_triggers;
450
451 uint32_t whole_reseed = 0;
452
453 /* Bitmask of completely empty cargo types to be matched. */
454 CargoTypes empty_mask{};
455 if (trigger == StationRandomTrigger::CargoTaken) {
456 empty_mask = GetEmptyMask(Station::From(st));
457 }
458
459 auto process_tile = [&](TileIndex cur_tile) {
460 const RoadStopSpec *ss = GetRoadStopSpec(cur_tile);
461 if (ss == nullptr) return;
462
463 st->tile_waiting_random_triggers[tile].Set(trigger);
464
465 /* Cargo taken "will only be triggered if all of those
466 * cargo types have no more cargo waiting." */
467 if (trigger == StationRandomTrigger::CargoTaken) {
468 if ((ss->cargo_triggers & ~empty_mask) != 0) return;
469 }
470
471 if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) {
472 RoadStopResolverObject object(ss, st, cur_tile, INVALID_ROADTYPE, GetStationType(cur_tile), GetStationGfx(cur_tile));
473 object.SetWaitingRandomTriggers(st->waiting_random_triggers | st->tile_waiting_random_triggers[tile]);
474
475 object.ResolveRerandomisation();
476
477 st->tile_waiting_random_triggers[tile].Reset(object.GetUsedRandomTriggers());
478 used_random_triggers.Set(object.GetUsedRandomTriggers());
479
480 uint32_t reseed = object.GetReseedSum();
481 if (reseed != 0) {
482 whole_reseed |= reseed;
483 reseed >>= 16;
484
485 /* Set individual tile random bits */
486 uint8_t random_bits = st->GetRoadStopRandomBits(cur_tile);
487 random_bits &= ~reseed;
488 random_bits |= Random() & reseed;
489 st->SetRoadStopRandomBits(cur_tile, random_bits);
490
491 MarkTileDirtyByTile(cur_tile);
492 }
493 }
494 };
495 if (ta == TA_WHOLE) {
496 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
497 process_tile(tile_data.tile);
498 }
499 } else {
500 process_tile(tile);
501 }
502
503 /* Update whole station random bits */
504 st->waiting_random_triggers.Reset(used_random_triggers);
505 if ((whole_reseed & 0xFFFF) != 0) {
506 st->random_bits &= ~whole_reseed;
507 st->random_bits |= Random() & whole_reseed;
508 }
509}
510
518{
519 for (const auto &cls : RoadStopClass::Classes()) {
520 /* Ignore the waypoint class. */
521 if (IsWaypointClass(cls)) continue;
522 /* Ignore the default class with only the default station. */
523 if (cls.Index() == ROADSTOP_CLASS_DFLT && cls.GetSpecCount() == 1) continue;
524 if (GetIfClassHasNewStopsByType(&cls, rs, roadtype)) return true;
525 }
526 return false;
527}
528
536bool GetIfClassHasNewStopsByType(const RoadStopClass *roadstopclass, RoadStopType rs, RoadType roadtype)
537{
538 for (const auto spec : roadstopclass->Specs()) {
539 if (GetIfStopIsForType(spec, rs, roadtype)) return true;
540 }
541 return false;
542}
543
551bool GetIfStopIsForType(const RoadStopSpec *roadstopspec, RoadStopType rs, RoadType roadtype)
552{
553 /* The roadstopspec is nullptr, must be the default station, always return true. */
554 if (roadstopspec == nullptr) return true;
555
556 if (roadstopspec->flags.Test(RoadStopSpecFlag::RoadOnly) && !RoadTypeIsRoad(roadtype)) return false;
557 if (roadstopspec->flags.Test(RoadStopSpecFlag::TramOnly) && !RoadTypeIsTram(roadtype)) return false;
558
559 if (roadstopspec->stop_type == ROADSTOPTYPE_ALL) return true;
560
561 switch (rs) {
563 if (roadstopspec->stop_type == ROADSTOPTYPE_PASSENGER) return true;
564 break;
565
567 if (roadstopspec->stop_type == ROADSTOPTYPE_FREIGHT) return true;
568 break;
569
570 default:
571 NOT_REACHED();
572 }
573 return false;
574}
575
576const RoadStopSpec *GetRoadStopSpec(TileIndex t)
577{
578 if (!IsCustomRoadStopSpecIndex(t)) return nullptr;
579
580 const BaseStation *st = BaseStation::GetByTile(t);
581 uint specindex = GetCustomRoadStopSpecIndex(t);
582 return specindex < st->roadstop_speclist.size() ? st->roadstop_speclist[specindex].spec : nullptr;
583}
584
591std::optional<uint8_t> AllocateSpecToRoadStop(const RoadStopSpec *spec, BaseStation *st)
592{
593 uint i;
594
595 if (spec == nullptr) return 0;
596
597 /* If station doesn't exist yet then the first slot is available. */
598 if (st == nullptr) return 1;
599
600 /* Try to find the same spec and return that one */
601 for (i = 1; i < st->roadstop_speclist.size() && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
602 if (st->roadstop_speclist[i].spec == spec) return i;
603 }
604
605 /* Try to find an unused spec slot */
606 for (i = 1; i < st->roadstop_speclist.size() && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
607 if (st->roadstop_speclist[i].spec == nullptr && st->roadstop_speclist[i].grfid == 0) break;
608 }
609
611 /* Full, give up */
612 return std::nullopt;
613 }
614
615 return i;
616}
617
624void AssignSpecToRoadStop(const RoadStopSpec *spec, BaseStation *st, uint8_t specindex)
625{
626 if (specindex == 0) return;
627 if (specindex >= st->roadstop_speclist.size()) st->roadstop_speclist.resize(specindex + 1);
628
629 st->roadstop_speclist[specindex].spec = spec;
630 st->roadstop_speclist[specindex].grfid = spec->grf_prop.grfid;
631 st->roadstop_speclist[specindex].localidx = spec->grf_prop.local_id;
632
634}
635
641void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex)
642{
643 /* specindex of 0 (default) is never freeable */
644 if (specindex == 0) return;
645
646 /* Check custom road stop tiles if the specindex is still in use */
647 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
648 if (GetCustomRoadStopSpecIndex(tile_data.tile) == specindex) {
649 return;
650 }
651 }
652
653 /* This specindex is no longer in use, so deallocate it */
654 st->roadstop_speclist[specindex].spec = nullptr;
655 st->roadstop_speclist[specindex].grfid = 0;
656 st->roadstop_speclist[specindex].localidx = 0;
657
658 /* If this was the highest spec index, reallocate */
659 if (specindex == st->roadstop_speclist.size() - 1) {
660 size_t num_specs;
661 for (num_specs = st->roadstop_speclist.size() - 1; num_specs > 0; num_specs--) {
662 if (st->roadstop_speclist[num_specs].grfid != 0) break;
663 }
664
665 if (num_specs > 0) {
666 st->roadstop_speclist.resize(num_specs + 1);
667 } else {
668 st->roadstop_speclist.clear();
671 return;
672 }
673 }
674
676}
677
683{
686
687 /* Combine animation trigger bitmask for all road stop specs
688 * of this station. */
689 for (const auto &sm : GetStationSpecList<RoadStopSpec>(st)) {
690 if (sm.spec == nullptr) continue;
691 st->cached_roadstop_anim_triggers.Set(sm.spec->animation.triggers);
692 st->cached_roadstop_cargo_triggers |= sm.spec->cargo_triggers;
693 }
694}
std::vector< SpecMapping< T > > & GetStationSpecList(BaseStation *bst)
Get spec mapping list for each supported custom spec type.
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.
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:104
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.
Struct containing information relating to NewGRF classes for stations and airports.
static std::span< NewGRFClass< RoadStopSpec, RoadStopClassID, Tmax > const > Classes()
StringID name
Name of this class.
void Insert(Tspec *spec)
Insert a spec into the class, and update its index.
std::span< Tspec *const > Specs() const
Get read-only span of specs of this class.
static NewGRFClass * Get(RoadStopClassID class_index)
static RoadStopClassID Allocate(uint32_t global_id)
DrawTileSpriteSpan GetLayout() const
Returns the result spritelayout after preprocessing.
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.
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:1038
Types related to the graphics and/or input devices.
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.
@ TownEdge
Edge of the town; roads without pavement.
Definition house.h:58
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:175
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:158
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
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.
CallbackID
List of implemented NewGRF callbacks.
@ CBID_STATION_ANIMATION_TRIGGER
Called for periodically starting or stopping the animation.
@ 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.
RoadStopCallbackMask
Callback masks for road stops.
@ AnimationNextFrame
Use a custom next frame callback.
@ AnimationSpeed
Customize the animation speed of the road stop.
Cargo support for NewGRFs.
Implementation of the NewGRF class' functions.
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.
@ TCX_NORMAL
Nothing special.
static const uint NUM_ROADSTOPSPECS_PER_STATION
Maximum number of parts per station.
void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger road stop randomisation.
void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex)
Deallocate a RoadStopSpec from a Station.
std::optional< uint8_t > AllocateSpecToRoadStop(const RoadStopSpec *spec, BaseStation *st)
Allocate a RoadStopSpec to a Station.
void RoadStopUpdateCachedTriggers(BaseStation *st)
Update the cached animation trigger bitmask for a station.
void AssignSpecToRoadStop(const RoadStopSpec *spec, BaseStation *st, uint8_t specindex)
Assign a previously allocated RoadStopSpec specindex to a Station.
bool GetIfClassHasNewStopsByType(const RoadStopClass *roadstopclass, RoadStopType rs, RoadType roadtype)
Checks if the given RoadStopClass has any specs assigned to it, compatible with the given RoadStopTyp...
void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec, StationType type, int view)
Draw representation of a road stop tile for GUI purposes.
bool GetIfNewStopsByType(RoadStopType rs, RoadType roadtype)
Checks if there's any new stations by a specific RoadStopType.
uint16_t GetAnimRoadStopCallback(CallbackID callback, uint32_t param1, uint32_t param2, const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, int)
Wrapper for animation control, see GetRoadStopCallback.
bool GetIfStopIsForType(const RoadStopSpec *roadstopspec, RoadStopType rs, RoadType roadtype)
Checks if the given RoadStopSpec is compatible with the given RoadStopType.
NewGRF definitions and structures for road stops.
@ Overlay
Drive-through stops: Draw the road overlay, e.g. pavement.
@ WaypGround
Waypoints: Draw the sprite layout ground tile (on top of the road).
@ Road
Bay stops: Draw the road itself.
bool IsWaypointClass(const RoadStopClass &cls)
Test if a RoadStopClass is the waypoint class.
@ ROADSTOP_CLASS_DFLT
Default road stop class.
@ ROADSTOPTYPE_FREIGHT
This RoadStop is for freight (truck) stops.
@ ROADSTOPTYPE_ALL
This RoadStop is for both types of station road stops.
@ ROADSTOPTYPE_PASSENGER
This RoadStop is for passenger (bus) stops.
@ RoadOnly
Only show in the road build menu (not tram).
@ Cb141RandomBits
Callback 141 needs random bits.
@ TramOnly
Only show in the tram build menu (not road).
@ DrawModeRegister
Read draw mode from register 0x100.
SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
uint8_t GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile)
Perform a reverse roadtype lookup to get the GRF internal ID.
NewGRF handling of road types.
Functions related to NewGRF provided sounds.
Road specific functions.
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
@ ROTSG_OVERLAY
Optional: Images for overlaying track.
Definition road.h:38
@ ROTSG_ROADSTOP
Required: Bay stop surface.
Definition road.h:47
@ ROTSG_GROUND
Required: Main group of ground images.
Definition road.h:39
RoadTramType
The different types of road type.
Definition road_type.h:37
@ RTT_ROAD
Road road type.
Definition road_type.h:38
@ RTT_TRAM
Tram road type.
Definition road_type.h:39
RoadType
The different roadtypes we support.
Definition road_type.h:23
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
Base class for roadstops.
A number of safeguards to prevent using unsafe methods.
@ Town
Source/destination is a town.
Definition source_type.h:22
void DrawCommonTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32_t orig_offset, uint32_t newgrf_offset, PaletteID default_palette, bool child_offset_is_unsigned)
Draws a tile sprite sequence in the GUI.
Definition sprite.cpp:86
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:198
static constexpr uint8_t SPRITE_WIDTH
number of bits for the sprite number
Definition sprites.h:1549
Base classes/functions for stations.
CargoTypes GetEmptyMask(const Station *st)
Get a mask of the cargo types that are empty at the station.
StationType GetStationType(Tile t)
Get the station type of this tile.
Definition station_map.h:44
StationGfx GetStationGfx(Tile t)
Get the station graphics of this tile.
Definition station_map.h:68
uint GetCustomRoadStopSpecIndex(Tile t)
Get the custom road stop spec for this tile.
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
bool IsCustomRoadStopSpecIndex(Tile t)
Is there a custom road stop spec on this tile?
bool IsAnyRoadStopTile(Tile t)
Is tile t a road stop station?
RoadStopType
Types of RoadStops.
@ Bus
A standard stop for buses.
@ Truck
A standard stop for trucks.
StationType
Station types.
@ Bus
Road stop for busses.
@ Truck
Road stop for trucks.
@ RoadWaypoint
Waypoint for trucks and busses.
StationRandomTrigger
Randomisation triggers for stations and roadstops.
@ CargoTaken
Trigger station when cargo is completely taken.
StationAnimationTrigger
Animation triggers for stations and roadstops.
@ NewCargo
Trigger station on new cargo arrival.
@ AcceptanceTick
Trigger station every 250 ticks.
@ CargoTaken
Trigger station when cargo is completely taken.
Definition of base types and functions in a cross-platform compatible way.
Helper class for a unified approach to NewGRF animation.
static void AnimateTile(const RoadStopSpec *spec, BaseStation *obj, TileIndex tile, bool random_animation, int extra_data=0)
static void ChangeAnimationFrame(CallbackID cb, const RoadStopSpec *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< RoadStopSpec > > roadstop_speclist
List of road stop specs of this station.
StationAnimationTriggers cached_roadstop_anim_triggers
NOSAVE: Combined animation trigger bitmask for road stops, used to determine if trigger processing sh...
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
CargoTypes cached_roadstop_cargo_triggers
NOSAVE: Combined cargo trigger bitmask for road stops.
uint16_t random_bits
Random bits assigned to this station.
std::vector< RoadStopTileData > custom_roadstop_tile_data
List of custom road stop tile data.
StationRandomTriggers waiting_random_triggers
Waiting triggers (NewGRF), shared by all station parts/tiles, road stops, ... essentially useless and...
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.
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:139
Helper class for animation control.
Road stop resolver.
std::optional< TownScopeResolver > town_scope
The town scope resolver (created on the first call).
RoadStopScopeResolver roadstop_scope
The stop scope resolver.
uint8_t view
Station axis.
RoadType roadtype
Road type (used when no tile).
uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const override
Get a variable value.
StationType type
Station type.
const struct RoadStopSpec * roadstopspec
Station (type) specification.
struct BaseStation * st
Instance of the station.
uint32_t GetRandomTriggers() const override
Get the triggers.
TileIndex tile
Tile of the station.
uint32_t GetRandomBits() const override
Get a few random bits.
Road stop specification.
CargoTypes cargo_triggers
Bitmask of cargo types which cause trigger re-randomizing.
CargoGRFFileProps grf_prop
Link to NewGRF.
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)
Tile information, used while rendering the tile.
Definition tile_cmd.h:32
TileIndex tile
Tile index.
Definition tile_cmd.h:34
Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
SpriteLayoutProcessor ProcessRegisters(const ResolverObject &object, uint8_t *stage) const
Process registers and the construction stage into the sprite layout.
Scope resolver for a town.
Definition newgrf_town.h:22
Town data structure.
Definition town.h:63
TileIndex xy
town center tile
Definition town.h:64
Generic 'commands' that can be performed on all tiles.
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
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.
HouseZone GetTownRadiusGroup(const Town *t, TileIndex tile)
Returns the bit corresponding to the town zone of the specified tile.
Functions related to (drawing on) viewports.
Types related to windows.
@ Station
station encountered (could be a target next time)
Definition yapf_type.hpp:26