freenukum/actor/
hostileshot.rs1use 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}