Skip to main content

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 CharacterRole = 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        #[cfg(feature = "vic3")] const InterestTierType = 1<<94;
226        #[cfg(feature = "vic3")] const NavalBattle = 1<<95;
227        #[cfg(feature = "vic3")] const NavalMission = 1<<96;
228        #[cfg(feature = "vic3")] const NavalMissionType = 1<<97;
229        #[cfg(feature = "vic3")] const Ship = 1<<98;
230        #[cfg(feature = "vic3")] const ShipGroup = 1<<99;
231        #[cfg(feature = "vic3")] const ShipModificationType = 1<<100;
232        #[cfg(feature = "vic3")] const ShipType = 1<<101;
233        #[cfg(feature = "vic3")] const Strait = 1<<102;
234        #[cfg(feature = "vic3")] const StraitType = 1<<103;
235
236        #[cfg(feature = "imperator")] const Area = 1<<16;
237        #[cfg(feature = "imperator")] const CountryCulture = 1<<17;
238        #[cfg(feature = "imperator")] const CultureGroup = 1<<18;
239        #[cfg(feature = "imperator")] const Deity = 1<<19;
240        #[cfg(feature = "imperator")] const Family = 1<<20;
241        #[cfg(feature = "imperator")] const Governorship = 1<<21;
242        #[cfg(feature = "imperator")] const GreatWork = 1<<22;
243        #[cfg(feature = "imperator")] const Job = 1<<23;
244        #[cfg(feature = "imperator")] const Legion = 1<<24;
245        #[cfg(feature = "imperator")] const LevyTemplate = 1<<25;
246        #[cfg(feature = "imperator")] const Region = 1<<26;
247        #[cfg(feature = "imperator")] const Siege = 1<<27;
248        #[cfg(feature = "imperator")] const SubUnit = 1<<28;
249        #[cfg(feature = "imperator")] const Treasure = 1<<29;
250        #[cfg(feature = "imperator")] const Unit = 1<<30;
251
252        #[cfg(feature = "eu5")] const Location = 1<<16;
253        #[cfg(feature = "eu5")] const Unit = 1<<17;
254        #[cfg(feature = "eu5")] const SubUnit = 1<<18;
255        #[cfg(feature = "eu5")] const Dynasty = 1<<19;
256        #[cfg(feature = "eu5")] const Combat = 1<<20;
257        #[cfg(feature = "eu5")] const CombatSide = 1<<21;
258        #[cfg(feature = "eu5")] const Siege = 1<<22;
259        #[cfg(feature = "eu5")] const ColonialCharter = 1<<23;
260        #[cfg(feature = "eu5")] const Market = 1<<24;
261        #[cfg(feature = "eu5")] const ProvinceDefinition = 1<<25;
262        #[cfg(feature = "eu5")] const Area = 1<<26;
263        #[cfg(feature = "eu5")] const Region = 1<<27;
264        #[cfg(feature = "eu5")] const SubContinent = 1<<28;
265        #[cfg(feature = "eu5")] const Continent = 1<<29;
266        #[cfg(feature = "eu5")] const Group = 1<<30;
267        #[cfg(feature = "eu5")] const Language = 1<<31;
268        #[cfg(feature = "eu5")] const Rebels = 1<<32;
269        #[cfg(feature = "eu5")] const Trade = 1<<33;
270        #[cfg(feature = "eu5")] const ReligiousSchool = 1<<34;
271        #[cfg(feature = "eu5")] const Goods = 1<<35;
272        #[cfg(feature = "eu5")] const Demand = 1<<36;
273        #[cfg(feature = "eu5")] const Privateer = 1<<37;
274        #[cfg(feature = "eu5")] const Exploration = 1<<38;
275        #[cfg(feature = "eu5")] const Mercenary = 1<<39;
276        #[cfg(feature = "eu5")] const WorkOfArt = 1<<40;
277        #[cfg(feature = "eu5")] const Government = 1<<41;
278        #[cfg(feature = "eu5")] const InternationalOrganization = 1<<42;
279        #[cfg(feature = "eu5")] const HolySite = 1<<43;
280        #[cfg(feature = "eu5")] const Institution = 1<<44;
281        #[cfg(feature = "eu5")] const Loan = 1<<45;
282        #[cfg(feature = "eu5")] const Building = 1<<46;
283        #[cfg(feature = "eu5")] const Law = 1<<47;
284        #[cfg(feature = "eu5")] const Policy = 1<<48;
285        #[cfg(feature = "eu5")] const Price = 1<<49;
286        #[cfg(feature = "eu5")] const Situation = 1<<50;
287        #[cfg(feature = "eu5")] const BuildingType = 1<<51;
288        #[cfg(feature = "eu5")] const Disaster = 1<<52;
289        #[cfg(feature = "eu5")] const ReligiousAspect = 1<<53;
290        #[cfg(feature = "eu5")] const EstatePrivilege = 1<<54;
291        #[cfg(feature = "eu5")] const CabinetAction = 1<<55;
292        #[cfg(feature = "eu5")] const GovernmentReform = 1<<56;
293        #[cfg(feature = "eu5")] const Cabinet = 1<<57;
294        #[cfg(feature = "eu5")] const ProductionMethod = 1<<58;
295        #[cfg(feature = "eu5")] const GraphicalCulture = 1<<59;
296        #[cfg(feature = "eu5")] const DiseaseOutbreak = 1<<60;
297        #[cfg(feature = "eu5")] const Disease = 1<<61;
298        #[cfg(feature = "eu5")] const ParliamentIssue = 1<<62;
299        #[cfg(feature = "eu5")] const ParliamentType = 1<<63;
300        #[cfg(feature = "eu5")] const Resolution = 1<<64;
301        #[cfg(feature = "eu5")] const God = 1<<65;
302        #[cfg(feature = "eu5")] const Avatar = 1<<66;
303        #[cfg(feature = "eu5")] const ReligiousFaction = 1<<67;
304        #[cfg(feature = "eu5")] const SubjectType = 1<<68;
305        #[cfg(feature = "eu5")] const Cardinal = 1<<69;
306        #[cfg(feature = "eu5")] const ActiveResolution = 1<<70;
307        #[cfg(feature = "eu5")] const Estate = 1<<71;
308        #[cfg(feature = "eu5")] const AudioCulture = 1<<72;
309        #[cfg(feature = "eu5")] const AdvanceType = 1<<73;
310        #[cfg(feature = "eu5")] const CharacterInteraction = 1<<74;
311        #[cfg(feature = "eu5")] const CountryInteraction = 1<<75;
312        #[cfg(feature = "eu5")] const GenericAction = 1<<76;
313        #[cfg(feature = "eu5")] const UnitType = 1<<77;
314        #[cfg(feature = "eu5")] const LevySetup = 1<<78;
315        #[cfg(feature = "eu5")] const ParliamentAgenda = 1<<79;
316        #[cfg(feature = "eu5")] const CasusBelli = 1<<80;
317        #[cfg(feature = "eu5")] const RelationType = 1<<81;
318        #[cfg(feature = "eu5")] const DisasterType = 1<<82;
319        #[cfg(feature = "eu5")] const SubUnitCategory = 1<<83;
320        #[cfg(feature = "eu5")] const PeaceTreaty = 1<<84;
321        #[cfg(feature = "eu5")] const ArtistType = 1<<85;
322        #[cfg(feature = "eu5")] const WorkOfArtType = 1<<86;
323        #[cfg(feature = "eu5")] const ChildEducation = 1<<87;
324        #[cfg(feature = "eu5")] const Mission = 1<<88;
325        #[cfg(feature = "eu5")] const MissionTask = 1<<89;
326        #[cfg(feature = "eu5")] const RecruitmentMethod = 1<<90;
327        #[cfg(feature = "eu5")] const RegencyType = 1<<91;
328        #[cfg(feature = "eu5")] const UnitAbility = 1<<92;
329        #[cfg(feature = "eu5")] const SocietalValueType = 1<<93;
330        #[cfg(feature = "eu5")] const RoadType = 1<<94;
331        #[cfg(feature = "eu5")] const LanguageFamily = 1<<95;
332        #[cfg(feature = "eu5")] const CultureGroup = 1<<96;
333        #[cfg(feature = "eu5")] const HeirSelection = 1<<97;
334        #[cfg(feature = "eu5")] const EstateType = 1<<98;
335        #[cfg(feature = "eu5")] const Dialect = 1<<99;
336        #[cfg(feature = "eu5")] const Ethnicity = 1<<100;
337        #[cfg(feature = "eu5")] const InternationalOrganizationType = 1<<101;
338        #[cfg(feature = "eu5")] const Payment = 1<<102;
339        #[cfg(feature = "eu5")] const SpecialStatus = 1<<103;
340        #[cfg(feature = "eu5")] const LandOwnershipRule = 1<<104;
341        #[cfg(feature = "eu5")] const WeatherSystem = 1<<105;
342        #[cfg(feature = "eu5")] const FormableCountry = 1<<106;
343        #[cfg(feature = "eu5")] const Hegemony = 1<<107;
344        #[cfg(feature = "eu5")] const HolySiteDefinition = 1<<108;
345        #[cfg(feature = "eu5")] const HolySiteType = 1<<109;
346        #[cfg(feature = "eu5")] const CountryRank = 1<<110;
347        #[cfg(feature = "eu5")] const LocationRank = 1<<111;
348        #[cfg(feature = "eu5")] const ReligiousFocus = 1<<112;
349        #[cfg(feature = "eu5")] const ReligiousFigure = 1<<113;
350        #[cfg(feature = "eu5")] const Climate = 1<<114;
351        #[cfg(feature = "eu5")] const Vegetation = 1<<115;
352        #[cfg(feature = "eu5")] const Topography = 1<<116;
353        #[cfg(feature = "eu5")] const Age = 1<<117;
354        #[cfg(feature = "eu5")] const EmploymentSystem = 1<<118;
355        #[cfg(feature = "eu5")] const MilitaryStance = 1<<119;
356        #[cfg(feature = "eu5")] const UnitTemplate = 1<<120;
357        #[cfg(feature = "eu5")] const UnitFormationPreference = 1<<121;
358        #[cfg(feature = "eu5")] const ScriptableHintDefinition = 1<<122;
359        #[cfg(feature = "eu5")] const ScriptedGeography = 1<<123;
360        #[cfg(feature = "eu5")] const ReligionGroup = 1<<124;
361
362        #[cfg(feature = "hoi4")] const Ace = 1<<16;
363        #[cfg(feature = "hoi4")] const Combatant = 1<<17;
364        #[cfg(feature = "hoi4")] const Division = 1<<18;
365        #[cfg(feature = "hoi4")] const IndustrialOrg = 1<<19;
366        #[cfg(feature = "hoi4")] const Operation = 1<<20;
367        #[cfg(feature = "hoi4")] const PurchaseContract = 1<<21;
368        #[cfg(feature = "hoi4")] const RaidInstance = 1<<22;
369        #[cfg(feature = "hoi4")] const SpecialProject = 1<<23;
370        // These two "combined" ones represent the odd scopes created for events.
371        #[cfg(feature = "hoi4")] const CombinedCountryAndState = 1<<24;
372        #[cfg(feature = "hoi4")] const CombinedCountryAndCharacter = 1<<25;
373    }
374}
375
376// These have to be expressed a bit awkwardly because the binary operators are not `const`.
377// TODO: Scopes::all() returns a too-large set if multiple features are enabled.
378impl Scopes {
379    pub const fn non_primitive() -> Scopes {
380        Scopes::all()
381            .difference(Scopes::None.union(Scopes::Value).union(Scopes::Bool).union(Scopes::Flag))
382    }
383
384    pub const fn primitive() -> Scopes {
385        Scopes::Value.union(Scopes::Bool).union(Scopes::Flag)
386    }
387
388    pub const fn all_but_none() -> Scopes {
389        Scopes::all().difference(Scopes::None)
390    }
391
392    /// Read a scope type in string form and return it as a [`Scopes`] value.
393    pub fn from_snake_case(s: &str) -> Option<Scopes> {
394        #[cfg(feature = "ck3")]
395        if Game::is_ck3() {
396            // Deal with some exceptions to the general pattern
397            match s {
398                "ghw" => return Some(Scopes::GreatHolyWar),
399                "story" => return Some(Scopes::StoryCycle),
400                "great_holy_war" | "story_cycle" => return None,
401                _ => (),
402            }
403        }
404
405        Scopes::from_name(&snake_case_to_camel_case(s))
406    }
407
408    /// Similar to `from_snake_case`, but allows multiple scopes separated by `|`
409    /// Returns None if any of the conversions fail.
410    pub fn from_snake_case_multi(s: &str) -> Option<Scopes> {
411        let mut scopes = Scopes::empty();
412        for part in s.split('|') {
413            if let Some(scope) = Scopes::from_snake_case(part) {
414                scopes |= scope;
415            } else {
416                return None;
417            }
418        }
419        // If `scopes` is still empty then probably `s` was empty.
420        // Remember that `Scopes::empty()` is different from a bitfield containing `Scopes::None`.
421        if scopes == Scopes::empty() {
422            return None;
423        }
424        Some(scopes)
425    }
426}
427
428impl Display for Scopes {
429    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
430        if *self == Scopes::all() {
431            write!(f, "any scope")
432        } else if *self == Scopes::primitive() {
433            write!(f, "any primitive scope")
434        } else if *self == Scopes::non_primitive() {
435            write!(f, "non-primitive scope")
436        } else if *self == Scopes::all_but_none() {
437            write!(f, "any except none scope")
438        } else {
439            let mut vec = Vec::new();
440            for (name, _) in self.iter_names() {
441                vec.push(camel_case_to_separated_words(name));
442            }
443            let vec: Vec<&str> = vec.iter().map(String::as_ref).collect();
444            display_choices(f, &vec, "or")
445        }
446    }
447}
448
449/// A description of the constraints on a value with a prefix such as `var:` or `list_size:`
450#[derive(Copy, Clone, Debug, Eq, PartialEq)]
451pub enum ArgumentValue {
452    /// The value must be an expression that resolves to a scope object of the given type.
453    #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5"))]
454    Scope(Scopes),
455    /// The value must be the name of an item of the given item type.
456    Item(Item),
457    /// The value can be either a Scope or an Item
458    #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5"))]
459    ScopeOrItem(Scopes, Item),
460    /// The value can be a trait name or `trait|track`.
461    #[cfg(feature = "ck3")]
462    TraitTrack,
463    /// The value must be the name of a modif
464    #[cfg(any(feature = "vic3", feature = "imperator", feature = "eu5"))]
465    Modif,
466    /// The value must be a single word
467    #[cfg(any(feature = "vic3", feature = "ck3", feature = "eu5"))]
468    Identifier(&'static str),
469    /// The value consists of multiple arguments separated by `|`
470    #[cfg(feature = "eu5")]
471    Multiple(&'static [ArgumentValue]),
472    /// The value can be anything
473    UncheckedValue,
474    /// This trigger no longer exists. Arguments are version and explanation
475    #[cfg(feature = "ck3")]
476    Removed(&'static str, &'static str),
477}
478
479/// Look up an "event link", which is a script token that looks up something related
480/// to a scope value and returns another scope value.
481///
482/// `name` is the token. `inscopes` is the known scope context of this token.
483/// `inscopes` is only used for some special-case event links whose output scope type
484/// depends on their input scope type.
485///
486/// Returns a pair of `Scopes`. The first is the scope types this token can accept as input,
487/// and the second is the scope types it may return.
488#[allow(unused_variables)] // inscopes is only used for vic3
489pub fn scope_to_scope(name: &Token, inscopes: Scopes) -> Option<(Scopes, Scopes)> {
490    let scope_to_scope = match Game::game() {
491        #[cfg(feature = "ck3")]
492        Game::Ck3 => crate::ck3::tables::targets::scope_to_scope,
493        #[cfg(feature = "vic3")]
494        Game::Vic3 => crate::vic3::tables::targets::scope_to_scope,
495        #[cfg(feature = "imperator")]
496        Game::Imperator => crate::imperator::tables::targets::scope_to_scope,
497        #[cfg(feature = "eu5")]
498        Game::Eu5 => crate::eu5::tables::targets::scope_to_scope,
499        #[cfg(feature = "hoi4")]
500        Game::Hoi4 => crate::hoi4::tables::targets::scope_to_scope,
501    };
502    let scope_to_scope_removed = match Game::game() {
503        #[cfg(feature = "ck3")]
504        Game::Ck3 => crate::ck3::tables::targets::scope_to_scope_removed,
505        #[cfg(feature = "vic3")]
506        Game::Vic3 => crate::vic3::tables::targets::scope_to_scope_removed,
507        #[cfg(feature = "imperator")]
508        Game::Imperator => crate::imperator::tables::targets::scope_to_scope_removed,
509        #[cfg(feature = "eu5")]
510        Game::Eu5 => crate::eu5::tables::targets::scope_to_scope_removed,
511        #[cfg(feature = "hoi4")]
512        Game::Hoi4 => crate::hoi4::tables::targets::scope_to_scope_removed,
513    };
514
515    let name_lc = name.as_str().to_ascii_lowercase();
516    #[allow(unused_assignments)] // `from` only used for vic3
517    if let scopes @ Some((from, _)) = scope_to_scope(&name_lc) {
518        #[cfg(feature = "vic3")]
519        if Game::is_vic3() && name_lc == "type" {
520            // Special case for "type" because it goes from specific scope types to specific
521            // other scope types.
522            let mut outscopes = Scopes::empty();
523            if inscopes.contains(Scopes::Building) {
524                outscopes |= Scopes::BuildingType;
525            }
526            if inscopes.contains(Scopes::Company) {
527                outscopes |= Scopes::CompanyType;
528            }
529            if inscopes.contains(Scopes::DiplomaticPlay) {
530                outscopes |= Scopes::DiplomaticPlayType;
531            }
532            if inscopes.contains(Scopes::DiplomaticCatalyst) {
533                outscopes |= Scopes::DiplomaticCatalystType;
534            }
535            if inscopes.contains(Scopes::PoliticalLobby) {
536                outscopes |= Scopes::PoliticalLobbyType;
537            }
538            if inscopes.contains(Scopes::Institution) {
539                outscopes |= Scopes::InstitutionType;
540            }
541            if inscopes.contains(Scopes::InterestGroup) {
542                outscopes |= Scopes::InterestGroupType;
543            }
544            if inscopes.contains(Scopes::Law) {
545                outscopes |= Scopes::LawType;
546            }
547            if inscopes.contains(Scopes::PoliticalMovement) {
548                outscopes |= Scopes::PoliticalMovementType;
549            }
550            if inscopes.contains(Scopes::HarvestCondition) {
551                outscopes |= Scopes::HarvestConditionType;
552            }
553            if !outscopes.is_empty() {
554                return Some((from, outscopes));
555            }
556        }
557        scopes
558    } else if let Some((version, explanation)) = scope_to_scope_removed(&name_lc) {
559        let msg = format!("`{name}` was removed in {version}");
560        err(ErrorKey::Removed).strong().msg(msg).info(explanation).loc(name).push();
561        Some((Scopes::all(), Scopes::all_but_none()))
562    } else {
563        None
564    }
565}
566
567/// Look up a prefixed token that is used to look up items in the game database.
568///
569/// For example, `character:alexander_the_great` to fetch that character as a scope value.
570///
571/// Some prefixes have an input scope, and they look up something related to the input scope value.
572///
573/// Returns a pair of `Scopes` and the type of argument it accepts.
574/// The first `Scopes` is the scope types this token can accept as input, and the second one is
575/// the scope types it may return. The first will be `Scopes::None` if it needs no input.
576pub fn scope_prefix(prefix: &Token) -> Option<(Scopes, Scopes, ArgumentValue)> {
577    let scope_prefix = match Game::game() {
578        #[cfg(feature = "ck3")]
579        Game::Ck3 => crate::ck3::tables::targets::scope_prefix,
580        #[cfg(feature = "vic3")]
581        Game::Vic3 => crate::vic3::tables::targets::scope_prefix,
582        #[cfg(feature = "imperator")]
583        Game::Imperator => crate::imperator::tables::targets::scope_prefix,
584        #[cfg(feature = "eu5")]
585        Game::Eu5 => crate::eu5::tables::targets::scope_prefix,
586        #[cfg(feature = "hoi4")]
587        Game::Hoi4 => crate::hoi4::tables::targets::scope_prefix,
588    };
589    let prefix_lc = prefix.as_str().to_ascii_lowercase();
590    scope_prefix(&prefix_lc)
591}
592
593/// Look up a token that's an invalid target, and see if it might be missing a prefix.
594/// Return the prefix if one was found.
595///
596/// `scopes` should be a singular `Scopes` flag.
597///
598/// Example: if the token is "irish" and `scopes` is `Scopes::Culture` then return
599/// `Some("culture")` to indicate that the token should have been "culture:irish".
600pub fn needs_prefix(arg: &str, data: &Everything, scopes: Scopes) -> Option<&'static str> {
601    match Game::game() {
602        #[cfg(feature = "ck3")]
603        Game::Ck3 => crate::ck3::scopes::needs_prefix(arg, data, scopes),
604        #[cfg(feature = "vic3")]
605        Game::Vic3 => crate::vic3::scopes::needs_prefix(arg, data, scopes),
606        #[cfg(feature = "imperator")]
607        Game::Imperator => crate::imperator::scopes::needs_prefix(arg, data, scopes),
608        #[cfg(feature = "eu5")]
609        Game::Eu5 => crate::eu5::scopes::needs_prefix(arg, data, scopes),
610        #[cfg(feature = "hoi4")]
611        Game::Hoi4 => crate::hoi4::scopes::needs_prefix(arg, data, scopes),
612    }
613}
614
615/// Look up an iterator, which is a script element that executes its block multiple times, once for
616/// each applicable scope value. Iterators may be builtin (the usual case) or may be scripted lists.
617///
618/// `name` is the name of the iterator, without its `any_`, `every_`, `random_` or `ordered_` prefix.
619/// `sc` is a [`ScopeContext`], only used for validating scripted lists.
620///
621/// Returns a pair of `Scopes`. The first is the scope types this token can accept as input,
622/// and the second is the scope types it may return.
623/// The first will be `Scopes::None` if it needs no input.
624pub fn scope_iterator(
625    name: &Token,
626    data: &Everything,
627    sc: &mut ScopeContext,
628) -> Option<(Scopes, Scopes)> {
629    let scope_iterator = match Game::game() {
630        #[cfg(feature = "ck3")]
631        Game::Ck3 => crate::ck3::tables::iterators::iterator,
632        #[cfg(feature = "vic3")]
633        Game::Vic3 => crate::vic3::tables::iterators::iterator,
634        #[cfg(feature = "imperator")]
635        Game::Imperator => crate::imperator::tables::iterators::iterator,
636        #[cfg(feature = "eu5")]
637        Game::Eu5 => crate::eu5::tables::iterators::iterator,
638        #[cfg(feature = "hoi4")]
639        Game::Hoi4 => crate::hoi4::tables::iterators::iterator,
640    };
641    let scope_iterator_removed = match Game::game() {
642        #[cfg(feature = "ck3")]
643        Game::Ck3 => crate::ck3::tables::iterators::iterator_removed,
644        #[cfg(feature = "vic3")]
645        Game::Vic3 => crate::vic3::tables::iterators::iterator_removed,
646        #[cfg(feature = "imperator")]
647        Game::Imperator => crate::imperator::tables::iterators::iterator_removed,
648        #[cfg(feature = "eu5")]
649        Game::Eu5 => crate::eu5::tables::iterators::iterator_removed,
650        #[cfg(feature = "hoi4")]
651        Game::Hoi4 => crate::hoi4::tables::iterators::iterator_removed,
652    };
653
654    let name_lc = Lowercase::new(name.as_str());
655    if let scopes @ Some(_) = scope_iterator(&name_lc, name, data) {
656        return scopes;
657    }
658    if let Some((version, explanation)) = scope_iterator_removed(name_lc.as_str()) {
659        let msg = format!("`{name}` iterators were removed in {version}");
660        err(ErrorKey::Removed).strong().msg(msg).info(explanation).loc(name).push();
661        return Some((Scopes::all(), Scopes::all()));
662    }
663    #[cfg(feature = "jomini")]
664    if Game::is_jomini() && data.scripted_lists.exists(name.as_str()) {
665        data.scripted_lists.validate_call(name, data, sc);
666        return data
667            .scripted_lists
668            .base(name)
669            .and_then(|base| scope_iterator(&Lowercase::new(base.as_str()), base, data));
670    }
671    #[cfg(feature = "hoi4")]
672    let _ = &data; // mark parameter used
673    #[cfg(feature = "hoi4")]
674    let _ = &sc; // mark parameter used
675    None
676}