OpenTTD Source 20250717-master-g55605ae8f2
newgrf_roadstop.cpp
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "debug.h"
12#include "station_base.h"
13#include "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 <>
46bool RoadStopClass::IsUIAvailable(uint) const
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 return this->st == nullptr ? 0 : this->st->waiting_random_triggers.base();
70}
71
72uint32_t RoadStopScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
73{
74 auto get_road_type_variable = [&](RoadTramType rtt) -> uint32_t {
75 RoadType rt;
76 if (this->tile == INVALID_TILE) {
77 rt = (GetRoadTramType(this->roadtype) == rtt) ? this->roadtype : INVALID_ROADTYPE;
78 } else {
79 rt = GetRoadType(this->tile, rtt);
80 }
81 if (rt == INVALID_ROADTYPE) {
82 return 0xFFFFFFFF;
83 } else {
85 }
86 };
87
88 switch (variable) {
89 /* View/rotation */
90 case 0x40: return this->view;
91
92 /* Stop type: 0: bus, 1: truck, 2: waypoint */
93 case 0x41:
94 if (this->type == StationType::Bus) return 0;
95 if (this->type == StationType::Truck) return 1;
96 return 2;
97
98 /* Terrain type */
99 case 0x42: return this->tile == INVALID_TILE ? 0 : (GetTileSlope(this->tile) << 8 | GetTerrainType(this->tile, TCX_NORMAL));
100
101 /* Road type */
102 case 0x43: return get_road_type_variable(RTT_ROAD);
103
104 /* Tram type */
105 case 0x44: return get_road_type_variable(RTT_TRAM);
106
107 /* Town zone and Manhattan distance of closest town */
108 case 0x45: {
109 if (this->tile == INVALID_TILE) return to_underlying(HouseZone::TownEdge) << 16;
110 const Town *t = (this->st == nullptr) ? ClosestTownFromTile(this->tile, UINT_MAX) : this->st->town;
111 return t != nullptr ? (to_underlying(GetTownRadiusGroup(t, this->tile)) << 16 | ClampTo<uint16_t>(DistanceManhattan(this->tile, t->xy))) : to_underlying(HouseZone::TownEdge) << 16;
112 }
113
114 /* Get square of Euclidean distance of closest town */
115 case 0x46: {
116 if (this->tile == INVALID_TILE) return 0;
117 const Town *t = (this->st == nullptr) ? ClosestTownFromTile(this->tile, UINT_MAX) : this->st->town;
118 return t != nullptr ? DistanceSquare(this->tile, t->xy) : 0;
119 }
120
121 /* Company information */
122 case 0x47: return GetCompanyInfo(this->st == nullptr ? _current_company : this->st->owner);
123
124 /* Animation frame */
125 case 0x49: return this->tile == INVALID_TILE ? 0 : this->st->GetRoadStopAnimationFrame(this->tile);
126
127 /* Misc info */
128 case 0x50: {
129 uint32_t result = 0;
130 if (this->tile == INVALID_TILE) {
131 SetBit(result, 4);
132 }
133 return result;
134 }
135
136 /* Variables which use the parameter */
137 /* Variables 0x60 to 0x65 and 0x69 are handled separately below */
138
139 /* Animation frame of nearby tile */
140 case 0x66: {
141 if (this->tile == INVALID_TILE) return UINT_MAX;
142 TileIndex tile = this->tile;
143 if (parameter != 0) tile = GetNearbyTile(parameter, tile);
144 return (IsAnyRoadStopTile(tile) && GetStationIndex(tile) == this->st->index) ? this->st->GetRoadStopAnimationFrame(tile) : UINT_MAX;
145 }
146
147 /* Land info of nearby tile */
148 case 0x67: {
149 if (this->tile == INVALID_TILE) return 0;
150 TileIndex tile = this->tile;
151 if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required
152 return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8);
153 }
154
155 /* Road stop info of nearby tiles */
156 case 0x68: {
157 if (this->tile == INVALID_TILE) return 0xFFFFFFFF;
158 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
159
160 if (!IsAnyRoadStopTile(nearby_tile)) return 0xFFFFFFFF;
161
162 uint32_t grfid = this->st->roadstop_speclist[GetCustomRoadStopSpecIndex(this->tile)].grfid;
163 bool same_orientation = GetStationGfx(this->tile) == GetStationGfx(nearby_tile);
164 bool same_station = GetStationIndex(nearby_tile) == this->st->index;
165 uint32_t res = GetStationGfx(nearby_tile) << 12 | !same_orientation << 11 | !!same_station << 10;
166 StationType type = GetStationType(nearby_tile);
167 if (type == StationType::Truck) res |= (1 << 16);
168 if (type == StationType::RoadWaypoint) res |= (2 << 16);
169 if (type == this->type) SetBit(res, 20);
170
171 if (IsCustomRoadStopSpecIndex(nearby_tile)) {
172 const auto &sm = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
173 res |= 1 << (sm.grfid != grfid ? 9 : 8) | ClampTo<uint8_t>(sm.localidx);
174 }
175 return res;
176 }
177
178 /* GRFID of nearby road stop tiles */
179 case 0x6A: {
180 if (this->tile == INVALID_TILE) return 0xFFFFFFFF;
181 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
182
183 if (!IsAnyRoadStopTile(nearby_tile)) return 0xFFFFFFFF;
184 if (!IsCustomRoadStopSpecIndex(nearby_tile)) return 0;
185
186 const auto &sm = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
187 return sm.grfid;
188 }
189
190 /* 16 bit road stop ID of nearby tiles */
191 case 0x6B: {
192 if (this->tile == INVALID_TILE) return 0xFFFFFFFF;
193 TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
194
195 if (!IsAnyRoadStopTile(nearby_tile)) return 0xFFFFFFFF;
196 if (!IsCustomRoadStopSpecIndex(nearby_tile)) return 0xFFFE;
197
198 uint32_t grfid = this->st->roadstop_speclist[GetCustomRoadStopSpecIndex(this->tile)].grfid;
199
200 const auto &sm = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
201 if (sm.grfid == grfid) {
202 return sm.localidx;
203 }
204
205 return 0xFFFE;
206 }
207
208 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, this->roadstopspec->badges, parameter);
209
210 case 0xF0: return this->st == nullptr ? 0 : this->st->facilities.base(); // facilities
211
212 case 0xFA: return ClampTo<uint16_t>((this->st == nullptr ? TimerGameCalendar::date : this->st->build_date) - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // build date
213 }
214
215 if (this->st != nullptr) return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
216
217 available = false;
218 return UINT_MAX;
219}
220
221RoadStopResolverObject::RoadStopResolverObject(const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, RoadType roadtype, StationType type, uint8_t view,
222 CallbackID callback, uint32_t param1, uint32_t param2)
223 : SpecializedResolverObject<StationRandomTriggers>(roadstopspec->grf_prop.grffile, callback, param1, param2), roadstop_scope(*this, st, roadstopspec, tile, roadtype, type, view)
224{
226
227 if (st == nullptr) {
228 /* No station, so we are in a purchase list */
230 } else if (Station::IsExpected(st)) {
231 const Station *station = Station::From(st);
232 /* Pick the first cargo that we have waiting */
233 for (const auto &[cargo, spritegroup] : roadstopspec->grf_prop.spritegroups) {
234 if (cargo < NUM_CARGO && station->goods[cargo].HasData() && station->goods[cargo].GetData().cargo.TotalCount() > 0) {
235 ctype = cargo;
236 this->root_spritegroup = spritegroup;
237 break;
238 }
239 }
240 }
241
242 this->root_spritegroup = this->roadstop_scope.roadstopspec->grf_prop.GetSpriteGroup(ctype);
243 if (this->root_spritegroup == nullptr) {
245 this->root_spritegroup = this->roadstop_scope.roadstopspec->grf_prop.GetSpriteGroup(ctype);
246 }
247
248 /* Remember the cargo type we've picked */
249 this->roadstop_scope.cargo_type = ctype;
250}
251
252TownScopeResolver *RoadStopResolverObject::GetTown()
253{
254 if (!this->town_scope.has_value()) {
255 Town *t;
256 if (this->roadstop_scope.st != nullptr) {
257 t = this->roadstop_scope.st->town;
258 } else {
259 t = ClosestTownFromTile(this->roadstop_scope.tile, UINT_MAX);
260 }
261 if (t == nullptr) return nullptr;
262 this->town_scope.emplace(*this, t, this->roadstop_scope.st == nullptr);
263 }
264 return &*this->town_scope;
265}
266
267uint16_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)
268{
269 RoadStopResolverObject object(roadstopspec, st, tile, roadtype, type, view, callback, param1, param2);
270 return object.ResolveCallback(regs100);
271}
272
282void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec, StationType type, int view)
283{
284 assert(roadtype != INVALID_ROADTYPE);
285 assert(spec != nullptr);
286
287 const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype);
288 RoadStopResolverObject object(spec, nullptr, INVALID_TILE, roadtype, type, view);
289 const auto *group = object.Resolve<TileLayoutSpriteGroup>();
290 if (group == nullptr) return;
291 auto processor = group->ProcessRegisters(object, nullptr);
292 auto dts = processor.GetLayout();
293
295
296 SpriteID image = dts.ground.sprite;
297 PaletteID pal = dts.ground.pal;
298
299 RoadStopDrawModes draw_mode;
300 if (spec->flags.Test(RoadStopSpecFlag::DrawModeRegister)) {
301 draw_mode = static_cast<RoadStopDrawModes>(object.GetRegister(0x100));
302 } else {
303 draw_mode = spec->draw_mode;
304 }
305
306 if (type == StationType::RoadWaypoint) {
307 DrawSprite(SPR_ROAD_PAVED_STRAIGHT_X, PAL_NONE, x, y);
308 if (draw_mode.Test(RoadStopDrawMode::WaypGround) && GB(image, 0, SPRITE_WIDTH) != 0) {
309 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
310 }
311 } else if (GB(image, 0, SPRITE_WIDTH) != 0) {
312 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
313 }
314
315 if (view >= 4) {
316 /* Drive-through stop */
317 uint sprite_offset = 5 - view;
318
319 /* Road underlay takes precedence over tram */
320 if (type == StationType::RoadWaypoint || draw_mode.Test(RoadStopDrawMode::Overlay)) {
321 if (rti->UsesOverlay()) {
323 DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
324
326 if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
327 } else if (RoadTypeIsTram(roadtype)) {
328 DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
329 }
330 }
331 } else {
332 /* Bay stop */
333 if (draw_mode.Test(RoadStopDrawMode::Road) && rti->UsesOverlay()) {
335 DrawSprite(ground + view, PAL_NONE, x, y);
336 }
337 }
338
339 DrawCommonTileSeqInGUI(x, y, &dts, 0, 0, palette, true);
340}
341
342std::optional<SpriteLayoutProcessor> GetRoadStopLayout(TileInfo *ti, const RoadStopSpec *spec, BaseStation *st, StationType type, int view, std::span<int32_t> regs100)
343{
344 RoadStopResolverObject object(spec, st, ti->tile, INVALID_ROADTYPE, type, view);
345 auto group = object.Resolve<TileLayoutSpriteGroup>();
346 if (group == nullptr) return std::nullopt;
347 for (uint i = 0; i < regs100.size(); ++i) {
348 regs100[i] = object.GetRegister(0x100 + i);
349 }
350 return group->ProcessRegisters(object, nullptr);
351}
352
354uint16_t GetAnimRoadStopCallback(CallbackID callback, uint32_t param1, uint32_t param2, const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, int)
355{
356 return GetRoadStopCallback(callback, param1, param2, roadstopspec, st, tile, INVALID_ROADTYPE, GetStationType(tile), GetStationGfx(tile));
357}
358
360 static uint8_t Get(BaseStation *st, TileIndex tile) { return st->GetRoadStopAnimationFrame(tile); }
361 static bool Set(BaseStation *st, TileIndex tile, uint8_t frame) { return st->SetRoadStopAnimationFrame(tile, frame); }
362};
363
372
373void AnimateRoadStopTile(TileIndex tile)
374{
375 const RoadStopSpec *ss = GetRoadStopSpec(tile);
376 if (ss == nullptr) return;
377
379}
380
381void TriggerRoadStopAnimation(BaseStation *st, TileIndex trigger_tile, StationAnimationTrigger trigger, CargoType cargo_type)
382{
383 assert(st != nullptr);
384
385 /* Check the cached animation trigger bitmask to see if we need
386 * to bother with any further processing. */
387 if (!st->cached_roadstop_anim_triggers.Test(trigger)) return;
388
389 uint16_t random_bits = Random();
390 auto process_tile = [&](TileIndex cur_tile) {
391 const RoadStopSpec *ss = GetRoadStopSpec(cur_tile);
392 if (ss != nullptr && ss->animation.triggers.Test(trigger)) {
393 uint8_t var18_extra = 0;
394 if (IsValidCargoType(cargo_type)) {
395 var18_extra |= ss->grf_prop.grffile->cargo_map[cargo_type] << 8;
396 }
397 RoadStopAnimationBase::ChangeAnimationFrame(CBID_STATION_ANIMATION_TRIGGER, ss, st, cur_tile, (random_bits << 16) | GB(Random(), 0, 16), to_underlying(trigger) | var18_extra);
398 }
399 };
400
402 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
403 process_tile(tile_data.tile);
404 }
405 } else {
406 process_tile(trigger_tile);
407 }
408}
409
418void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandomTrigger trigger, CargoType cargo_type)
419{
420 assert(st != nullptr);
421
422 /* Check the cached cargo trigger bitmask to see if we need
423 * to bother with any further processing.
424 * Note: cached_roadstop_cargo_triggers must be non-zero even for cargo-independent triggers. */
425 if (st->cached_roadstop_cargo_triggers == 0) return;
426 if (IsValidCargoType(cargo_type) && !HasBit(st->cached_roadstop_cargo_triggers, cargo_type)) return;
427
428 st->waiting_random_triggers.Set(trigger);
429
430 uint32_t whole_reseed = 0;
431
432 /* Bitmask of completely empty cargo types to be matched. */
433 CargoTypes empty_mask{};
434 if (trigger == StationRandomTrigger::CargoTaken) {
435 empty_mask = GetEmptyMask(Station::From(st));
436 }
437
438 StationRandomTriggers used_random_triggers;
439 auto process_tile = [&](TileIndex cur_tile) {
440 const RoadStopSpec *ss = GetRoadStopSpec(cur_tile);
441 if (ss == nullptr) return;
442
443 /* Cargo taken "will only be triggered if all of those
444 * cargo types have no more cargo waiting." */
445 if (trigger == StationRandomTrigger::CargoTaken) {
446 if ((ss->cargo_triggers & ~empty_mask) != 0) return;
447 }
448
449 if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) {
450 RoadStopResolverObject object(ss, st, cur_tile, INVALID_ROADTYPE, GetStationType(cur_tile), GetStationGfx(cur_tile));
451 object.SetWaitingRandomTriggers(st->waiting_random_triggers);
452
453 object.ResolveRerandomisation();
454
455 used_random_triggers.Set(object.GetUsedRandomTriggers());
456
457 uint32_t reseed = object.GetReseedSum();
458 if (reseed != 0) {
459 whole_reseed |= reseed;
460 reseed >>= 16;
461
462 /* Set individual tile random bits */
463 uint8_t random_bits = st->GetRoadStopRandomBits(cur_tile);
464 random_bits &= ~reseed;
465 random_bits |= Random() & reseed;
466 st->SetRoadStopRandomBits(cur_tile, random_bits);
467
468 MarkTileDirtyByTile(cur_tile);
469 }
470 }
471 };
473 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
474 process_tile(tile_data.tile);
475 }
476 } else {
477 process_tile(tile);
478 }
479
480 /* Update whole station random bits */
481 st->waiting_random_triggers.Reset(used_random_triggers);
482 if ((whole_reseed & 0xFFFF) != 0) {
483 st->random_bits &= ~whole_reseed;
484 st->random_bits |= Random() & whole_reseed;
485 }
486}
487
494bool GetIfNewStopsByType(RoadStopType rs, RoadType roadtype)
495{
496 for (const auto &cls : RoadStopClass::Classes()) {
497 /* Ignore the waypoint class. */
498 if (IsWaypointClass(cls)) continue;
499 /* Ignore the default class with only the default station. */
500 if (cls.Index() == ROADSTOP_CLASS_DFLT && cls.GetSpecCount() == 1) continue;
501 if (GetIfClassHasNewStopsByType(&cls, rs, roadtype)) return true;
502 }
503 return false;
504}
505
513bool GetIfClassHasNewStopsByType(const RoadStopClass *roadstopclass, RoadStopType rs, RoadType roadtype)
514{
515 for (const auto spec : roadstopclass->Specs()) {
516 if (GetIfStopIsForType(spec, rs, roadtype)) return true;
517 }
518 return false;
519}
520
528bool GetIfStopIsForType(const RoadStopSpec *roadstopspec, RoadStopType rs, RoadType roadtype)
529{
530 /* The roadstopspec is nullptr, must be the default station, always return true. */
531 if (roadstopspec == nullptr) return true;
532
533 if (roadstopspec->flags.Test(RoadStopSpecFlag::RoadOnly) && !RoadTypeIsRoad(roadtype)) return false;
534 if (roadstopspec->flags.Test(RoadStopSpecFlag::TramOnly) && !RoadTypeIsTram(roadtype)) return false;
535
536 if (roadstopspec->stop_type == ROADSTOPTYPE_ALL) return true;
537
538 switch (rs) {
540 if (roadstopspec->stop_type == ROADSTOPTYPE_PASSENGER) return true;
541 break;
542
544 if (roadstopspec->stop_type == ROADSTOPTYPE_FREIGHT) return true;
545 break;
546
547 default:
548 NOT_REACHED();
549 }
550 return false;
551}
552
553const RoadStopSpec *GetRoadStopSpec(TileIndex t)
554{
555 if (!IsCustomRoadStopSpecIndex(t)) return nullptr;
556
557 const BaseStation *st = BaseStation::GetByTile(t);
558 uint specindex = GetCustomRoadStopSpecIndex(t);
559 return specindex < st->roadstop_speclist.size() ? st->roadstop_speclist[specindex].spec : nullptr;
560}
561
562int AllocateSpecToRoadStop(const RoadStopSpec *statspec, BaseStation *st, bool exec)
563{
564 uint i;
565
566 if (statspec == nullptr || st == nullptr) return 0;
567
568 /* Try to find the same spec and return that one */
569 for (i = 1; i < st->roadstop_speclist.size() && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
570 if (st->roadstop_speclist[i].spec == statspec) return i;
571 }
572
573 /* Try to find an unused spec slot */
574 for (i = 1; i < st->roadstop_speclist.size() && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
575 if (st->roadstop_speclist[i].spec == nullptr && st->roadstop_speclist[i].grfid == 0) break;
576 }
577
578 if (i == NUM_ROADSTOPSPECS_PER_STATION) {
579 /* Full, give up */
580 return -1;
581 }
582
583 if (exec) {
584 if (i >= st->roadstop_speclist.size()) st->roadstop_speclist.resize(i + 1);
585 st->roadstop_speclist[i].spec = statspec;
586 st->roadstop_speclist[i].grfid = statspec->grf_prop.grfid;
587 st->roadstop_speclist[i].localidx = statspec->grf_prop.local_id;
588
589 RoadStopUpdateCachedTriggers(st);
590 }
591
592 return i;
593}
594
595void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex)
596{
597 /* specindex of 0 (default) is never freeable */
598 if (specindex == 0) return;
599
600 /* Check custom road stop tiles if the specindex is still in use */
601 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
602 if (GetCustomRoadStopSpecIndex(tile_data.tile) == specindex) {
603 return;
604 }
605 }
606
607 /* This specindex is no longer in use, so deallocate it */
608 st->roadstop_speclist[specindex].spec = nullptr;
609 st->roadstop_speclist[specindex].grfid = 0;
610 st->roadstop_speclist[specindex].localidx = 0;
611
612 /* If this was the highest spec index, reallocate */
613 if (specindex == st->roadstop_speclist.size() - 1) {
614 size_t num_specs;
615 for (num_specs = st->roadstop_speclist.size() - 1; num_specs > 0; num_specs--) {
616 if (st->roadstop_speclist[num_specs].grfid != 0) break;
617 }
618
619 if (num_specs > 0) {
620 st->roadstop_speclist.resize(num_specs + 1);
621 } else {
622 st->roadstop_speclist.clear();
625 return;
626 }
627 }
628
629 RoadStopUpdateCachedTriggers(st);
630}
631
636void RoadStopUpdateCachedTriggers(BaseStation *st)
637{
640
641 /* Combine animation trigger bitmask for all road stop specs
642 * of this station. */
643 for (const auto &sm : GetStationSpecList<RoadStopSpec>(st)) {
644 if (sm.spec == nullptr) continue;
645 st->cached_roadstop_anim_triggers.Set(sm.spec->animation.triggers);
646 st->cached_roadstop_cargo_triggers |= sm.spec->cargo_triggers;
647 }
648}
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
Struct containing information relating to NewGRF classes for stations and airports.
static std::span< NewGRFClass< Tspec, Tindex, Tmax > const > Classes()
Get read-only span of all classes of this type.
StringID name
Name of this class.
bool IsUIAvailable(uint index) const
Check whether the spec will be available to the user at some point in time.
void Insert(Tspec *spec)
Insert a spec into the class, and update its index.
std::span< Tspec *const > Specs() const
Get read-only span of specs of this class.
static NewGRFClass * Get(Tindex class_index)
Get a particular class.
static Tindex Allocate(uint32_t global_id)
Allocate a class with a given global class ID.
static void InsertDefaults()
Initialise the defaults.
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
The date of the first day of the original base year.
PaletteID GetCompanyPalette(CompanyID company)
Get the palette for recolouring with a company colour.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
Functions related to debugging.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:1024
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.
@ Random
Randomise borders.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:159
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:142
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.
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:230
@ ROTSG_OVERLAY
Optional: Images for overlaying track.
Definition road.h:52
@ ROTSG_ROADSTOP
Required: Bay stop surface.
Definition road.h:61
@ ROTSG_GROUND
Required: Main group of ground images.
Definition road.h:53
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.
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:91
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:170
static constexpr uint8_t SPRITE_WIDTH
number of bits for the sprite number
Definition sprites.h:1541
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.
StationRandomTrigger
Randomisation triggers for stations and roadstops.
@ NewCargo
Trigger station on new cargo arrival.
@ 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)
Animate a single tile.
static void ChangeAnimationFrame(CallbackID cb, const RoadStopSpec *spec, BaseStation *obj, TileIndex tile, uint32_t random_bits, uint32_t trigger, int extra_data=0)
Check a callback to determine what the next animation step is and execute that step.
Base class for all station-ish types.
virtual uint32_t GetNewGRFVariable(const struct ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const =0
Helper function to get a NewGRF variable that isn't implemented by the base class.
std::vector< SpecMapping< RoadStopSpec > > roadstop_speclist
List of road stop specs of this station.
StationFacilities facilities
The facilities that this station has.
Owner owner
The owner of this station.
StationAnimationTriggers cached_roadstop_anim_triggers
NOSAVE: Combined animation trigger bitmask for road stops, used to determine if trigger processing sh...
Town * town
The town this station is associated with.
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.
TimerGameCalendar::Date build_date
Date of construction.
StationRandomTriggers waiting_random_triggers
Waiting triggers (NewGRF), shared by all station parts/tiles, road stops, ... essentially useless and...
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:137
Tindex index
Index of this pool item.
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
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)
Helper for checking whether the given station is of this type.
static Station * From(BaseStation *st)
Converts a BaseStation to SpecializedStation with type checking.
Station data structure.
std::array< GoodsEntry, NUM_CARGO > goods
Goods at this station.
Tile information, used while rendering the tile.
Definition tile_cmd.h:29
TileIndex tile
Tile index.
Definition tile_cmd.h:33
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:52
TileIndex xy
town center tile
Definition town.h:53
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
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
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.