freenukum 0.4.0

A clone of the 1991 DOS game Duke Nukem 1
Documentation
// SPDX-License-Identifier: AGPL-3.0-or-later
// SPDX-FileCopyrightText: Wolfgang Silbermayr <wolfgang@silbermayr.at>

use crate::{
    actor::{
        ActParameters, Actor, ActorExt, CreateActorWithDetails,
        RenderParameters,
    },
    level::tiles::LevelTiles,
    RangedIterator, Result, Sizes, ANIMATION_BROKENWALLBG,
    ANIMATION_STONEWINDOWBG, ANIMATION_WINDOWBG,
};
use sdl2::rect::{Point, Rect};

#[derive(Debug)]
pub(crate) struct BackgroundAnimation {
    tile: usize,
    frame: RangedIterator,
    position: Rect,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BackgroundAnimationType {
    TextOnScreen,
    HighVoltageFlash,
    RedFlashlight,
    BlueFlashlight,
    Keypanel,
    RedRotationLight,
    UpArrow,
    BlueLight1,
    BlueLight2,
    BlueLight3,
    BlueLight4,
    GreenPoison,
    Lava,
    WindowLeft,
    WindowRight,
    StoneWindow,
    BrokenWall,
}

impl BackgroundAnimationType {
    fn tile_and_num_frames(&self) -> (usize, usize) {
        match self {
            BackgroundAnimationType::TextOnScreen => (0x0004, 4),
            BackgroundAnimationType::HighVoltageFlash => (0x0008, 4),
            BackgroundAnimationType::RedFlashlight => (0x000C, 4),
            BackgroundAnimationType::BlueFlashlight => (0x0010, 4),
            BackgroundAnimationType::Keypanel => (0x0014, 4),
            BackgroundAnimationType::RedRotationLight => (0x0018, 4),
            BackgroundAnimationType::UpArrow => (0x001C, 4),
            BackgroundAnimationType::BlueLight1 => (0x0020, 4),
            BackgroundAnimationType::BlueLight2 => (0x0021, 4),
            BackgroundAnimationType::BlueLight3 => (0x0022, 4),
            BackgroundAnimationType::BlueLight4 => (0x0023, 4),
            BackgroundAnimationType::GreenPoison => (0x0028, 4),
            BackgroundAnimationType::Lava => (0x002C, 4),
            BackgroundAnimationType::WindowLeft => (ANIMATION_WINDOWBG, 1),
            BackgroundAnimationType::WindowRight => {
                (ANIMATION_WINDOWBG + 1, 1)
            }
            BackgroundAnimationType::StoneWindow => {
                (ANIMATION_STONEWINDOWBG, 1)
            }
            BackgroundAnimationType::BrokenWall => {
                (ANIMATION_BROKENWALLBG, 1)
            }
        }
    }
}

impl CreateActorWithDetails for BackgroundAnimation {
    type Details = BackgroundAnimationType;

    fn create_with_details(
        animation_type: BackgroundAnimationType,
        pos: Point,
        sizes: &dyn Sizes,
        _tiles: &mut LevelTiles,
    ) -> Actor {
        let (tile, num_frames) = animation_type.tile_and_num_frames();

        Actor::BackgroundAnimation(Self {
            tile,
            frame: RangedIterator::new(num_frames),
            position: Rect::new(
                pos.x,
                pos.y,
                sizes.width(),
                sizes.height(),
            ),
        })
    }
}

impl ActorExt for BackgroundAnimation {
    fn act(&mut self, _p: ActParameters) {
        self.frame.next();
    }

    fn render(&mut self, p: RenderParameters) -> Result<()> {
        p.renderer.place_tile(
            self.tile + self.frame.current(),
            self.position.top_left(),
        )?;
        Ok(())
    }

    fn position(&self) -> Rect {
        self.position
    }

    fn is_in_foreground(&self) -> bool {
        false
    }
}