tiger_lib/
scopes.rs

1//! The core [`Scopes`] type which tracks our knowledge about the types of in-game values.
2
3use std::fmt::{Display, Formatter};
4
5use bitflags::bitflags;
6
7use crate::context::ScopeContext;
8use crate::everything::Everything;
9use crate::game::Game;
10use crate::helpers::{camel_case_to_separated_words, display_choices, snake_case_to_camel_case};
11use crate::item::Item;
12use crate::lowercase::Lowercase;
13use crate::report::{ErrorKey, err};
14use crate::token::Token;
15
16/// vic3 and ck3 and eu5 need more than 64 bits, but the others don't.
17#[cfg(any(feature = "vic3", feature = "ck3", feature = "eu5"))]
18type ScopesBits = u128;
19#[cfg(not(any(feature = "vic3", feature = "ck3", feature = "eu5")))]
20type ScopesBits = u64;
21
22bitflags! {
23    /// This type represents our knowledge about the set of scope types that a script value can
24    /// have. In most cases it's narrowed down to a single scope type, but not always.
25    ///
26    /// The available scope types depend on the game.
27    /// They are listed in `event_scopes.log` from the game data dumps.
28    // LAST UPDATED CK3 VERSION 1.16.0
29    // LAST UPDATED VIC3 VERSION 1.8.1
30    // LAST UPDATED IR VERSION 2.0.4
31    //
32    // Each scope type gets one bitflag. In order to keep the bit count down, scope types from
33    // the different games have overlapping bitflags. Therefore, scope types from different games
34    // should be kept carefully separated.
35    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
36    #[rustfmt::skip] // having the cfg and the flag on one line is much more readable
37    pub struct Scopes: ScopesBits {
38        // Generic scope types
39        const None = 1<<0;
40        const Value = 1<<1;
41        const Bool = 1<<2;
42        const Flag = 1<<3;
43
44        // Scope types shared by multiple games
45
46        #[cfg(any(feature = "vic3", feature = "imperator", feature = "eu5"))]
47        const Color = 1<<4;
48        #[cfg(any(feature = "vic3", feature = "imperator", feature = "eu5", feature = "hoi4"))]
49        const Country = 1<<5;
50        const Character = 1<<6;
51        #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5", feature = "imperator"))]
52        const Culture = 1<<7;
53        #[cfg(any(feature = "ck3", feature = "vic3", feature = "imperator", feature = "eu5"))]
54        const Province = 1<<8;
55        #[cfg(any(feature = "vic3", feature = "imperator", feature = "eu5"))]
56        const Pop = 1<<9;
57        #[cfg(any(feature = "vic3", feature = "imperator"))]
58        const Party = 1<<10;
59        #[cfg(feature = "eu5")]
60        const PopType = 1<<10; // overlap with Party to save a bit
61        #[cfg(any(feature = "ck3", feature = "vic3", feature = "imperator", feature = "eu5"))]
62        const Religion = 1<<11;
63        #[cfg(any(feature = "vic3", feature = "imperator", feature = "hoi4"))]
64        const State = 1<<12;
65        #[cfg(feature = "eu5")]
66        const Trait = 1<<12; // overlap with State to save a bit
67        #[cfg(any(feature = "ck3", feature = "vic3", feature = "imperator", feature = "eu5"))]
68        const War = 1<<13;
69        #[cfg(any(feature = "vic3", feature = "hoi4"))]
70        const StrategicRegion = 1<<14;
71        #[cfg(feature = "eu5")]
72        const Invalid = 1<<14; // overlap with StrategicRegion to save a bit
73        #[cfg(any(feature = "ck3", feature = "vic3"))]
74        const Decision = 1<<15;
75        #[cfg(feature = "eu5")]
76        const Date = 1<<15; // overlap with Decision to save a bit
77
78        // Scope types for CK3
79        #[cfg(feature = "ck3")] const Accolade = 1<<16;
80        #[cfg(feature = "ck3")] const AccoladeType = 1<<17;
81        #[cfg(feature = "ck3")] const Activity = 1<<18;
82        #[cfg(feature = "ck3")] const ActivityType = 1<<19;
83        #[cfg(feature = "ck3")] const Army = 1<<20;
84        #[cfg(feature = "ck3")] const Artifact = 1<<21;
85        #[cfg(feature = "ck3")] const CasusBelli = 1<<22;
86        #[cfg(feature = "ck3")] const CharacterMemory = 1<<23;
87        #[cfg(feature = "ck3")] const Combat = 1<<24;
88        #[cfg(feature = "ck3")] const CombatSide = 1<<25;
89        #[cfg(feature = "ck3")] const CouncilTask = 1<<26;
90        #[cfg(feature = "ck3")] const CulturePillar = 1<<27;
91        #[cfg(feature = "ck3")] const CultureTradition = 1<<28;
92        #[cfg(feature = "ck3")] const Doctrine = 1<<29;
93        #[cfg(feature = "ck3")] const Dynasty = 1<<30;
94        #[cfg(feature = "ck3")] const DynastyHouse = 1<<31;
95        #[cfg(feature = "ck3")] const Faction = 1<<32;
96        #[cfg(feature = "ck3")] const Faith = 1<<33;
97        #[cfg(feature = "ck3")] const GovernmentType = 1<<34;
98        #[cfg(feature = "ck3")] const GreatHolyWar = 1<<35;
99        #[cfg(feature = "ck3")] const HolyOrder = 1<<36;
100        #[cfg(feature = "ck3")] const Inspiration = 1<<37;
101        #[cfg(feature = "ck3")] const LandedTitle = 1<<38;
102        #[cfg(feature = "ck3")] const MercenaryCompany = 1<<39;
103        #[cfg(feature = "ck3")] const Scheme = 1<<40;
104        #[cfg(feature = "ck3")] const Secret = 1<<41;
105        #[cfg(feature = "ck3")] const StoryCycle = 1<<42;
106        #[cfg(feature = "ck3")] const Struggle = 1<<43;
107        #[cfg(feature = "ck3")] const TitleAndVassalChange = 1<<44;
108        #[cfg(feature = "ck3")] const Trait = 1<<45;
109        #[cfg(feature = "ck3")] const TravelPlan = 1<<46;
110        #[cfg(feature = "ck3")] const VassalContract = 1<<47;
111        #[cfg(feature = "ck3")] const VassalObligationLevel = 1<<48;
112        // CK3 1.11
113        #[cfg(feature = "ck3")] const HoldingType = 1<<49;
114        #[cfg(feature = "ck3")] const TaxSlot = 1<<50;
115        // CK3 1.12
116        #[cfg(feature = "ck3")] const EpidemicType = 1<<51;
117        #[cfg(feature = "ck3")] const Epidemic = 1<<52;
118        #[cfg(feature = "ck3")] const LegendType = 1<<53;
119        #[cfg(feature = "ck3")] const Legend = 1<<54;
120        #[cfg(feature = "ck3")] const GeographicalRegion = 1<<55;
121        // CK3 1.13
122        #[cfg(feature = "ck3")] const Domicile = 1<<56;
123        #[cfg(feature = "ck3")] const AgentSlot = 1<<57;
124        #[cfg(feature = "ck3")] const TaskContract = 1<<58;
125        #[cfg(feature = "ck3")] const TaskContractType = 1<<59;
126        #[cfg(feature = "ck3")] const Regiment = 1<<60;
127        #[cfg(feature = "ck3")] const CasusBelliType = 1<<61;
128        // CK3 1.15
129        #[cfg(feature = "ck3")] const CourtPosition = 1<<62;
130        #[cfg(feature = "ck3")] const CourtPositionType = 1<<63;
131        // CK3 1.16
132        #[cfg(feature = "ck3")] const Situation = 1<<64;
133        #[cfg(feature = "ck3")] const SituationParticipantGroup = 1<<65;
134        #[cfg(feature = "ck3")] const SituationSubRegion = 1<<66;
135        #[cfg(feature = "ck3")] const Confederation = 1<<67;
136        // CK3 1.18
137        #[cfg(feature = "ck3")] const HouseAspiration = 1<<68;
138        #[cfg(feature = "ck3")] const HouseRelation = 1<<69;
139        #[cfg(feature = "ck3")] const HouseRelationType = 1<<70;
140        #[cfg(feature = "ck3")] const HouseRelationLevel = 1<<71;
141        #[cfg(feature = "ck3")] const ConfederationType = 1<<72;
142        #[cfg(feature = "ck3")] const GreatProject = 1<<73;
143        #[cfg(feature = "ck3")] const ProjectContribution = 1<<74;
144        #[cfg(feature = "ck3")] const CultureInnovation = 1<<75;
145        #[cfg(feature = "ck3")] const GreatProjectType = 1<<76;
146
147        #[cfg(feature = "vic3")] const Battle = 1<<16;
148        #[cfg(feature = "vic3")] const BattleSide = 1<<17;
149        #[cfg(feature = "vic3")] const Building = 1<<18;
150        #[cfg(feature = "vic3")] const BuildingType = 1<<19;
151        #[cfg(feature = "vic3")] const CanalType = 1<<20;
152        #[cfg(feature = "vic3")] const CivilWar = 1<<21;
153        #[cfg(feature = "vic3")] const CulturalCommunity = 1<<22;
154        #[cfg(feature = "vic3")] const NewCombatUnit = 1<<23;
155        #[cfg(feature = "vic3")] const CommanderOrderType = 1<<24;
156        #[cfg(feature = "vic3")] const CountryCreation = 1<<25;
157        #[cfg(feature = "vic3")] const CountryDefinition = 1<<26;
158        #[cfg(feature = "vic3")] const CountryFormation = 1<<27;
159        #[cfg(feature = "vic3")] const Decree = 1<<28;
160        #[cfg(feature = "vic3")] const DiplomaticAction = 1<<29;
161        #[cfg(feature = "vic3")] const DiplomaticPact = 1<<30;
162        #[cfg(feature = "vic3")] const DiplomaticPlay = 1<<31;
163        #[cfg(feature = "vic3")] const DiplomaticRelations = 1<<32;
164        #[cfg(feature = "vic3")] const Front = 1<<33;
165        #[cfg(feature = "vic3")] const Goods = 1<<34;
166        #[cfg(feature = "vic3")] const Hq = 1<<35;
167        #[cfg(feature = "vic3")] const Ideology = 1<<36;
168        #[cfg(feature = "vic3")] const Institution = 1<<37;
169        #[cfg(feature = "vic3")] const InstitutionType = 1<<38;
170        #[cfg(feature = "vic3")] const InterestMarker = 1<<39;
171        #[cfg(feature = "vic3")] const InterestGroup = 1<<40;
172        #[cfg(feature = "vic3")] const InterestGroupTrait = 1<<41;
173        #[cfg(feature = "vic3")] const InterestGroupType = 1<<42;
174        #[cfg(feature = "vic3")] const JournalEntry = 1<<43;
175        #[cfg(feature = "vic3")] const Law = 1<<44;
176        #[cfg(feature = "vic3")] const LawType = 1<<45;
177        #[cfg(feature = "vic3")] const Market = 1<<46;
178        #[cfg(feature = "vic3")] const MarketGoods = 1<<47;
179        #[cfg(feature = "vic3")] const Objective = 1<<48;
180        #[cfg(feature = "vic3")] const PoliticalMovement = 1<<49;
181        #[cfg(feature = "vic3")] const PopType = 1<<50;
182        #[cfg(feature = "vic3")] const ShippingLanes = 1<<51;
183        #[cfg(feature = "vic3")] const StateRegion = 1<<52;
184        #[cfg(feature = "vic3")] const StateTrait = 1<<53;
185        #[cfg(feature = "vic3")] const Technology = 1<<54;
186        #[cfg(feature = "vic3")] const TechnologyStatus = 1<<55;
187        #[cfg(feature = "vic3")] const Theater = 1<<56;
188        #[cfg(feature = "vic3")] const CombatUnitType = 1<<57;
189        #[cfg(feature = "vic3")] const MilitaryFormation = 1<<58;
190        #[cfg(feature = "vic3")] const Sway = 1<<59;
191        #[cfg(feature = "vic3")] const StateGoods = 1<<60;
192        #[cfg(feature = "vic3")] const DiplomaticDemand = 1<<61;
193        #[cfg(feature = "vic3")] const Company = 1<<62;
194        #[cfg(feature = "vic3")] const CompanyType = 1<<63;
195        #[cfg(feature = "vic3")] const TravelNode = 1<<64;
196        #[cfg(feature = "vic3")] const TravelNodeDefinition = 1<<65;
197        #[cfg(feature = "vic3")] const TravelConnection = 1<<66;
198        #[cfg(feature = "vic3")] const TravelConnectionDefinition = 1<<67;
199        #[cfg(feature = "vic3")] const Invasion = 1<<68;
200        #[cfg(feature = "vic3")] const MobilizationOption = 1<<69;
201        #[cfg(feature = "vic3")] const PowerBlocPrincipleGroup = 1<<70;
202        #[cfg(feature = "vic3")] const DiplomaticPlayType = 1<<71;
203        #[cfg(feature = "vic3")] const DiplomaticCatalyst = 1<<72;
204        #[cfg(feature = "vic3")] const DiplomaticCatalystType = 1<<73;
205        #[cfg(feature = "vic3")] const DiplomaticCatalystCategory = 1<<74;
206        #[cfg(feature = "vic3")] const PoliticalLobby = 1<<75;
207        #[cfg(feature = "vic3")] const PoliticalLobbyType = 1<<76;
208        #[cfg(feature = "vic3")] const PoliticalLobbyAppeasement = 1<<77;
209        #[cfg(feature = "vic3")] const PowerBloc = 1<<78;
210        #[cfg(feature = "vic3")] const PowerBlocIdentity = 1<<79;
211        #[cfg(feature = "vic3")] const PowerBlocPrinciple = 1<<80;
212        #[cfg(feature = "vic3")] const HarvestCondition = 1<<81;
213        #[cfg(feature = "vic3")] const PoliticalMovementType = 1<<82;
214        #[cfg(feature = "vic3")] const HarvestConditionType = 1<<83;
215        #[cfg(feature = "vic3")] const TreatyArticle = 1<<84;
216        #[cfg(feature = "vic3")] const TreatyOptions = 1<<85;
217        #[cfg(feature = "vic3")] const TreatyArticleOptions = 1<<86;
218        #[cfg(feature = "vic3")] const Treaty = 1<<87;
219        #[cfg(feature = "vic3")] const BuildingGroup = 1<<88;
220        #[cfg(feature = "vic3")] const Amendment = 1<<89;
221        #[cfg(feature = "vic3")] const AmendmentType = 1<<90;
222        #[cfg(feature = "vic3")] const GeographicRegion = 1<<91;
223        #[cfg(feature = "vic3")] const WarGoal = 1<<92;
224        #[cfg(feature = "vic3")] const WarGoalType = 1<<93;
225
226        #[cfg(feature = "imperator")] const Area = 1<<16;
227        #[cfg(feature = "imperator")] const CountryCulture = 1<<17;
228        #[cfg(feature = "imperator")] const CultureGroup = 1<<18;
229        #[cfg(feature = "imperator")] const Deity = 1<<19;
230        #[cfg(feature = "imperator")] const Family = 1<<20;
231        #[cfg(feature = "imperator")] const Governorship = 1<<21;
232        #[cfg(feature = "imperator")] const GreatWork = 1<<22;
233        #[cfg(feature = "imperator")] const Job = 1<<23;
234        #[cfg(feature = "imperator")] const Legion = 1<<24;
235        #[cfg(feature = "imperator")] const LevyTemplate = 1<<25;
236        #[cfg(feature = "imperator")] const Region = 1<<26;
237        #[cfg(feature = "imperator")] const Siege = 1<<27;
238        #[cfg(feature = "imperator")] const SubUnit = 1<<28;
239        #[cfg(feature = "imperator")] const Treasure = 1<<29;
240        #[cfg(feature = "imperator")] const Unit = 1<<30;
241
242        #[cfg(feature = "eu5")] const Location = 1<<16;
243        #[cfg(feature = "eu5")] const Unit = 1<<17;
244        #[cfg(feature = "eu5")] const SubUnit = 1<<18;
245        #[cfg(feature = "eu5")] const Dynasty = 1<<19;
246        #[cfg(feature = "eu5")] const Combat = 1<<20;
247        #[cfg(feature = "eu5")] const CombatSide = 1<<21;
248        #[cfg(feature = "eu5")] const Siege = 1<<22;
249        #[cfg(feature = "eu5")] const ColonialCharter = 1<<23;
250        #[cfg(feature = "eu5")] const Market = 1<<24;
251        #[cfg(feature = "eu5")] const ProvinceDefinition = 1<<25;
252        #[cfg(feature = "eu5")] const Area = 1<<26;
253        #[cfg(feature = "eu5")] const Region = 1<<27;
254        #[cfg(feature = "eu5")] const SubContinent = 1<<28;
255        #[cfg(feature = "eu5")] const Continent = 1<<29;
256        #[cfg(feature = "eu5")] const Group = 1<<30;
257        #[cfg(feature = "eu5")] const Language = 1<<31;
258        #[cfg(feature = "eu5")] const Rebels = 1<<32;
259        #[cfg(feature = "eu5")] const Trade = 1<<33;
260        #[cfg(feature = "eu5")] const ReligiousSchool = 1<<34;
261        #[cfg(feature = "eu5")] const Goods = 1<<35;
262        #[cfg(feature = "eu5")] const Demand = 1<<36;
263        #[cfg(feature = "eu5")] const Privateer = 1<<37;
264        #[cfg(feature = "eu5")] const Exploration = 1<<38;
265        #[cfg(feature = "eu5")] const Mercenary = 1<<39;
266        #[cfg(feature = "eu5")] const WorkOfArt = 1<<40;
267        #[cfg(feature = "eu5")] const Government = 1<<41;
268        #[cfg(feature = "eu5")] const InternationalOrganization = 1<<42;
269        #[cfg(feature = "eu5")] const HolySite = 1<<43;
270        #[cfg(feature = "eu5")] const Institution = 1<<44;
271        #[cfg(feature = "eu5")] const Loan = 1<<45;
272        #[cfg(feature = "eu5")] const Building = 1<<46;
273        #[cfg(feature = "eu5")] const Law = 1<<47;
274        #[cfg(feature = "eu5")] const Policy = 1<<48;
275        #[cfg(feature = "eu5")] const Price = 1<<49;
276        #[cfg(feature = "eu5")] const Situation = 1<<50;
277        #[cfg(feature = "eu5")] const BuildingType = 1<<51;
278        #[cfg(feature = "eu5")] const Disaster = 1<<52;
279        #[cfg(feature = "eu5")] const ReligiousAspect = 1<<53;
280        #[cfg(feature = "eu5")] const EstatePrivilege = 1<<54;
281        #[cfg(feature = "eu5")] const CabinetAction = 1<<55;
282        #[cfg(feature = "eu5")] const GovernmentReform = 1<<56;
283        #[cfg(feature = "eu5")] const Cabinet = 1<<57;
284        #[cfg(feature = "eu5")] const ProductionMethod = 1<<58;
285        #[cfg(feature = "eu5")] const GraphicalCulture = 1<<59;
286        #[cfg(feature = "eu5")] const DiseaseOutbreak = 1<<60;
287        #[cfg(feature = "eu5")] const Disease = 1<<61;
288        #[cfg(feature = "eu5")] const ParliamentIssue = 1<<62;
289        #[cfg(feature = "eu5")] const ParliamentType = 1<<63;
290        #[cfg(feature = "eu5")] const Resolution = 1<<64;
291        #[cfg(feature = "eu5")] const God = 1<<65;
292        #[cfg(feature = "eu5")] const Avatar = 1<<66;
293        #[cfg(feature = "eu5")] const ReligiousFaction = 1<<67;
294        #[cfg(feature = "eu5")] const SubjectType = 1<<68;
295        #[cfg(feature = "eu5")] const Cardinal = 1<<69;
296        #[cfg(feature = "eu5")] const ActiveResolution = 1<<70;
297        #[cfg(feature = "eu5")] const Estate = 1<<71;
298        #[cfg(feature = "eu5")] const AudioCulture = 1<<72;
299        #[cfg(feature = "eu5")] const AdvanceType = 1<<73;
300        #[cfg(feature = "eu5")] const CharacterInteraction = 1<<74;
301        #[cfg(feature = "eu5")] const CountryInteraction = 1<<75;
302        #[cfg(feature = "eu5")] const GenericAction = 1<<76;
303        #[cfg(feature = "eu5")] const UnitType = 1<<77;
304        #[cfg(feature = "eu5")] const LevySetup = 1<<78;
305        #[cfg(feature = "eu5")] const ParliamentAgenda = 1<<79;
306        #[cfg(feature = "eu5")] const CasusBelli = 1<<80;
307        #[cfg(feature = "eu5")] const RelationType = 1<<81;
308        #[cfg(feature = "eu5")] const DisasterType = 1<<82;
309        #[cfg(feature = "eu5")] const SubUnitCategory = 1<<83;
310        #[cfg(feature = "eu5")] const PeaceTreaty = 1<<84;
311        #[cfg(feature = "eu5")] const ArtistType = 1<<85;
312        #[cfg(feature = "eu5")] const WorkOfArtType = 1<<86;
313        #[cfg(feature = "eu5")] const ChildEducation = 1<<87;
314        #[cfg(feature = "eu5")] const Mission = 1<<88;
315        #[cfg(feature = "eu5")] const MissionTask = 1<<89;
316        #[cfg(feature = "eu5")] const RecruitmentMethod = 1<<90;
317        #[cfg(feature = "eu5")] const RegencyType = 1<<91;
318        #[cfg(feature = "eu5")] const UnitAbility = 1<<92;
319        #[cfg(feature = "eu5")] const SocietalValueType = 1<<93;
320        #[cfg(feature = "eu5")] const RoadType = 1<<94;
321        #[cfg(feature = "eu5")] const LanguageFamily = 1<<95;
322        #[cfg(feature = "eu5")] const CultureGroup = 1<<96;
323        #[cfg(feature = "eu5")] const HeirSelection = 1<<97;
324        #[cfg(feature = "eu5")] const EstateType = 1<<98;
325        #[cfg(feature = "eu5")] const Dialect = 1<<99;
326        #[cfg(feature = "eu5")] const Ethnicity = 1<<100;
327        #[cfg(feature = "eu5")] const InternationalOrganizationType = 1<<101;
328        #[cfg(feature = "eu5")] const Payment = 1<<102;
329        #[cfg(feature = "eu5")] const SpecialStatus = 1<<103;
330        #[cfg(feature = "eu5")] const LandOwnershipRule = 1<<104;
331        #[cfg(feature = "eu5")] const WeatherSystem = 1<<105;
332        #[cfg(feature = "eu5")] const FormableCountry = 1<<106;
333        #[cfg(feature = "eu5")] const Hegemony = 1<<107;
334        #[cfg(feature = "eu5")] const HolySiteDefinition = 1<<108;
335        #[cfg(feature = "eu5")] const HolySiteType = 1<<109;
336        #[cfg(feature = "eu5")] const CountryRank = 1<<110;
337        #[cfg(feature = "eu5")] const LocationRank = 1<<111;
338        #[cfg(feature = "eu5")] const ReligiousFocus = 1<<112;
339        #[cfg(feature = "eu5")] const ReligiousFigure = 1<<113;
340        #[cfg(feature = "eu5")] const Climate = 1<<114;
341        #[cfg(feature = "eu5")] const Vegetation = 1<<115;
342        #[cfg(feature = "eu5")] const Topography = 1<<116;
343        #[cfg(feature = "eu5")] const Age = 1<<117;
344        #[cfg(feature = "eu5")] const EmploymentSystem = 1<<118;
345        #[cfg(feature = "eu5")] const MilitaryStance = 1<<119;
346        #[cfg(feature = "eu5")] const UnitTemplate = 1<<120;
347        #[cfg(feature = "eu5")] const UnitFormationPreference = 1<<121;
348        #[cfg(feature = "eu5")] const ScriptableHintDefinition = 1<<122;
349        #[cfg(feature = "eu5")] const ScriptedGeography = 1<<123;
350        #[cfg(feature = "eu5")] const ReligionGroup = 1<<124;
351
352        #[cfg(feature = "hoi4")] const Ace = 1<<16;
353        #[cfg(feature = "hoi4")] const Combatant = 1<<17;
354        #[cfg(feature = "hoi4")] const Division = 1<<18;
355        #[cfg(feature = "hoi4")] const IndustrialOrg = 1<<19;
356        #[cfg(feature = "hoi4")] const Operation = 1<<20;
357        #[cfg(feature = "hoi4")] const PurchaseContract = 1<<21;
358        #[cfg(feature = "hoi4")] const RaidInstance = 1<<22;
359        #[cfg(feature = "hoi4")] const SpecialProject = 1<<23;
360        // These two "combined" ones represent the odd scopes created for events.
361        #[cfg(feature = "hoi4")] const CombinedCountryAndState = 1<<24;
362        #[cfg(feature = "hoi4")] const CombinedCountryAndCharacter = 1<<25;
363    }
364}
365
366// These have to be expressed a bit awkwardly because the binary operators are not `const`.
367// TODO: Scopes::all() returns a too-large set if multiple features are enabled.
368impl Scopes {
369    pub const fn non_primitive() -> Scopes {
370        Scopes::all()
371            .difference(Scopes::None.union(Scopes::Value).union(Scopes::Bool).union(Scopes::Flag))
372    }
373
374    pub const fn primitive() -> Scopes {
375        Scopes::Value.union(Scopes::Bool).union(Scopes::Flag)
376    }
377
378    pub const fn all_but_none() -> Scopes {
379        Scopes::all().difference(Scopes::None)
380    }
381
382    /// Read a scope type in string form and return it as a [`Scopes`] value.
383    pub fn from_snake_case(s: &str) -> Option<Scopes> {
384        #[cfg(feature = "ck3")]
385        if Game::is_ck3() {
386            // Deal with some exceptions to the general pattern
387            match s {
388                "ghw" => return Some(Scopes::GreatHolyWar),
389                "story" => return Some(Scopes::StoryCycle),
390                "great_holy_war" | "story_cycle" => return None,
391                _ => (),
392            }
393        }
394
395        Scopes::from_name(&snake_case_to_camel_case(s))
396    }
397
398    /// Similar to `from_snake_case`, but allows multiple scopes separated by `|`
399    /// Returns None if any of the conversions fail.
400    pub fn from_snake_case_multi(s: &str) -> Option<Scopes> {
401        let mut scopes = Scopes::empty();
402        for part in s.split('|') {
403            if let Some(scope) = Scopes::from_snake_case(part) {
404                scopes |= scope;
405            } else {
406                return None;
407            }
408        }
409        // If `scopes` is still empty then probably `s` was empty.
410        // Remember that `Scopes::empty()` is different from a bitfield containing `Scopes::None`.
411        if scopes == Scopes::empty() {
412            return None;
413        }
414        Some(scopes)
415    }
416}
417
418impl Display for Scopes {
419    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
420        if *self == Scopes::all() {
421            write!(f, "any scope")
422        } else if *self == Scopes::primitive() {
423            write!(f, "any primitive scope")
424        } else if *self == Scopes::non_primitive() {
425            write!(f, "non-primitive scope")
426        } else if *self == Scopes::all_but_none() {
427            write!(f, "any except none scope")
428        } else {
429            let mut vec = Vec::new();
430            for (name, _) in self.iter_names() {
431                vec.push(camel_case_to_separated_words(name));
432            }
433            let vec: Vec<&str> = vec.iter().map(String::as_ref).collect();
434            display_choices(f, &vec, "or")
435        }
436    }
437}
438
439/// A description of the constraints on a value with a prefix such as `var:` or `list_size:`
440#[derive(Copy, Clone, Debug, Eq, PartialEq)]
441pub enum ArgumentValue {
442    /// The value must be an expression that resolves to a scope object of the given type.
443    #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5"))]
444    Scope(Scopes),
445    /// The value must be the name of an item of the given item type.
446    Item(Item),
447    /// The value can be either a Scope or an Item
448    #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5"))]
449    ScopeOrItem(Scopes, Item),
450    /// The value can be a trait name or `trait|track`.
451    #[cfg(feature = "ck3")]
452    TraitTrack,
453    /// The value must be the name of a modif
454    #[cfg(any(feature = "vic3", feature = "imperator", feature = "eu5"))]
455    Modif,
456    /// The value must be a single word
457    #[cfg(any(feature = "vic3", feature = "ck3", feature = "eu5"))]
458    Identifier(&'static str),
459    /// The value consists of multiple arguments separated by `|`
460    #[cfg(feature = "eu5")]
461    Multiple(&'static [ArgumentValue]),
462    /// The value can be anything
463    UncheckedValue,
464    /// This trigger no longer exists. Arguments are version and explanation
465    #[cfg(feature = "ck3")]
466    Removed(&'static str, &'static str),
467}
468
469/// Look up an "event link", which is a script token that looks up something related
470/// to a scope value and returns another scope value.
471///
472/// `name` is the token. `inscopes` is the known scope context of this token.
473/// `inscopes` is only used for some special-case event links whose output scope type
474/// depends on their input scope type.
475///
476/// Returns a pair of `Scopes`. The first is the scope types this token can accept as input,
477/// and the second is the scope types it may return.
478#[allow(unused_variables)] // inscopes is only used for vic3
479pub fn scope_to_scope(name: &Token, inscopes: Scopes) -> Option<(Scopes, Scopes)> {
480    let scope_to_scope = match Game::game() {
481        #[cfg(feature = "ck3")]
482        Game::Ck3 => crate::ck3::tables::targets::scope_to_scope,
483        #[cfg(feature = "vic3")]
484        Game::Vic3 => crate::vic3::tables::targets::scope_to_scope,
485        #[cfg(feature = "imperator")]
486        Game::Imperator => crate::imperator::tables::targets::scope_to_scope,
487        #[cfg(feature = "eu5")]
488        Game::Eu5 => crate::eu5::tables::targets::scope_to_scope,
489        #[cfg(feature = "hoi4")]
490        Game::Hoi4 => crate::hoi4::tables::targets::scope_to_scope,
491    };
492    let scope_to_scope_removed = match Game::game() {
493        #[cfg(feature = "ck3")]
494        Game::Ck3 => crate::ck3::tables::targets::scope_to_scope_removed,
495        #[cfg(feature = "vic3")]
496        Game::Vic3 => crate::vic3::tables::targets::scope_to_scope_removed,
497        #[cfg(feature = "imperator")]
498        Game::Imperator => crate::imperator::tables::targets::scope_to_scope_removed,
499        #[cfg(feature = "eu5")]
500        Game::Eu5 => crate::eu5::tables::targets::scope_to_scope_removed,
501        #[cfg(feature = "hoi4")]
502        Game::Hoi4 => crate::hoi4::tables::targets::scope_to_scope_removed,
503    };
504
505    let name_lc = name.as_str().to_ascii_lowercase();
506    #[allow(unused_assignments)] // `from` only used for vic3
507    if let scopes @ Some((from, _)) = scope_to_scope(&name_lc) {
508        #[cfg(feature = "vic3")]
509        if Game::is_vic3() && name_lc == "type" {
510            // Special case for "type" because it goes from specific scope types to specific
511            // other scope types.
512            let mut outscopes = Scopes::empty();
513            if inscopes.contains(Scopes::Building) {
514                outscopes |= Scopes::BuildingType;
515            }
516            if inscopes.contains(Scopes::Company) {
517                outscopes |= Scopes::CompanyType;
518            }
519            if inscopes.contains(Scopes::DiplomaticPlay) {
520                outscopes |= Scopes::DiplomaticPlayType;
521            }
522            if inscopes.contains(Scopes::DiplomaticCatalyst) {
523                outscopes |= Scopes::DiplomaticCatalystType;
524            }
525            if inscopes.contains(Scopes::PoliticalLobby) {
526                outscopes |= Scopes::PoliticalLobbyType;
527            }
528            if inscopes.contains(Scopes::Institution) {
529                outscopes |= Scopes::InstitutionType;
530            }
531            if inscopes.contains(Scopes::InterestGroup) {
532                outscopes |= Scopes::InterestGroupType;
533            }
534            if inscopes.contains(Scopes::Law) {
535                outscopes |= Scopes::LawType;
536            }
537            if inscopes.contains(Scopes::PoliticalMovement) {
538                outscopes |= Scopes::PoliticalMovementType;
539            }
540            if inscopes.contains(Scopes::HarvestCondition) {
541                outscopes |= Scopes::HarvestConditionType;
542            }
543            if !outscopes.is_empty() {
544                return Some((from, outscopes));
545            }
546        }
547        scopes
548    } else if let Some((version, explanation)) = scope_to_scope_removed(&name_lc) {
549        let msg = format!("`{name}` was removed in {version}");
550        err(ErrorKey::Removed).strong().msg(msg).info(explanation).loc(name).push();
551        Some((Scopes::all(), Scopes::all_but_none()))
552    } else {
553        None
554    }
555}
556
557/// Look up a prefixed token that is used to look up items in the game database.
558///
559/// For example, `character:alexander_the_great` to fetch that character as a scope value.
560///
561/// Some prefixes have an input scope, and they look up something related to the input scope value.
562///
563/// Returns a pair of `Scopes` and the type of argument it accepts.
564/// The first `Scopes` is the scope types this token can accept as input, and the second one is
565/// the scope types it may return. The first will be `Scopes::None` if it needs no input.
566pub fn scope_prefix(prefix: &Token) -> Option<(Scopes, Scopes, ArgumentValue)> {
567    let scope_prefix = match Game::game() {
568        #[cfg(feature = "ck3")]
569        Game::Ck3 => crate::ck3::tables::targets::scope_prefix,
570        #[cfg(feature = "vic3")]
571        Game::Vic3 => crate::vic3::tables::targets::scope_prefix,
572        #[cfg(feature = "imperator")]
573        Game::Imperator => crate::imperator::tables::targets::scope_prefix,
574        #[cfg(feature = "eu5")]
575        Game::Eu5 => crate::eu5::tables::targets::scope_prefix,
576        #[cfg(feature = "hoi4")]
577        Game::Hoi4 => crate::hoi4::tables::targets::scope_prefix,
578    };
579    let prefix_lc = prefix.as_str().to_ascii_lowercase();
580    scope_prefix(&prefix_lc)
581}
582
583/// Look up a token that's an invalid target, and see if it might be missing a prefix.
584/// Return the prefix if one was found.
585///
586/// `scopes` should be a singular `Scopes` flag.
587///
588/// Example: if the token is "irish" and `scopes` is `Scopes::Culture` then return
589/// `Some("culture")` to indicate that the token should have been "culture:irish".
590pub fn needs_prefix(arg: &str, data: &Everything, scopes: Scopes) -> Option<&'static str> {
591    match Game::game() {
592        #[cfg(feature = "ck3")]
593        Game::Ck3 => crate::ck3::scopes::needs_prefix(arg, data, scopes),
594        #[cfg(feature = "vic3")]
595        Game::Vic3 => crate::vic3::scopes::needs_prefix(arg, data, scopes),
596        #[cfg(feature = "imperator")]
597        Game::Imperator => crate::imperator::scopes::needs_prefix(arg, data, scopes),
598        #[cfg(feature = "eu5")]
599        Game::Eu5 => crate::eu5::scopes::needs_prefix(arg, data, scopes),
600        #[cfg(feature = "hoi4")]
601        Game::Hoi4 => crate::hoi4::scopes::needs_prefix(arg, data, scopes),
602    }
603}
604
605/// Look up an iterator, which is a script element that executes its block multiple times, once for
606/// each applicable scope value. Iterators may be builtin (the usual case) or may be scripted lists.
607///
608/// `name` is the name of the iterator, without its `any_`, `every_`, `random_` or `ordered_` prefix.
609/// `sc` is a [`ScopeContext`], only used for validating scripted lists.
610///
611/// Returns a pair of `Scopes`. The first is the scope types this token can accept as input,
612/// and the second is the scope types it may return.
613/// The first will be `Scopes::None` if it needs no input.
614pub fn scope_iterator(
615    name: &Token,
616    data: &Everything,
617    sc: &mut ScopeContext,
618) -> Option<(Scopes, Scopes)> {
619    let scope_iterator = match Game::game() {
620        #[cfg(feature = "ck3")]
621        Game::Ck3 => crate::ck3::tables::iterators::iterator,
622        #[cfg(feature = "vic3")]
623        Game::Vic3 => crate::vic3::tables::iterators::iterator,
624        #[cfg(feature = "imperator")]
625        Game::Imperator => crate::imperator::tables::iterators::iterator,
626        #[cfg(feature = "eu5")]
627        Game::Eu5 => crate::eu5::tables::iterators::iterator,
628        #[cfg(feature = "hoi4")]
629        Game::Hoi4 => crate::hoi4::tables::iterators::iterator,
630    };
631    let scope_iterator_removed = match Game::game() {
632        #[cfg(feature = "ck3")]
633        Game::Ck3 => crate::ck3::tables::iterators::iterator_removed,
634        #[cfg(feature = "vic3")]
635        Game::Vic3 => crate::vic3::tables::iterators::iterator_removed,
636        #[cfg(feature = "imperator")]
637        Game::Imperator => crate::imperator::tables::iterators::iterator_removed,
638        #[cfg(feature = "eu5")]
639        Game::Eu5 => crate::eu5::tables::iterators::iterator_removed,
640        #[cfg(feature = "hoi4")]
641        Game::Hoi4 => crate::hoi4::tables::iterators::iterator_removed,
642    };
643
644    let name_lc = Lowercase::new(name.as_str());
645    if let scopes @ Some(_) = scope_iterator(&name_lc, name, data) {
646        return scopes;
647    }
648    if let Some((version, explanation)) = scope_iterator_removed(name_lc.as_str()) {
649        let msg = format!("`{name}` iterators were removed in {version}");
650        err(ErrorKey::Removed).strong().msg(msg).info(explanation).loc(name).push();
651        return Some((Scopes::all(), Scopes::all()));
652    }
653    #[cfg(feature = "jomini")]
654    if Game::is_jomini() && data.scripted_lists.exists(name.as_str()) {
655        data.scripted_lists.validate_call(name, data, sc);
656        return data
657            .scripted_lists
658            .base(name)
659            .and_then(|base| scope_iterator(&Lowercase::new(base.as_str()), base, data));
660    }
661    #[cfg(feature = "hoi4")]
662    let _ = &data; // mark parameter used
663    #[cfg(feature = "hoi4")]
664    let _ = &sc; // mark parameter used
665    None
666}