OpenTTD Source: src/newgrf_badge.cpp Source File

OpenTTD Source 15.0-RC2

newgrf_badge.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
10#include "stdafx.h"
11#include "newgrf.h"
12#include "newgrf_badge.h"
13#include "newgrf_badge_type.h"
14#include "newgrf_spritegroup.h"
15#include "stringfilter_type.h"
16#include "strings_func.h"
17#include "timer/timer_game_calendar.h"
18
19#include "table/strings.h"
20
21#include "safeguards.h"
22
24 static constexpr char BADGE_CLASS_SEPARATOR = '/';
25
27 class Badges {
28public:
29 std::vector<BadgeID> classes;
30 std::vector<Badge> specs;
31};
32
34 static Badges _badges = {};
35
40std::span<const Badge> GetBadges()
41{
42 return _badges.specs;
43}
44
49std::span<const BadgeID> GetClassBadges()
50{
51 return _badges.classes;
52}
53
59 static BadgeClassID GetOrCreateBadgeClass(BadgeID index)
60{
61 auto it = std::ranges::find(_badges.classes, index);
62 if (it == std::end(_badges.classes)) {
63 it = _badges.classes.emplace(it, index);
64 }
65
66 return static_cast<BadgeClassID>(std::distance(std::begin(_badges.classes), it));
67}
68
72 void ResetBadges()
73{
74 _badges = {};
75}
76
82 Badge &GetOrCreateBadge(std::string_view label)
83{
84 /* Check if the label exists. */
85 auto it = std::ranges::find(_badges.specs, label, &Badge::label);
86 if (it != std::end(_badges.specs)) return *it;
87
88 BadgeClassID class_index;
89
90 /* Extract class. */
91 auto sep = label.find_first_of(BADGE_CLASS_SEPARATOR);
92 if (sep != std::string_view::npos) {
93 /* There is a separator, find (and create if necessary) the class label. */
94 class_index = GetOrCreateBadge(label.substr(0, sep)).class_index;
95 it = std::end(_badges.specs);
96 }
97
98 BadgeID index = BadgeID(std::distance(std::begin(_badges.specs), it));
99 if (sep == std::string_view::npos) {
100 /* There is no separator, so this badge is a class badge. */
101 class_index = GetOrCreateBadgeClass(index);
102 }
103
104 it = _badges.specs.emplace(it, label, index, class_index);
105 return *it;
106}
107
113 Badge *GetBadge(BadgeID index)
114{
115 if (index.base() >= std::size(_badges.specs)) return nullptr;
116 return &_badges.specs[index.base()];
117}
118
124 Badge *GetBadgeByLabel(std::string_view label)
125{
126 auto it = std::ranges::find(_badges.specs, label, &Badge::label);
127 if (it == std::end(_badges.specs)) return nullptr;
128
129 return &*it;
130}
131
137 Badge *GetClassBadge(BadgeClassID class_index)
138{
139 if (class_index.base() >= std::size(_badges.classes)) return nullptr;
140 return GetBadge(_badges.classes[class_index.base()]);
141}
142
144 struct BadgeScopeResolver : public ScopeResolver {
145 const Badge &badge;
146 const std::optional<TimerGameCalendar::Date> introduction_date;
147
154 BadgeScopeResolver(ResolverObject &ro, const Badge &badge, const std::optional<TimerGameCalendar::Date> introduction_date)
155 : ScopeResolver(ro), badge(badge), introduction_date(introduction_date) { }
156
157 uint32_t GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const override;
158};
159
160/* virtual */ uint32_t BadgeScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
161{
162 switch (variable) {
163 case 0x40:
164 if (this->introduction_date.has_value()) return this->introduction_date->base();
165 return TimerGameCalendar::date.base();
166
167 default: break;
168 }
169
170 available = false;
171 return UINT_MAX;
172}
173
175 struct BadgeResolverObject : public ResolverObject {
176 BadgeScopeResolver self_scope;
177
178 BadgeResolverObject(const Badge &badge, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, CallbackID callback = CBID_NO_CALLBACK, uint32_t callback_param1 = 0, uint32_t callback_param2 = 0);
179
180 ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, uint8_t relative = 0) override
181 {
182 switch (scope) {
183 case VSG_SCOPE_SELF: return &this->self_scope;
184 default: return ResolverObject::GetScope(scope, relative);
185 }
186 }
187
188 GrfSpecFeature GetFeature() const override;
189 uint32_t GetDebugID() const override;
190};
191
192 GrfSpecFeature BadgeResolverObject::GetFeature() const
193{
194 return GSF_BADGES;
195}
196
197uint32_t BadgeResolverObject::GetDebugID() const
198{
199 return this->self_scope.badge.index.base();
200}
201
211BadgeResolverObject::BadgeResolverObject(const Badge &badge, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, CallbackID callback, uint32_t callback_param1, uint32_t callback_param2)
212 : ResolverObject(badge.grf_prop.grffile, callback, callback_param1, callback_param2), self_scope(*this, badge, introduction_date)
213{
214 assert(feature <= GSF_END);
215 this->root_spritegroup = this->self_scope.badge.grf_prop.GetFirstSpriteGroupOf({feature, GSF_DEFAULT});
216}
217
225uint32_t GetBadgeVariableResult(const GRFFile &grffile, std::span<const BadgeID> badges, uint32_t parameter)
226{
227 if (parameter >= std::size(grffile.badge_list)) return UINT_MAX;
228
229 BadgeID index = grffile.badge_list[parameter];
230 return std::ranges::find(badges, index) != std::end(badges);
231}
232
236 void MarkBadgeSeen(BadgeID index, GrfSpecFeature feature)
237{
238 Badge *b = GetBadge(index);
239 assert(b != nullptr);
240 b->features.Set(feature);
241}
242
250 void AppendCopyableBadgeList(std::vector<BadgeID> &dst, std::span<const BadgeID> src, GrfSpecFeature feature)
251{
252 for (const BadgeID &index : src) {
253 /* Is badge already present? */
254 if (std::ranges::find(dst, index) != std::end(dst)) continue;
255
256 /* Is badge copyable? */
257 Badge *badge = GetBadge(index);
258 if (badge == nullptr) continue;
259 if (!badge->flags.Test(BadgeFlag::Copy)) continue;
260
261 dst.push_back(index);
262 badge->features.Set(feature);
263 }
264}
265
267 void ApplyBadgeFeaturesToClassBadges()
268{
269 for (const Badge &badge : GetBadges()) {
270 Badge *class_badge = GetClassBadge(badge.class_index);
271 assert(class_badge != nullptr);
272 class_badge->features.Set(badge.features);
273 if (badge.name != STR_NULL) class_badge->flags.Set(BadgeFlag::HasText);
274 }
275}
276
285 PalSpriteID GetBadgeSprite(const Badge &badge, GrfSpecFeature feature, std::optional<TimerGameCalendar::Date> introduction_date, PaletteID remap)
286{
287 BadgeResolverObject object(badge, feature, introduction_date);
288 const auto *group = object.Resolve<ResultSpriteGroup>();
289 if (group == nullptr || group->num_sprites == 0) return {0, PAL_NONE};
290
291 PaletteID pal = badge.flags.Test(BadgeFlag::UseCompanyColour) ? remap : PAL_NONE;
292
293 return {group->sprite, pal};
294}
295
300UsedBadgeClasses::UsedBadgeClasses(GrfSpecFeature feature) : feature(feature)
301{
302 for (auto index : _badges.classes) {
303 Badge *class_badge = GetBadge(index);
304 if (!class_badge->features.Test(feature)) continue;
305
306 this->classes.push_back(class_badge->class_index);
307 }
308
309 std::ranges::sort(this->classes, [](const BadgeClassID &a, const BadgeClassID &b) { return GetClassBadge(a)->label < GetClassBadge(b)->label; });
310}
311
317BadgeTextFilter::BadgeTextFilter(StringFilter &filter, GrfSpecFeature feature)
318{
319 /* Do not filter if the filter text box is empty */
320 if (filter.IsEmpty()) return;
321
322 /* Pre-build list of badges that match by string. */
323 for (const auto &badge : GetBadges()) {
324 if (badge.name == STR_NULL) continue;
325 if (!badge.features.Test(feature)) continue;
326
327 filter.ResetState();
328 filter.AddLine(GetString(badge.name));
329 if (!filter.GetState()) continue;
330
331 this->badges.insert(badge.index);
332 }
333}
334
340 bool BadgeTextFilter::Filter(std::span<const BadgeID> badges) const
341{
342 return std::ranges::any_of(badges, [this](const BadgeID &badge) { return std::ranges::binary_search(this->badges, badge); });
343}
344
350 bool BadgeDropdownFilter::Filter(std::span<const BadgeID> badges) const
351{
352 if (this->badges.empty()) return true;
353
354 /* We want all filtered badges to match. */
355 return std::ranges::all_of(this->badges, [&badges](const auto &badge) { return std::ranges::find(badges, badge.second) != std::end(badges); });
356}
BadgeDropdownFilter::Filter
bool Filter(std::span< const BadgeID > badges) const
Test if the given badges matches the filtered badge list.
Definition newgrf_badge.cpp:350
BadgeTextFilter::Filter
bool Filter(std::span< const BadgeID > badges) const
Test if any of the given badges matches the filtered badge list.
Definition newgrf_badge.cpp:340
BadgeTextFilter::BadgeTextFilter
BadgeTextFilter(struct StringFilter &filter, GrfSpecFeature feature)
Construct a badge text filter.
Definition newgrf_badge.cpp:317
Badge
Definition newgrf_badge.h:20
Badge::class_index
BadgeClassID class_index
Index of class this badge belongs to.
Definition newgrf_badge.h:24
Badge::grf_prop
VariableGRFFileProps< GrfSpecFeature > grf_prop
Sprite information.
Definition newgrf_badge.h:28
Badge::label
std::string label
Label of badge.
Definition newgrf_badge.h:22
Badge::index
BadgeID index
Index assigned to badge.
Definition newgrf_badge.h:23
Badge::flags
BadgeFlags flags
Display flags.
Definition newgrf_badge.h:25
Badge::features
GrfSpecFeatures features
Bitmask of which features use this badge.
Definition newgrf_badge.h:27
Badges
Global state for badge definitions.
Definition newgrf_badge.cpp:27
Badges::classes
std::vector< BadgeID > classes
List of known badge classes.
Definition newgrf_badge.cpp:29
Badges::specs
std::vector< Badge > specs
List of known badges.
Definition newgrf_badge.cpp:30
BaseBitSet::Test
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Definition base_bitset_type.hpp:141
BaseBitSet::Set
constexpr Timpl & Set()
Set all bits.
Definition base_bitset_type.hpp:40
TimerGameCalendar::date
static Date date
Current date in days (day counter).
Definition timer_game_calendar.h:33
UsedBadgeClasses::classes
std::vector< BadgeClassID > classes
List of badge classes.
Definition newgrf_badge.h:51
PaletteID
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
newgrf.h
Base for the NewGRF implementation.
GrfSpecFeature
GrfSpecFeature
Definition newgrf.h:68
GSF_DEFAULT
@ GSF_DEFAULT
Unspecified feature, default badge.
Definition newgrf.h:93
_badges
static Badges _badges
Static instance of badge state.
Definition newgrf_badge.cpp:34
GetBadge
Badge * GetBadge(BadgeID index)
Get a badge if it exists.
Definition newgrf_badge.cpp:113
GetBadges
std::span< const Badge > GetBadges()
Get a read-only view of badges.
Definition newgrf_badge.cpp:40
ApplyBadgeFeaturesToClassBadges
void ApplyBadgeFeaturesToClassBadges()
Apply features from all badges to their badge classes.
Definition newgrf_badge.cpp:267
MarkBadgeSeen
void MarkBadgeSeen(BadgeID index, GrfSpecFeature feature)
Mark a badge a seen (used) by a feature.
Definition newgrf_badge.cpp:236
AppendCopyableBadgeList
void AppendCopyableBadgeList(std::vector< BadgeID > &dst, std::span< const BadgeID > src, GrfSpecFeature feature)
Append copyable badges from a list onto another.
Definition newgrf_badge.cpp:250
GetBadgeSprite
PalSpriteID GetBadgeSprite(const Badge &badge, GrfSpecFeature feature, std::optional< TimerGameCalendar::Date > introduction_date, PaletteID remap)
Get sprite for the given badge.
Definition newgrf_badge.cpp:285
GetClassBadges
std::span< const BadgeID > GetClassBadges()
Get a read-only view of class badge index.
Definition newgrf_badge.cpp:49
GetClassBadge
Badge * GetClassBadge(BadgeClassID class_index)
Get the badge for a badge class index.
Definition newgrf_badge.cpp:137
BADGE_CLASS_SEPARATOR
static constexpr char BADGE_CLASS_SEPARATOR
Separator to identify badge classes from a label.
Definition newgrf_badge.cpp:24
GetOrCreateBadgeClass
static BadgeClassID GetOrCreateBadgeClass(BadgeID index)
Assign a BadgeClassID to the given badge.
Definition newgrf_badge.cpp:59
GetOrCreateBadge
Badge & GetOrCreateBadge(std::string_view label)
Register a badge label and return its global index.
Definition newgrf_badge.cpp:82
GetBadgeVariableResult
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.
Definition newgrf_badge.cpp:225
GetBadgeByLabel
Badge * GetBadgeByLabel(std::string_view label)
Get a badge by label if it exists.
Definition newgrf_badge.cpp:124
ResetBadges
void ResetBadges()
Reset badges to the default state.
Definition newgrf_badge.cpp:72
newgrf_badge.h
Functions related to NewGRF badges.
GetBadge
Badge * GetBadge(BadgeID index)
Get a badge if it exists.
Definition newgrf_badge.cpp:113
GetBadges
std::span< const Badge > GetBadges()
Get a read-only view of badges.
Definition newgrf_badge.cpp:40
GetClassBadge
Badge * GetClassBadge(BadgeClassID class_index)
Get the badge for a badge class index.
Definition newgrf_badge.cpp:137
newgrf_badge_type.h
Types related to NewGRF badges.
BadgeFlag::UseCompanyColour
@ UseCompanyColour
Apply company colour palette to this badge.
BadgeFlag::Copy
@ Copy
Copy badge to related things.
BadgeFlag::HasText
@ HasText
Internal flag set if the badge has text.
CallbackID
CallbackID
List of implemented NewGRF callbacks.
Definition newgrf_callbacks.h:22
CBID_NO_CALLBACK
@ CBID_NO_CALLBACK
Set when using the callback resolve system, but not to resolve a callback.
Definition newgrf_callbacks.h:24
newgrf_spritegroup.h
Action 2 handling.
VarSpriteGroupScope
VarSpriteGroupScope
Definition newgrf_spritegroup.h:82
VSG_SCOPE_SELF
@ VSG_SCOPE_SELF
Resolved object itself.
Definition newgrf_spritegroup.h:85
safeguards.h
A number of safeguards to prevent using unsafe methods.
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
stringfilter_type.h
Searching and filtering using a stringterm.
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
strings_func.h
Functions related to OTTD's strings.
BadgeResolverObject
Resolver of badges.
Definition newgrf_badge.cpp:175
BadgeResolverObject::GetFeature
GrfSpecFeature GetFeature() const override
Get the feature number being resolved for.
Definition newgrf_badge.cpp:192
BadgeResolverObject::BadgeResolverObject
BadgeResolverObject(const Badge &badge, GrfSpecFeature feature, std::optional< TimerGameCalendar::Date > introduction_date, CallbackID callback=CBID_NO_CALLBACK, uint32_t callback_param1=0, uint32_t callback_param2=0)
Constructor of the badge resolver.
Definition newgrf_badge.cpp:211
BadgeResolverObject::GetScope
ScopeResolver * GetScope(VarSpriteGroupScope scope=VSG_SCOPE_SELF, uint8_t relative=0) override
Get a resolver for the scope.
Definition newgrf_badge.cpp:180
BadgeResolverObject::GetDebugID
uint32_t GetDebugID() const override
Get an identifier for the item being resolved.
Definition newgrf_badge.cpp:197
BadgeScopeResolver
Resolver for a badge scope.
Definition newgrf_badge.cpp:144
BadgeScopeResolver::BadgeScopeResolver
BadgeScopeResolver(ResolverObject &ro, const Badge &badge, const std::optional< TimerGameCalendar::Date > introduction_date)
Scope resolver of a badge.
Definition newgrf_badge.cpp:154
BadgeScopeResolver::GetVariable
uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const override
Get a variable value.
Definition newgrf_badge.cpp:160
GRFFile
Dynamic data of a loaded NewGRF.
Definition newgrf.h:114
GRFFile::badge_list
std::vector< BadgeID > badge_list
Badge translation table (local index -> global index)
Definition newgrf.h:138
PalSpriteID
Combination of a palette sprite and a 'real' sprite.
Definition gfx_type.h:22
ResolverObject
Interface for SpriteGroup-s to access the gamestate.
Definition newgrf_spritegroup.h:288
ResolverObject::callback_param2
uint32_t callback_param2
Second parameter (var 18) of the callback.
Definition newgrf_spritegroup.h:342
ResolverObject::callback
CallbackID callback
Callback being resolved.
Definition newgrf_spritegroup.h:340
ResolverObject::callback_param1
uint32_t callback_param1
First parameter (var 10) of the callback.
Definition newgrf_spritegroup.h:341
ResolverObject::root_spritegroup
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
Definition newgrf_spritegroup.h:353
ResolverObject::GetScope
virtual ScopeResolver * GetScope(VarSpriteGroupScope scope=VSG_SCOPE_SELF, uint8_t relative=0)
Get a resolver for the scope.
Definition newgrf_spritegroup.cpp:133
ResultSpriteGroup
Definition newgrf_spritegroup.h:217
ScopeResolver
Interface to query and set values specific to a single VarSpriteGroupScope (action 2 scope).
Definition newgrf_spritegroup.h:269
ScopeResolver::ro
ResolverObject & ro
Surrounding resolver object.
Definition newgrf_spritegroup.h:270
StringFilter
String filter and state.
Definition stringfilter_type.h:30
StringFilter::IsEmpty
bool IsEmpty() const
Check whether any filter words were entered.
Definition stringfilter_type.h:57
StringFilter::ResetState
void ResetState()
Reset the matching state to process a new item.
Definition stringfilter.cpp:80
StringFilter::GetState
bool GetState() const
Get the matching state of the current item.
Definition stringfilter_type.h:67
StrongType::Typedef< uint16_t, struct BadgeClassIDTag, StrongType::Compare >
VariableGRFFileProps::GetFirstSpriteGroupOf
const struct SpriteGroup * GetFirstSpriteGroupOf(std::initializer_list< Tkey > indices) const
Get the first existing SpriteGroup from a list of options.
Definition newgrf_commons.h:427
timer_game_calendar.h
Definition of the game-calendar-timer.