1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! A reader, writer, and converter for all versions of Age of Empires scenarios.
//!
//! This crate aims to support every single scenario that exists. If a scenario file from any Age
//! of Empires 1 or Age of Empires 2 version does not work, please upload it and file an issue!
mod format;
mod triggers;
mod util;
mod types;
pub mod convert;

use std::io::{Result, Read, Write};
use format::{
    SCXFormat,
};

pub use types::*;
pub use format::{
    DLCOptions,
    Tile,
    SCXHeader,
    Map,
    ScenarioObject,
};
pub use triggers::{
    TriggerSystem,
    Trigger,
    TriggerCondition,
    TriggerEffect,
};

/// A Scenario file.
pub struct Scenario {
    format: SCXFormat,
    version: VersionBundle,
}

impl Scenario {
    /// Read a scenario file.
    pub fn from<R: Read>(input: &mut R) -> Result<Self> {
        let format = SCXFormat::load_scenario(input)?;
        let version = format.version();

        Ok(Self { format, version })
    }

    pub fn write_to<W: Write>(&self, output: &mut W) -> Result<()> {
        self.format.write_to(output, self.version())
    }

    pub fn write_to_version<W: Write>(&self, output: &mut W, version: &VersionBundle) -> Result<()> {
        self.format.write_to(output, version)
    }

    /// Get the format version of this SCX file.
    pub fn format_version(&self) -> SCXVersion {
        self.version().format
    }

    /// Get the header version for this SCX file.
    pub fn header_version(&self) -> u32 {
        self.version().header
    }

    /// Get the data version for this SCX file.
    pub fn data_version(&self) -> f32 {
        self.version().data
    }

    /// Get the header.
    pub fn header(&self) -> &SCXHeader {
        &self.format.header
    }

    /// Get the scenario description.
    pub fn description(&self) -> Option<&str> {
        self.format.tribe_scen.description()
    }

    /// Get the scenario filename.
    pub fn filename(&self) -> &str {
        &self.format.tribe_scen.base.name
    }

    pub fn version(&self) -> &VersionBundle {
        &self.version
    }

    pub fn requires_dlc(&self, dlc: DLCPackage) -> bool {
        match &self.header().dlc_options {
            Some(options) => options.dependencies.iter().any(|dep| *dep == dlc),
            None => false,
        }
    }

    pub fn objects(&self) -> impl Iterator<Item = &ScenarioObject> {
        self.format.player_objects.iter()
            .map(|list| list.iter())
            .flatten()
    }

    pub fn objects_mut(&mut self) -> impl Iterator<Item = &mut ScenarioObject> {
        self.format.player_objects.iter_mut()
            .map(|list| list.iter_mut())
            .flatten()
    }

    pub fn map(&self) -> &Map {
        &self.format.map
    }

    pub fn map_mut(&mut self) -> &mut Map {
        &mut self.format.map
    }

    pub fn triggers(&self) -> Option<&TriggerSystem> {
        self.format.triggers.as_ref()
    }

    pub fn triggers_mut(&mut self) -> Option<&mut TriggerSystem> {
        self.format.triggers.as_mut()
    }
}