OpenTTD Source 20250529-master-g10c159a79f
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 this->root_spritegroup = roadstopspec->grf_prop.GetSpriteGroup(ctype);
231 } else if (Station::IsExpected(st)) {
232 const Station *station = Station::From(st);
233 /* Pick the first cargo that we have waiting */
234 for (const auto &[cargo, spritegroup] : roadstopspec->grf_prop.spritegroups) {
235 if (cargo < NUM_CARGO && station->goods[cargo].HasData() && station->goods[cargo].GetData().cargo.TotalCount() > 0) {
236 ctype = cargo;
237 this->root_spritegroup = spritegroup;
238 break;
239 }
240 }
241
242 if (this->root_spritegroup == nullptr) {
244 this->root_spritegroup = roadstopspec->grf_prop.GetSpriteGroup(ctype);
245 }
246 }
247
248 if (this->root_spritegroup == nullptr) {
250 this->root_spritegroup = roadstopspec->grf_prop.GetSpriteGroup(ctype);
251 }
252
253 /* Remember the cargo type we've picked */
254 this->roadstop_scope.cargo_type = ctype;
255}
256
257TownScopeResolver *RoadStopResolverObject::GetTown()
258{
259 if (!this->town_scope.has_value()) {
260 Town *t;
261 if (this->roadstop_scope.st != nullptr) {
262 t = this->roadstop_scope.st->town;
263 } else {
264 t = ClosestTownFromTile(this->roadstop_scope.tile, UINT_MAX);
265 }
266 if (t == nullptr) return nullptr;
267 this->town_scope.emplace(*this, t, this->roadstop_scope.st == nullptr);
268 }
269 return &*this->town_scope;
270}
271
272uint16_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)
273{
274 RoadStopResolverObject object(roadstopspec, st, tile, roadtype, type, view, callback, param1, param2);
275 return object.ResolveCallback(regs100);
276}
277
287void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec, StationType type, int view)
288{
289 assert(roadtype != INVALID_ROADTYPE);
290 assert(spec != nullptr);
291
292 const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype);
293 RoadStopResolverObject object(spec, nullptr, INVALID_TILE, roadtype, type, view);
294 const auto *group = object.Resolve<TileLayoutSpriteGroup>();
295 if (group == nullptr) return;
296 auto processor = group->ProcessRegisters(object, nullptr);
297 auto dts = processor.GetLayout();
298
300
301 SpriteID image = dts.ground.sprite;
302 PaletteID pal = dts.ground.pal;
303
304 RoadStopDrawModes draw_mode;
305 if (spec->flags.Test(RoadStopSpecFlag::DrawModeRegister)) {
306 draw_mode = static_cast<RoadStopDrawMode>(object.GetRegister(0x100));
307 } else {
308 draw_mode = spec->draw_mode;
309 }
310
311 if (type == StationType::RoadWaypoint) {
312 DrawSprite(SPR_ROAD_PAVED_STRAIGHT_X, PAL_NONE, x, y);
313 if (draw_mode.Test(RoadStopDrawMode::WaypGround) && GB(image, 0, SPRITE_WIDTH) != 0) {
314 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
315 }
316 } else if (GB(image, 0, SPRITE_WIDTH) != 0) {
317 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
318 }
319
320 if (view >= 4) {
321 /* Drive-through stop */
322 uint sprite_offset = 5 - view;
323
324 /* Road underlay takes precedence over tram */
325 if (type == StationType::RoadWaypoint || draw_mode.Test(RoadStopDrawMode::Overlay)) {
326 if (rti->UsesOverlay()) {
328 DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
329
331 if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
332 } else if (RoadTypeIsTram(roadtype)) {
333 DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
334 }
335 }
336 } else {
337 /* Bay stop */
338 if (draw_mode.Test(RoadStopDrawMode::Road) && rti->UsesOverlay()) {
340 DrawSprite(ground + view, PAL_NONE, x, y);
341 }
342 }
343
344 DrawCommonTileSeqInGUI(x, y, &dts, 0, 0, palette, true);
345}
346
347std::optional<SpriteLayoutProcessor> GetRoadStopLayout(TileInfo *ti, const RoadStopSpec *spec, BaseStation *st, StationType type, int view, std::span<int32_t> regs100)
348{
349 RoadStopResolverObject object(spec, st, ti->tile, INVALID_ROADTYPE, type, view);
350 auto group = object.Resolve<TileLayoutSpriteGroup>();
351 if (group == nullptr) return std::nullopt;
352 for (uint i = 0; i < regs100.size(); ++i) {
353 regs100[i] = object.GetRegister(0x100 + i);
354 }
355 return group->ProcessRegisters(object, nullptr);
356}
357
359uint16_t GetAnimRoadStopCallback(CallbackID callback, uint32_t param1, uint32_t param2, const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, int)
360{
361 return GetRoadStopCallback(callback, param1, param2, roadstopspec, st, tile, INVALID_ROADTYPE, GetStationType(tile), GetStationGfx(tile));
362}
363
365 static uint8_t Get(BaseStation *st, TileIndex tile) { return st->GetRoadStopAnimationFrame(tile); }
366 static bool Set(BaseStation *st, TileIndex tile, uint8_t frame) { return st->SetRoadStopAnimationFrame(tile, frame); }
367};
368
377
378void AnimateRoadStopTile(TileIndex tile)
379{
380 const RoadStopSpec *ss = GetRoadStopSpec(tile);
381 if (ss == nullptr) return;
382
384}
385
386void TriggerRoadStopAnimation(BaseStation *st, TileIndex trigger_tile, StationAnimationTrigger trigger, CargoType cargo_type)
387{
388 assert(st != nullptr);
389
390 /* Check the cached animation trigger bitmask to see if we need
391 * to bother with any further processing. */
392 if (!st->cached_roadstop_anim_triggers.Test(trigger)) return;
393
394 uint16_t random_bits = Random();
395 auto process_tile = [&](TileIndex cur_tile) {
396 const RoadStopSpec *ss = GetRoadStopSpec(cur_tile);
397 if (ss != nullptr && ss->animation.triggers.Test(trigger)) {
398 uint8_t var18_extra = 0;
399 if (IsValidCargoType(cargo_type)) {
400 var18_extra |= ss->grf_prop.grffile->cargo_map[cargo_type] << 8;
401 }
402 RoadStopAnimationBase::ChangeAnimationFrame(CBID_STATION_ANIMATION_TRIGGER, ss, st, cur_tile, (random_bits << 16) | GB(Random(), 0, 16), to_underlying(trigger) | var18_extra);
403 }
404 };
405
407 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
408 process_tile(tile_data.tile);
409 }
410 } else {
411 process_tile(trigger_tile);
412 }
413}
414
423void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandomTrigger trigger, CargoType cargo_type)
424{
425 assert(st != nullptr);
426
427 /* Check the cached cargo trigger bitmask to see if we need
428 * to bother with any further processing.
429 * Note: cached_roadstop_cargo_triggers must be non-zero even for cargo-independent triggers. */
430 if (st->cached_roadstop_cargo_triggers == 0) return;
431 if (IsValidCargoType(cargo_type) && !HasBit(st->cached_roadstop_cargo_triggers, cargo_type)) return;
432
433 st->waiting_random_triggers.Set(trigger);
434
435 uint32_t whole_reseed = 0;
436
437 /* Bitmask of completely empty cargo types to be matched. */
438 CargoTypes empty_mask{};
439 if (trigger == StationRandomTrigger::CargoTaken) {
440 empty_mask = GetEmptyMask(Station::From(st));
441 }
442
443 StationRandomTriggers used_random_triggers;
444 auto process_tile = [&](TileIndex cur_tile) {
445 const RoadStopSpec *ss = GetRoadStopSpec(cur_tile);
446 if (ss == nullptr) return;
447
448 /* Cargo taken "will only be triggered if all of those
449 * cargo types have no more cargo waiting." */
450 if (trigger == StationRandomTrigger::CargoTaken) {
451 if ((ss->cargo_triggers & ~empty_mask) != 0) return;
452 }
453
454 if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) {
455 RoadStopResolverObject object(ss, st, cur_tile, INVALID_ROADTYPE, GetStationType(cur_tile), GetStationGfx(cur_tile));
456 object.SetWaitingRandomTriggers(st->waiting_random_triggers);
457
458 object.ResolveRerandomisation();
459
460 used_random_triggers.Set(object.GetUsedRandomTriggers());
461
462 uint32_t reseed = object.GetReseedSum();
463 if (reseed != 0) {
464 whole_reseed |= reseed;
465 reseed >>= 16;
466
467 /* Set individual tile random bits */
468 uint8_t random_bits = st->GetRoadStopRandomBits(cur_tile);
469 random_bits &= ~reseed;
470 random_bits |= Random() & reseed;
471 st->SetRoadStopRandomBits(cur_tile, random_bits);
472
473 MarkTileDirtyByTile(cur_tile);
474 }
475 }
476 };
478 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
479 process_tile(tile_data.tile);
480 }
481 } else {
482 process_tile(tile);
483 }
484
485 /* Update whole station random bits */
486 st->waiting_random_triggers.Reset(used_random_triggers);
487 if ((whole_reseed & 0xFFFF) != 0) {
488 st->random_bits &= ~whole_reseed;
489 st->random_bits |= Random() & whole_reseed;
490 }
491}
492
499bool GetIfNewStopsByType(RoadStopType rs, RoadType roadtype)
500{
501 for (const auto &cls : RoadStopClass::Classes()) {
502 /* Ignore the waypoint class. */
503 if (IsWaypointClass(cls)) continue;
504 /* Ignore the default class with only the default station. */
505 if (cls.Index() == ROADSTOP_CLASS_DFLT && cls.GetSpecCount() == 1) continue;
506 if (GetIfClassHasNewStopsByType(&cls, rs, roadtype)) return true;
507 }
508 return false;
509}
510
518bool GetIfClassHasNewStopsByType(const RoadStopClass *roadstopclass, RoadStopType rs, RoadType roadtype)
519{
520 for (const auto spec : roadstopclass->Specs()) {
521 if (GetIfStopIsForType(spec, rs, roadtype)) return true;
522 }
523 return false;
524}
525
533bool GetIfStopIsForType(const RoadStopSpec *roadstopspec, RoadStopType rs, RoadType roadtype)
534{
535 /* The roadstopspec is nullptr, must be the default station, always return true. */
536 if (roadstopspec == nullptr) return true;
537
538 if (roadstopspec->flags.Test(RoadStopSpecFlag::RoadOnly) && !RoadTypeIsRoad(roadtype)) return false;
539 if (roadstopspec->flags.Test(RoadStopSpecFlag::TramOnly) && !RoadTypeIsTram(roadtype)) return false;
540
541 if (roadstopspec->stop_type == ROADSTOPTYPE_ALL) return true;
542
543 switch (rs) {
545 if (roadstopspec->stop_type == ROADSTOPTYPE_PASSENGER) return true;
546 break;
547
549 if (roadstopspec->stop_type == ROADSTOPTYPE_FREIGHT) return true;
550 break;
551
552 default:
553 NOT_REACHED();
554 }
555 return false;
556}
557
558const RoadStopSpec *GetRoadStopSpec(TileIndex t)
559{
560 if (!IsCustomRoadStopSpecIndex(t)) return nullptr;
561
562 const BaseStation *st = BaseStation::GetByTile(t);
563 uint specindex = GetCustomRoadStopSpecIndex(t);
564 return specindex < st->roadstop_speclist.size() ? st->roadstop_speclist[specindex].spec : nullptr;
565}
566
567int AllocateSpecToRoadStop(const RoadStopSpec *statspec, BaseStation *st, bool exec)
568{
569 uint i;
570
571 if (statspec == nullptr || st == nullptr) return 0;
572
573 /* Try to find the same spec and return that one */
574 for (i = 1; i < st->roadstop_speclist.size() && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
575 if (st->roadstop_speclist[i].spec == statspec) return i;
576 }
577
578 /* Try to find an unused spec slot */
579 for (i = 1; i < st->roadstop_speclist.size() && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
580 if (st->roadstop_speclist[i].spec == nullptr && st->roadstop_speclist[i].grfid == 0) break;
581 }
582
583 if (i == NUM_ROADSTOPSPECS_PER_STATION) {
584 /* Full, give up */
585 return -1;
586 }
587
588 if (exec) {
589 if (i >= st->roadstop_speclist.size()) st->roadstop_speclist.resize(i + 1);
590 st->roadstop_speclist[i].spec = statspec;
591 st->roadstop_speclist[i].grfid = statspec->grf_prop.grfid;
592 st->roadstop_speclist[i].localidx = statspec->grf_prop.local_id;
593
594 RoadStopUpdateCachedTriggers(st);
595 }
596
597 return i;
598}
599
600void DeallocateSpecFromRoadStop(BaseStation *st, uint8_t specindex)
601{
602 /* specindex of 0 (default) is never freeable */
603 if (specindex == 0) return;
604
605 /* Check custom road stop tiles if the specindex is still in use */
606 for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
607 if (GetCustomRoadStopSpecIndex(tile_data.tile) == specindex) {
608 return;
609 }
610 }
611
612 /* This specindex is no longer in use, so deallocate it */
613 st->roadstop_speclist[specindex].spec = nullptr;
614 st->roadstop_speclist[specindex].grfid = 0;
615 st->roadstop_speclist[specindex].localidx = 0;
616
617 /* If this was the highest spec index, reallocate */
618 if (specindex == st->roadstop_speclist.size() - 1) {
619 size_t num_specs;
620 for (num_specs = st->roadstop_speclist.size() - 1; num_specs > 0; num_specs--) {
621 if (st->roadstop_speclist[num_specs].grfid != 0) break;
622 }
623
624 if (num_specs > 0) {
625 st->roadstop_speclist.resize(num_specs + 1);
626 } else {
627 st->roadstop_speclist.clear();
630 return;
631 }
632 }
633
634 RoadStopUpdateCachedTriggers(st);
635}
636
641void RoadStopUpdateCachedTriggers(BaseStation *st)
642{
645
646 /* Combine animation trigger bitmask for all road stop specs
647 * of this station. */
648 for (const auto &sm : GetStationSpecList<RoadStopSpec>(st)) {
649 if (sm.spec == nullptr) continue;
650 st->cached_roadstop_anim_triggers.Set(sm.spec->animation.triggers);
651 st->cached_roadstop_cargo_triggers |= sm.spec->cargo_triggers;
652 }
653}
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.
RoadStopDrawMode
Different draw modes to disallow rendering of some parts of the stop or road.
@ 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
const SpriteGroup * GetSpriteGroup(Tkey index) const
Get the SpriteGroup at the specified index.
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.