use std::fmt::{Display, Formatter};
use bitflags::bitflags;
use crate::context::ScopeContext;
use crate::everything::Everything;
use crate::game::Game;
use crate::item::Item;
use crate::report::{err, ErrorKey};
use crate::token::Token;
#[cfg(feature = "vic3")]
type ScopesBits = u128;
#[cfg(not(feature = "vic3"))]
type ScopesBits = u64;
bitflags! {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[rustfmt::skip] pub struct Scopes: ScopesBits {
const None = 0x0000_0001;
const Value = 0x0000_0002;
const Bool = 0x0000_0004;
const Flag = 0x0000_0008;
#[cfg(any(feature = "vic3", feature = "imperator"))]
const Color = 0x0000_0010;
#[cfg(any(feature = "vic3", feature = "imperator"))]
const Country = 0x0000_0020;
const Character = 0x0000_0040;
const Culture = 0x0000_0080;
const Province = 0x0000_0100;
#[cfg(any(feature = "vic3", feature = "imperator"))]
const Pop = 0x0000_0200;
#[cfg(any(feature = "vic3", feature = "imperator"))]
const Party = 0x0000_0400;
const Religion = 0x0000_0800;
#[cfg(any(feature = "vic3", feature = "imperator"))]
const State = 0x0000_1000;
const War = 0x0000_2000;
#[cfg(feature = "ck3")] const Accolade = 0x0001_0000;
#[cfg(feature = "ck3")] const AccoladeType = 0x0002_0000;
#[cfg(feature = "ck3")] const Activity = 0x0004_0000;
#[cfg(feature = "ck3")] const ActivityType = 0x0008_0000;
#[cfg(feature = "ck3")] const Army = 0x0010_0000;
#[cfg(feature = "ck3")] const Artifact = 0x0020_0000;
#[cfg(feature = "ck3")] const CasusBelli = 0x0040_0000;
#[cfg(feature = "ck3")] const CharacterMemory = 0x0080_0000;
#[cfg(feature = "ck3")] const Combat = 0x0100_0000;
#[cfg(feature = "ck3")] const CombatSide = 0x0200_0000;
#[cfg(feature = "ck3")] const CouncilTask = 0x0400_0000;
#[cfg(feature = "ck3")] const CulturePillar = 0x0800_0000;
#[cfg(feature = "ck3")] const CultureTradition = 0x1000_0000;
#[cfg(feature = "ck3")] const Decision = 0x2000_0000;
#[cfg(feature = "ck3")] const Doctrine = 0x4000_0000;
#[cfg(feature = "ck3")] const Dynasty = 0x8000_0000;
#[cfg(feature = "ck3")] const DynastyHouse = 0x0000_0001_0000_0000;
#[cfg(feature = "ck3")] const Faction = 0x0000_0002_0000_0000;
#[cfg(feature = "ck3")] const Faith = 0x0000_0004_0000_0000;
#[cfg(feature = "ck3")] const GovernmentType = 0x0000_0008_0000_0000;
#[cfg(feature = "ck3")] const GreatHolyWar = 0x0000_0010_0000_0000;
#[cfg(feature = "ck3")] const HolyOrder = 0x0000_0020_0000_0000;
#[cfg(feature = "ck3")] const Inspiration = 0x0000_0040_0000_0000;
#[cfg(feature = "ck3")] const LandedTitle = 0x0000_0080_0000_0000;
#[cfg(feature = "ck3")] const MercenaryCompany = 0x0000_0100_0000_0000;
#[cfg(feature = "ck3")] const Scheme = 0x0000_0200_0000_0000;
#[cfg(feature = "ck3")] const Secret = 0x0000_0400_0000_0000;
#[cfg(feature = "ck3")] const StoryCycle = 0x0000_0800_0000_0000;
#[cfg(feature = "ck3")] const Struggle = 0x0000_1000_0000_0000;
#[cfg(feature = "ck3")] const TitleAndVassalChange = 0x0000_2000_0000_0000;
#[cfg(feature = "ck3")] const Trait = 0x0000_4000_0000_0000;
#[cfg(feature = "ck3")] const TravelPlan = 0x0000_8000_0000_0000;
#[cfg(feature = "ck3")] const VassalContract = 0x0001_0000_0000_0000;
#[cfg(feature = "ck3")] const VassalObligationLevel = 0x0002_0000_0000_0000;
#[cfg(feature = "ck3")] const HoldingType = 0x0004_0000_0000_0000;
#[cfg(feature = "ck3")] const TaxSlot = 0x0008_0000_0000_0000;
#[cfg(feature = "ck3")] const EpidemicType = 0x0010_0000_0000_0000;
#[cfg(feature = "ck3")] const Epidemic = 0x0020_0000_0000_0000;
#[cfg(feature = "ck3")] const LegendType = 0x0040_0000_0000_0000;
#[cfg(feature = "ck3")] const Legend = 0x0080_0000_0000_0000;
#[cfg(feature = "ck3")] const GeographicalRegion = 0x0100_0000_0000_0000;
#[cfg(feature = "ck3")] const Domicile = 0x0200_0000_0000_0000;
#[cfg(feature = "ck3")] const AgentSlot = 0x0400_0000_0000_0000;
#[cfg(feature = "ck3")] const TaskContract = 0x0800_0000_0000_0000;
#[cfg(feature = "ck3")] const TaskContractType = 0x1000_0000_0000_0000;
#[cfg(feature = "ck3")] const Regiment = 0x2000_0000_0000_0000;
#[cfg(feature = "ck3")] const CasusBelliType = 0x4000_0000_0000_0000;
#[cfg(feature = "vic3")] const Battle = 0x0001_0000;
#[cfg(feature = "vic3")] const BattleSide = 0x0002_0000;
#[cfg(feature = "vic3")] const Building = 0x0004_0000;
#[cfg(feature = "vic3")] const BuildingType = 0x0008_0000;
#[cfg(feature = "vic3")] const CanalType = 0x0010_0000;
#[cfg(feature = "vic3")] const CivilWar = 0x0020_0000;
#[cfg(feature = "vic3")] const CulturalCommunity = 0x0040_0000;
#[cfg(feature = "vic3")] const NewCombatUnit = 0x0080_0000;
#[cfg(feature = "vic3")] const CommanderOrderType = 0x0100_0000;
#[cfg(feature = "vic3")] const CountryCreation = 0x0200_0000;
#[cfg(feature = "vic3")] const CountryDefinition = 0x0400_0000;
#[cfg(feature = "vic3")] const CountryFormation = 0x0800_0000;
#[cfg(feature = "vic3")] const Decree = 0x1000_0000;
#[cfg(feature = "vic3")] const DiplomaticAction = 0x2000_0000;
#[cfg(feature = "vic3")] const DiplomaticPact = 0x4000_0000;
#[cfg(feature = "vic3")] const DiplomaticPlay = 0x8000_0000;
#[cfg(feature = "vic3")] const DiplomaticRelations = 0x0000_0001_0000_0000;
#[cfg(feature = "vic3")] const Front = 0x0000_0002_0000_0000;
#[cfg(feature = "vic3")] const Goods = 0x0000_0004_0000_0000;
#[cfg(feature = "vic3")] const Hq = 0x0000_0008_0000_0000;
#[cfg(feature = "vic3")] const Ideology = 0x0000_0010_0000_0000;
#[cfg(feature = "vic3")] const Institution = 0x0000_0020_0000_0000;
#[cfg(feature = "vic3")] const InstitutionType = 0x0000_0040_0000_0000;
#[cfg(feature = "vic3")] const InterestMarker = 0x0000_0080_0000_0000;
#[cfg(feature = "vic3")] const InterestGroup = 0x0000_0100_0000_0000;
#[cfg(feature = "vic3")] const InterestGroupTrait = 0x0000_0200_0000_0000;
#[cfg(feature = "vic3")] const InterestGroupType = 0x0000_0400_0000_0000;
#[cfg(feature = "vic3")] const JournalEntry = 0x0000_0800_0000_0000;
#[cfg(feature = "vic3")] const Law = 0x0000_1000_0000_0000;
#[cfg(feature = "vic3")] const LawType = 0x0000_2000_0000_0000;
#[cfg(feature = "vic3")] const Market = 0x0000_4000_0000_0000;
#[cfg(feature = "vic3")] const MarketGoods = 0x0000_8000_0000_0000;
#[cfg(feature = "vic3")] const Objective = 0x0001_0000_0000_0000;
#[cfg(feature = "vic3")] const PoliticalMovement = 0x0002_0000_0000_0000;
#[cfg(feature = "vic3")] const PopType = 0x0004_0000_0000_0000;
#[cfg(feature = "vic3")] const ShippingLane = 0x0008_0000_0000_0000;
#[cfg(feature = "vic3")] const StateRegion = 0x0010_0000_0000_0000;
#[cfg(feature = "vic3")] const StateTrait = 0x0020_0000_0000_0000;
#[cfg(feature = "vic3")] const StrategicRegion = 0x0040_0000_0000_0000;
#[cfg(feature = "vic3")] const Technology = 0x0080_0000_0000_0000;
#[cfg(feature = "vic3")] const TechnologyStatus = 0x0100_0000_0000_0000;
#[cfg(feature = "vic3")] const Theater = 0x0200_0000_0000_0000;
#[cfg(feature = "vic3")] const TradeRoute = 0x0400_0000_0000_0000;
#[cfg(feature = "vic3")] const CombatUnitType = 0x1000_0000_0000_0000;
#[cfg(feature = "vic3")] const MilitaryFormation = 0x2000_0000_0000_0000;
#[cfg(feature = "vic3")] const Sway = 0x4000_0000_0000_0000;
#[cfg(feature = "vic3")] const StateGoods = 0x8000_0000_0000_0000;
#[cfg(feature = "vic3")] const DiplomaticDemand = 0x0000_0000_0000_0001_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const Company = 0x0000_0000_0000_0002_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const CompanyType = 0x0000_0000_0000_0004_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const TravelNode = 0x0000_0000_0000_0008_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const TravelNodeDefinition = 0x0000_0000_0000_0010_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const TravelConnection = 0x0000_0000_0000_0020_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const TravelConnectionDefinition = 0x0000_0000_0000_0040_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const NavalInvasion = 0x0000_0000_0000_0080_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const MobilizationOption = 0x0000_0000_0000_0100_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const PowerBlocPrincipleGroup = 0x0000_0000_0000_0200_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const DiplomaticPlayType = 0x0000_0000_0000_0400_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const DiplomaticCatalyst = 0x0000_0000_0000_0800_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const DiplomaticCatalystType = 0x0000_0000_0000_1000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const DiplomaticCatalystCategory = 0x0000_0000_0000_2000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const PoliticalLobby = 0x0000_0000_0000_4000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const PoliticalLobbyType = 0x0000_0000_0000_8000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const PoliticalLobbyAppeasement = 0x0000_0000_0001_0000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const PowerBloc = 0x0000_0000_0002_0000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const PowerBlocIdentity = 0x0000_0000_0004_0000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const PowerBlocPrinciple = 0x0000_0000_0008_0000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const HarvestCondition = 0x0000_0000_0010_0000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const PoliticalMovementType = 0x0000_0000_0020_0000_0000_0000_0000_0000;
#[cfg(feature = "vic3")] const HarvestConditionType = 0x0000_0000_0040_0000_0000_0000_0000_0000;
#[cfg(feature = "imperator")] const Area = 0x0001_0000;
#[cfg(feature = "imperator")] const CountryCulture = 0x0002_0000;
#[cfg(feature = "imperator")] const CultureGroup = 0x0004_0000;
#[cfg(feature = "imperator")] const Deity = 0x0008_0000;
#[cfg(feature = "imperator")] const Family = 0x0010_0000;
#[cfg(feature = "imperator")] const Governorship = 0x0020_0000;
#[cfg(feature = "imperator")] const GreatWork = 0x0040_0000;
#[cfg(feature = "imperator")] const Job = 0x0080_0000;
#[cfg(feature = "imperator")] const Legion = 0x0100_0000;
#[cfg(feature = "imperator")] const LevyTemplate = 0x0200_0000;
#[cfg(feature = "imperator")] const Region = 0x0400_0000;
#[cfg(feature = "imperator")] const Siege = 0x0800_0000;
#[cfg(feature = "imperator")] const SubUnit = 0x1000_0000;
#[cfg(feature = "imperator")] const Treasure = 0x2000_0000;
#[cfg(feature = "imperator")] const Unit = 0x4000_0000;
}
}
impl Scopes {
pub const fn non_primitive() -> Scopes {
Scopes::all()
.difference(Scopes::None.union(Scopes::Value).union(Scopes::Bool).union(Scopes::Flag))
}
pub const fn primitive() -> Scopes {
Scopes::Value.union(Scopes::Bool).union(Scopes::Flag)
}
pub const fn all_but_none() -> Scopes {
Scopes::all().difference(Scopes::None)
}
pub fn from_snake_case(s: &str) -> Option<Scopes> {
match s {
"none" => return Some(Scopes::None),
"value" => return Some(Scopes::Value),
"bool" => return Some(Scopes::Bool),
"flag" => return Some(Scopes::Flag),
_ => (),
};
match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => crate::ck3::scopes::scope_from_snake_case(s),
#[cfg(feature = "vic3")]
Game::Vic3 => crate::vic3::scopes::scope_from_snake_case(s),
#[cfg(feature = "imperator")]
Game::Imperator => crate::imperator::scopes::scope_from_snake_case(s),
}
}
pub fn from_snake_case_multi(s: &str) -> Option<Scopes> {
let mut scopes = Scopes::empty();
for part in s.split('|') {
if let Some(scope) = Scopes::from_snake_case(part) {
scopes |= scope;
} else {
return None;
}
}
if scopes == Scopes::empty() {
return None;
}
Some(scopes)
}
}
impl Display for Scopes {
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
if *self == Scopes::all() {
write!(f, "any scope")
} else if *self == Scopes::primitive() {
write!(f, "any primitive scope")
} else if *self == Scopes::non_primitive() {
write!(f, "non-primitive scope")
} else if *self == Scopes::all_but_none() {
write!(f, "any except none scope")
} else {
match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => crate::ck3::scopes::display_fmt(*self, f),
#[cfg(feature = "vic3")]
Game::Vic3 => crate::vic3::scopes::display_fmt(*self, f),
#[cfg(feature = "imperator")]
Game::Imperator => crate::imperator::scopes::display_fmt(*self, f),
}
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ArgumentValue {
#[cfg(any(feature = "ck3", feature = "vic3"))]
Scope(Scopes),
Item(Item),
#[cfg(feature = "ck3")]
ScopeOrItem(Scopes, Item),
#[cfg(feature = "ck3")]
TraitTrack,
#[cfg(feature = "vic3")]
Modif,
UncheckedValue,
}
#[allow(unused_variables)] pub fn scope_to_scope(name: &Token, inscopes: Scopes) -> Option<(Scopes, Scopes)> {
let scope_to_scope = match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => crate::ck3::scopes::scope_to_scope,
#[cfg(feature = "vic3")]
Game::Vic3 => crate::vic3::scopes::scope_to_scope,
#[cfg(feature = "imperator")]
Game::Imperator => crate::imperator::scopes::scope_to_scope,
};
let scope_to_scope_removed = match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => crate::ck3::scopes::scope_to_scope_removed,
#[cfg(feature = "vic3")]
Game::Vic3 => crate::vic3::scopes::scope_to_scope_removed,
#[cfg(feature = "imperator")]
Game::Imperator => crate::imperator::scopes::scope_to_scope_removed,
};
let name_lc = name.as_str().to_ascii_lowercase();
if let scopes @ Some((from, _)) = scope_to_scope(&name_lc) {
#[cfg(feature = "vic3")]
if Game::is_vic3() && name_lc == "type" {
let mut outscopes = Scopes::empty();
if inscopes.contains(Scopes::Building) {
outscopes |= Scopes::BuildingType;
}
if inscopes.contains(Scopes::Company) {
outscopes |= Scopes::CompanyType;
}
if inscopes.contains(Scopes::DiplomaticPlay) {
outscopes |= Scopes::DiplomaticPlayType;
}
if inscopes.contains(Scopes::DiplomaticCatalyst) {
outscopes |= Scopes::DiplomaticCatalystType;
}
if inscopes.contains(Scopes::PoliticalLobby) {
outscopes |= Scopes::PoliticalLobbyType;
}
if inscopes.contains(Scopes::Institution) {
outscopes |= Scopes::InstitutionType;
}
if inscopes.contains(Scopes::InterestGroup) {
outscopes |= Scopes::InterestGroupType;
}
if inscopes.contains(Scopes::Law) {
outscopes |= Scopes::LawType;
}
if inscopes.contains(Scopes::PoliticalMovement) {
outscopes |= Scopes::PoliticalMovementType;
}
if inscopes.contains(Scopes::HarvestCondition) {
outscopes |= Scopes::HarvestConditionType;
}
if !outscopes.is_empty() {
return Some((from, outscopes));
}
}
scopes
} else if let Some((version, explanation)) = scope_to_scope_removed(&name_lc) {
let msg = format!("`{name}` was removed in {version}");
err(ErrorKey::Removed).strong().msg(msg).info(explanation).loc(name).push();
return Some((Scopes::all(), Scopes::all_but_none()));
} else {
None
}
}
pub fn scope_prefix(prefix: &Token) -> Option<(Scopes, Scopes, ArgumentValue)> {
let scope_prefix = match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => crate::ck3::scopes::scope_prefix,
#[cfg(feature = "vic3")]
Game::Vic3 => crate::vic3::scopes::scope_prefix,
#[cfg(feature = "imperator")]
Game::Imperator => crate::imperator::scopes::scope_prefix,
};
let prefix_lc = prefix.as_str().to_ascii_lowercase();
scope_prefix(&prefix_lc)
}
pub fn needs_prefix(arg: &str, data: &Everything, scopes: Scopes) -> Option<&'static str> {
match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => crate::ck3::scopes::needs_prefix(arg, data, scopes),
#[cfg(feature = "vic3")]
Game::Vic3 => crate::vic3::scopes::needs_prefix(arg, data, scopes),
#[cfg(feature = "imperator")]
Game::Imperator => crate::imperator::scopes::needs_prefix(arg, data, scopes),
}
}
pub fn scope_iterator(
name: &Token,
data: &Everything,
sc: &mut ScopeContext,
) -> Option<(Scopes, Scopes)> {
let scope_iterator = match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => crate::ck3::scopes::scope_iterator,
#[cfg(feature = "vic3")]
Game::Vic3 => crate::vic3::scopes::scope_iterator,
#[cfg(feature = "imperator")]
Game::Imperator => crate::imperator::scopes::scope_iterator,
};
let scope_iterator_removed = match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => crate::ck3::scopes::scope_iterator_removed,
#[cfg(feature = "vic3")]
Game::Vic3 => crate::vic3::scopes::scope_iterator_removed,
#[cfg(feature = "imperator")]
Game::Imperator => crate::imperator::scopes::scope_iterator_removed,
};
let name_lc = name.as_str().to_ascii_lowercase();
if let scopes @ Some(_) = scope_iterator(&name_lc) {
return scopes;
} else if let Some((version, explanation)) = scope_iterator_removed(&name_lc) {
let msg = format!("`{name}` iterators were removed in {version}");
err(ErrorKey::Removed).strong().msg(msg).info(explanation).loc(name).push();
return Some((Scopes::all(), Scopes::all()));
} else if data.scripted_lists.exists(name.as_str()) {
data.scripted_lists.validate_call(name, data, sc);
return data
.scripted_lists
.base(name)
.and_then(|base| scope_iterator(&base.as_str().to_ascii_lowercase()));
}
None
}