use bitflags::bitflags;
use getset::*;
use serde_derive::{Serialize, Deserialize};
use crate::binary::{ReadBytes, WriteBytes};
use crate::error::{Result, RLibError};
use crate::files::{Decodeable, EncodeableExtraData, Encodeable};
use crate::games::supported_games::*;
use crate::utils::*;
use super::DecodeableExtraData;
pub const PATH: &str = "groupformations.bin";
mod versions;
#[cfg(test)] mod test_group_formations;
#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct GroupFormations {
formations: Vec<GroupFormation>,
}
#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct GroupFormation {
name: String,
ai_priority: f32,
ai_purpose: AIPurposeCommon,
uk_2: u32,
min_unit_category_percentage: Vec<MinUnitCategoryPercentage>,
ai_supported_subcultures: Vec<String>,
ai_supported_factions: Vec<String>,
group_formation_blocks: Vec<GroupFormationBlock>,
}
#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct MinUnitCategoryPercentage {
category: UnitCategoryCommon,
percentage: u32,
}
#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct GroupFormationBlock {
block_id: u32,
block: Block,
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Block {
ContainerAbsolute(ContainerAbsolute),
ContainerRelative(ContainerRelative),
Spanning(Spanning)
}
#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct ContainerAbsolute {
block_priority: f32,
entity_arrangement: EntityArrangementCommon,
inter_entity_spacing: f32,
crescent_y_offset: f32,
position_x: f32,
position_y: f32,
minimum_entity_threshold: i32,
maximum_entity_threshold: i32,
entity_preferences: Vec<EntityPreference>,
}
#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct ContainerRelative {
block_priority: f32,
relative_block_id: u32,
entity_arrangement: EntityArrangementCommon,
inter_entity_spacing: f32,
crescent_y_offset: f32,
position_x: f32,
position_y: f32,
minimum_entity_threshold: i32,
maximum_entity_threshold: i32,
entity_preferences: Vec<EntityPreference>,
}
#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct EntityPreference {
priority: f32,
entity: EntityCommon,
entity_weight: EntityWeightCommon,
uk_1: u32,
uk_2: u32,
uk_3: u32,
entity_class: String,
}
#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
#[getset(get = "pub", get_mut = "pub", set = "pub")]
pub struct Spanning {
spanned_block_ids: Vec<u32>,
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum AIPurposeCommon {
Rome2(versions::rome_2::AIPurpose),
Shogun2(versions::shogun_2::AIPurpose),
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum EntityArrangementCommon {
Rome2(versions::rome_2::EntityArrangement),
Shogun2(versions::shogun_2::EntityArrangement),
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum UnitCategoryCommon {
Rome2(versions::rome_2::UnitCategory),
Shogun2(versions::shogun_2::UnitCategory),
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum EntityCommon {
Rome2(versions::rome_2::Entity),
Shogun2(versions::shogun_2::Entity),
}
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum EntityWeightCommon {
Rome2(versions::rome_2::EntityWeight),
Attila(versions::rome_2::EntityWeight),
}
impl Default for Block {
fn default() -> Self {
Self::ContainerAbsolute(ContainerAbsolute::default())
}
}
impl Default for AIPurposeCommon {
fn default() -> Self {
Self::Shogun2(versions::shogun_2::AIPurpose::default())
}
}
impl Default for EntityArrangementCommon {
fn default() -> Self {
Self::Shogun2(versions::shogun_2::EntityArrangement::default())
}
}
impl Default for UnitCategoryCommon {
fn default() -> Self {
Self::Shogun2(versions::shogun_2::UnitCategory::default())
}
}
impl Default for EntityCommon {
fn default() -> Self {
Self::Shogun2(versions::shogun_2::Entity::default())
}
}
impl Default for EntityWeightCommon {
fn default() -> Self {
Self::Rome2(versions::rome_2::EntityWeight::default())
}
}
impl Decodeable for GroupFormations {
fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
let extra_data = extra_data.as_ref().ok_or(RLibError::DecodingMissingExtraData)?;
let game_info = extra_data.game_info.ok_or_else(|| RLibError::DecodingMissingExtraDataField("game_info".to_owned()))?;
let mut decoded = Self::default();
let data_len = data.len()?;
match game_info.key() {
KEY_ROME_2 => decoded.decode_rom_2(data)?,
KEY_SHOGUN_2 => decoded.decode_sho_2(data)?,
_ => return Err(RLibError::DecodingUnsupportedGameSelected(game_info.key().to_string())),
}
check_size_mismatch(data.stream_position()? as usize, data_len as usize)?;
Ok(decoded)
}
}
impl Encodeable for GroupFormations {
fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
let extra_data = extra_data.as_ref().ok_or(RLibError::EncodingMissingExtraData)?;
let game_info = extra_data.game_info.ok_or_else(|| RLibError::DecodingMissingExtraDataField("game_info".to_owned()))?;
match game_info.key() {
KEY_ROME_2 => self.encode_rom_2(buffer)?,
KEY_SHOGUN_2 => self.encode_sho_2(buffer)?,
_ => return Err(RLibError::DecodingUnsupportedGameSelected(game_info.key().to_string())),
};
Ok(())
}
}