freenukum/actor/
hostileshot.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// SPDX-FileCopyrightText: Wolfgang Silbermayr <wolfgang@silbermayr.at>
3
4use crate::{
5    actor::{
6        ActParameters, Actor, ActorExt, CreateActorWithDetails,
7        RenderParameters,
8    },
9    level::tiles::LevelTiles,
10    Hero, HorizontalDirection, RangedIterator, Result, Sizes,
11    OBJECT_HOSTILESHOT,
12};
13use sdl2::rect::{Point, Rect};
14
15#[derive(Debug)]
16pub(crate) struct HostileShot {
17    tile: usize,
18    frame: RangedIterator,
19    position: Rect,
20    is_alive: bool,
21    direction: HorizontalDirection,
22}
23
24impl CreateActorWithDetails for HostileShot {
25    type Details = HorizontalDirection;
26
27    fn create_with_details(
28        direction: HorizontalDirection,
29        pos: Point,
30        sizes: &dyn Sizes,
31        _tiles: &mut LevelTiles,
32    ) -> Actor {
33        let tile = match direction {
34            HorizontalDirection::Left => OBJECT_HOSTILESHOT,
35            HorizontalDirection::Right => OBJECT_HOSTILESHOT + 2,
36        };
37
38        Actor::HostileShot(Self {
39            tile,
40            frame: RangedIterator::new(2),
41            position: Rect::new(
42                pos.x,
43                pos.y,
44                sizes.width(),
45                sizes.height(),
46            ),
47            is_alive: true,
48            direction,
49        })
50    }
51}
52
53impl ActorExt for HostileShot {
54    fn act(&mut self, p: ActParameters) {
55        let offset =
56            (p.sizes.width() as i32) * self.direction.as_factor_i32();
57        self.position.offset(offset, 0);
58
59        self.is_alive = p
60            .tiles
61            .get(
62                self.position.x() / p.sizes.width() as i32,
63                self.position.y() / p.sizes.height() as i32,
64            )
65            .map(|t| !t.solid)
66            .unwrap_or(false);
67
68        self.frame.next();
69    }
70
71    fn render(&mut self, p: RenderParameters) -> Result<()> {
72        p.renderer.place_tile(
73            self.tile + self.frame.current(),
74            self.position.top_left(),
75        )?;
76        Ok(())
77    }
78
79    fn position(&self) -> Rect {
80        self.position
81    }
82
83    fn is_in_foreground(&self) -> bool {
84        true
85    }
86
87    fn hurts_hero(&self, hero: &Hero) -> bool {
88        self.position.has_intersection(hero.position.geometry)
89    }
90
91    fn is_alive(&self) -> bool {
92        self.is_alive
93    }
94
95    fn acts_while_invisible(&self) -> bool {
96        true
97    }
98}