use std::{convert::TryFrom, result::Result};
pub type SCXVersion = [u8; 4];
#[derive(Debug, Clone, Copy)]
pub struct ParseDiplomaticStanceError(i32);
impl std::fmt::Display for ParseDiplomaticStanceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid diplomatic stance {} (must be 0/1/3)", self.0)
}
}
impl std::error::Error for ParseDiplomaticStanceError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiplomaticStance {
Ally = 0,
Neutral = 1,
Enemy = 3,
}
impl TryFrom<i32> for DiplomaticStance {
type Error = ParseDiplomaticStanceError;
fn try_from(n: i32) -> Result<Self, Self::Error> {
match n {
0 => Ok(DiplomaticStance::Ally),
1 => Ok(DiplomaticStance::Neutral),
3 => Ok(DiplomaticStance::Enemy),
n => Err(ParseDiplomaticStanceError(n)),
}
}
}
impl From<DiplomaticStance> for i32 {
fn from(stance: DiplomaticStance) -> i32 {
match stance {
DiplomaticStance::Ally => 0,
DiplomaticStance::Neutral => 1,
DiplomaticStance::Enemy => 3,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ParseDataSetError(i32);
impl std::fmt::Display for ParseDataSetError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid data set {} (must be 0/1)", self.0)
}
}
impl std::error::Error for ParseDataSetError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DataSet {
BaseGame,
Expansions,
}
impl TryFrom<i32> for DataSet {
type Error = ParseDataSetError;
fn try_from(n: i32) -> Result<Self, Self::Error> {
match n {
0 => Ok(DataSet::BaseGame),
1 => Ok(DataSet::Expansions),
n => Err(ParseDataSetError(n)),
}
}
}
impl From<DataSet> for i32 {
fn from(id: DataSet) -> i32 {
match id {
DataSet::BaseGame => 0,
DataSet::Expansions => 1,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ParseDLCPackageError(i32);
impl std::fmt::Display for ParseDLCPackageError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "unknown dlc package {}", self.0)
}
}
impl std::error::Error for ParseDLCPackageError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DLCPackage {
AgeOfKings,
AgeOfConquerors,
TheForgotten,
AfricanKingdoms,
RiseOfTheRajas,
}
impl TryFrom<i32> for DLCPackage {
type Error = ParseDLCPackageError;
fn try_from(n: i32) -> Result<Self, Self::Error> {
match n {
2 => Ok(DLCPackage::AgeOfKings),
3 => Ok(DLCPackage::AgeOfConquerors),
4 => Ok(DLCPackage::TheForgotten),
5 => Ok(DLCPackage::AfricanKingdoms),
6 => Ok(DLCPackage::RiseOfTheRajas),
n => Err(ParseDLCPackageError(n)),
}
}
}
impl From<DLCPackage> for i32 {
fn from(dlc_id: DLCPackage) -> i32 {
match dlc_id {
DLCPackage::AgeOfKings => 2,
DLCPackage::AgeOfConquerors => 3,
DLCPackage::TheForgotten => 4,
DLCPackage::AfricanKingdoms => 5,
DLCPackage::RiseOfTheRajas => 6,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ParseStartingAgeError {
version: f32,
found: i32,
}
impl std::fmt::Display for ParseStartingAgeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let expected = if self.version < 1.25 { "-1-4" } else { "-1-6" };
write!(
f,
"invalid starting age {} (must be {})",
self.found, expected
)
}
}
impl std::error::Error for ParseStartingAgeError {}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum StartingAge {
Default = -1,
Nomad = -2,
DarkAge = 0,
FeudalAge = 1,
CastleAge = 2,
ImperialAge = 3,
PostImperialAge = 4,
}
impl StartingAge {
pub fn try_from(n: i32, version: f32) -> Result<Self, ParseStartingAgeError> {
if version < 1.25 {
match n {
-1 => Ok(StartingAge::Default),
0 => Ok(StartingAge::DarkAge),
1 => Ok(StartingAge::FeudalAge),
2 => Ok(StartingAge::CastleAge),
3 => Ok(StartingAge::ImperialAge),
4 => Ok(StartingAge::PostImperialAge),
_ => Err(ParseStartingAgeError { version, found: n }),
}
} else {
match n {
-1 | 0 => Ok(StartingAge::Default),
1 => Ok(StartingAge::Nomad),
2 => Ok(StartingAge::DarkAge),
3 => Ok(StartingAge::FeudalAge),
4 => Ok(StartingAge::CastleAge),
5 => Ok(StartingAge::ImperialAge),
6 => Ok(StartingAge::PostImperialAge),
_ => Err(ParseStartingAgeError { version, found: n }),
}
}
}
pub fn to_i32(self, version: f32) -> i32 {
if version < 1.25 {
match self {
StartingAge::Default => -1,
StartingAge::Nomad | StartingAge::DarkAge => 0,
StartingAge::FeudalAge => 1,
StartingAge::CastleAge => 2,
StartingAge::ImperialAge => 3,
StartingAge::PostImperialAge => 4,
}
} else {
match self {
StartingAge::Default => 0,
StartingAge::Nomad => 1,
StartingAge::DarkAge => 2,
StartingAge::FeudalAge => 3,
StartingAge::CastleAge => 4,
StartingAge::ImperialAge => 5,
StartingAge::PostImperialAge => 6,
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VictoryCondition {
Capture = 0,
Create = 1,
Destroy = 2,
DestroyMultiple = 3,
BringToArea = 4,
BringToObject = 5,
Attribute = 6,
Explore = 7,
CreateInArea = 8,
DestroyAll = 9,
DestroyPlayer = 10,
Points = 11,
}
#[derive(Debug, Clone, PartialEq)]
pub struct VersionBundle {
pub format: SCXVersion,
pub header: u32,
pub dlc_options: i32,
pub data: f32,
pub picture: u32,
pub victory: f32,
pub triggers: f64,
}
impl VersionBundle {
pub fn aoe() -> Self {
unimplemented!()
}
pub fn ror() -> Self {
unimplemented!()
}
pub fn aok() -> Self {
unimplemented!()
}
pub fn aoc() -> Self {
Self {
format: *b"1.21",
header: 2,
dlc_options: -1,
data: 1.22,
picture: 1,
victory: 2.0,
triggers: 1.6,
}
}
pub fn userpatch_14() -> Self {
Self::aoc()
}
pub fn userpatch_15() -> Self {
Self::userpatch_14()
}
pub fn hd_edition() -> Self {
Self {
format: *b"1.21",
header: 3,
dlc_options: 1000,
data: 1.26,
picture: 3,
victory: 2.0,
triggers: 1.6,
}
}
pub fn is_aok(&self) -> bool {
match &self.format {
b"1.18" | b"1.19" | b"1.20" => true,
_ => false,
}
}
pub fn is_aoc(&self) -> bool {
self.format == *b"1.21" && self.data <= 1.22
}
pub fn is_hd_edition(&self) -> bool {
self.format == *b"1.21" || self.format == *b"1.22" && self.data > 1.22
}
}