earthbound-battle-backgrounds 0.1.0

Emulate and render the battle backgrounds from EarthBound / Mother 2.
Documentation
use crate::rom;

// In the ROM, each battle background struct at 0xADEA1 takes up 17 bytes.
const STRUCT_SIZE: usize = 17;

#[derive(Debug)]
pub struct BattleBackground {
    bbg_data: Vec<i16>,
}

impl BattleBackground {
    // Background data table: $CADCA1
    // 17 bytes per entry:
    //
    // 0 Graphics/Arrangement index
    // 1 Palette
    // 2 Bits per pixel
    // 3 Palette cycle type
    // 4 Palette cycle #1 start
    // 5 Palette cycle #1 end
    // 6 Palette cycle #2 start
    // 7 Palette cycle #2 end
    // 8 Palette cycle speed
    // 9 Mov
    // 10 Mov
    // 11 Mov
    // 12 Mov
    // 13 Effects
    // 14 Effects
    // 15 Effects
    // 16 Effects
    pub fn new(i: usize) -> Self {
        let mut bbg = BattleBackground {
            bbg_data: vec![0i16; STRUCT_SIZE],
        };

        bbg.read(i);

        bbg
    }

    /// Index of the compresses graphics/arrangment to use for this
    pub fn graphics_index(&self) -> usize {
        self.bbg_data[0] as usize
    }

    /// Index of the background Palette to use.
    pub fn palette_index(&self) -> usize {
        self.bbg_data[1] as usize
    }

    /// Must always be 2 or 4.
    pub fn bits_per_pixel(&self) -> u8 {
        self.bbg_data[2] as u8
    }

    /// Which kind of palette cycle to use.
    pub fn palette_cycle_type(&self) -> i16 {
        self.bbg_data[3]
    }

    /// Cycle 1 start index
    pub fn palette_cycle_1_start(&self) -> usize {
        self.bbg_data[4] as usize
    }

    /// Cycle 1 end index
    pub fn palette_cycle_1_end(&self) -> usize {
        self.bbg_data[5] as usize
    }

    /// Cycle 2 start index
    pub fn palette_cycle_2_start(&self) -> usize {
        self.bbg_data[6] as usize
    }

    /// Cycle 2 end index
    pub fn palette_cycle_2_end(&self) -> usize {
        self.bbg_data[7] as usize
    }

    /// Determines the animation speed of the palette cycle in frames the animation is held. (i.e.
    /// 3 = palette changes every 3 frames, 60 = palette changes every 60 frames).
    pub fn palette_cycle_speed(&self) -> i16 {
        self.bbg_data[8]
    }

    // TODO: Implement these!
    #[allow(unused)]
    pub fn horizontal_movement(&self) -> i16 {
        self.bbg_data[9]
    }

    #[allow(unused)]
    pub fn vertical_movement(&self) -> i16 {
        self.bbg_data[10]
    }

    #[allow(unused)]
    pub fn horizontal_acceleration(&self) -> i16 {
        self.bbg_data[11]
    }

    #[allow(unused)]
    pub fn vertical_acceleration(&self) -> i16 {
        self.bbg_data[12]
    }

    /// Bytes 13-16 of BG data in big-endian order. Exact function unknown; related to background
    /// animation effects.
    pub fn animation(&self) -> u32 {
        ((self.bbg_data[13] as u32) << 24)
            + ((self.bbg_data[14] as u32) << 16)
            + ((self.bbg_data[15] as u32) << 8)
            + (self.bbg_data[16] as u32)
    }

    fn read(&mut self, index: usize) {
        let mut main = rom::read_block(0xDCA1 + index * STRUCT_SIZE);
        for i in 0..STRUCT_SIZE {
            self.bbg_data[i] = main.read_int16();
        }
    }
}