use std::fmt::{Display, Formatter};
use std::sync::OnceLock;
use anyhow::{anyhow, Result};
use bitflags::bitflags;
use crate::helpers::display_choices;
static GAME: OnceLock<Game> = OnceLock::new();
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Game {
#[cfg(feature = "ck3")]
Ck3,
#[cfg(feature = "vic3")]
Vic3,
#[cfg(feature = "imperator")]
Imperator,
}
impl Game {
pub fn set(game: Game) -> Result<()> {
GAME.set(game).map_err(|_| anyhow!("tried to set game type twice"))?;
Ok(())
}
#[allow(clippy::self_named_constructors)] #[allow(unreachable_code)]
pub fn game() -> Game {
#[cfg(all(feature = "ck3", not(feature = "vic3"), not(feature = "imperator")))]
return Game::Ck3;
#[cfg(all(feature = "vic3", not(feature = "ck3"), not(feature = "imperator")))]
return Game::Vic3;
#[cfg(all(feature = "imperator", not(feature = "ck3"), not(feature = "vic3")))]
return Game::Imperator;
*GAME.get().expect("internal error: don't know which game we are validating")
}
pub(crate) fn is_ck3() -> bool {
#[cfg(not(feature = "ck3"))]
return false;
#[cfg(all(feature = "ck3", not(feature = "vic3"), not(feature = "imperator")))]
return true;
#[cfg(all(feature = "ck3", any(feature = "vic3", feature = "imperator")))]
return GAME.get() == Some(&Game::Ck3);
}
pub(crate) fn is_vic3() -> bool {
#[cfg(not(feature = "vic3"))]
return false;
#[cfg(all(feature = "vic3", not(feature = "ck3"), not(feature = "imperator")))]
return true;
#[cfg(all(feature = "vic3", any(feature = "ck3", feature = "imperator")))]
return GAME.get() == Some(&Game::Vic3);
}
pub(crate) fn is_imperator() -> bool {
#[cfg(not(feature = "imperator"))]
return false;
#[cfg(all(feature = "imperator", not(feature = "ck3"), not(feature = "vic3")))]
return true;
#[cfg(all(feature = "imperator", any(feature = "ck3", feature = "vic3")))]
return GAME.get() == Some(&Game::Imperator);
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GameFlags: u8 {
const Ck3 = 0x01;
const Vic3 = 0x02;
const Imperator = 0x04;
}
}
impl GameFlags {
pub fn game() -> Self {
match Game::game() {
#[cfg(feature = "ck3")]
Game::Ck3 => GameFlags::Ck3,
#[cfg(feature = "vic3")]
Game::Vic3 => GameFlags::Vic3,
#[cfg(feature = "imperator")]
Game::Imperator => GameFlags::Imperator,
}
}
}
impl Display for GameFlags {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
let mut vec = Vec::new();
if self.contains(Self::Ck3) {
vec.push("Crusader Kings 3");
}
if self.contains(Self::Vic3) {
vec.push("Victoria 3");
}
if self.contains(Self::Imperator) {
vec.push("Imperator: Rome");
}
display_choices(f, &vec, "and")
}
}
impl From<Game> for GameFlags {
fn from(game: Game) -> Self {
match game {
#[cfg(feature = "ck3")]
Game::Ck3 => GameFlags::Ck3,
#[cfg(feature = "vic3")]
Game::Vic3 => GameFlags::Vic3,
#[cfg(feature = "imperator")]
Game::Imperator => GameFlags::Imperator,
}
}
}