//! Walls, solid barriers that are generally unscaleable. //! //! This interpretation is generally up to the GM to decide, but generally speaking, a wall cannot be //! crossed by a player. If special conditions apply (for instance, when the player wants to scale the //! wall), a check is necessary. If a check is not necessary, then maybe you were not thinking about //! a wall. use super::Mappable; use crate::colours::DEFAULT_COLOURS; use crate::math::{LineSegment, Rect, Vec2}; use crate::transform::Transform; use crate::transformable::NonRigidTransformable; use nalgebra::Matrix3; use raylib::drawing::{RaylibDraw, RaylibDrawHandle}; use std::ops::{Deref, DerefMut}; /// The data which defines a wall segment completely for serialisation. pub type WallData = LineSegment; /// A solid wall a player cannot go through, except if special conditions apply. pub struct Wall { data: WallData, selected: bool, round_start: bool, round_end: bool, } impl Wall { /// Create a new wall from the deserialised data and information known from internal sources. pub fn from_data(data: WallData, round_start: bool, round_end: bool) -> Self { Self { data, selected: false, round_start, round_end, } } /// Get the internal data for serialisation pub fn data(&self) -> &WallData { &self.data } } fn draw_round_corner( rld: &mut RaylibDrawHandle, pos_px: Vec2, transform: &Transform, selected: bool, ) { rld.draw_circle_v( pos_px, transform.length_m_to_px(0.05) as f32, if selected { DEFAULT_COLOURS.wall_selected } else { DEFAULT_COLOURS.wall_normal }, ); } impl Mappable for Wall { fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { let start_px = transform.point_m_to_px(&self.data.start); let end_px = transform.point_m_to_px(&self.data.end); rld.draw_line_ex( start_px, end_px, transform.length_m_to_px(0.1) as f32, if self.selected() { DEFAULT_COLOURS.wall_selected } else { DEFAULT_COLOURS.wall_normal }, ); if self.round_start { draw_round_corner(rld, start_px, transform, self.selected()); } if self.round_end { draw_round_corner(rld, end_px, transform, self.selected()); } } fn set_selected(&mut self, selected: bool) { self.selected = selected; } fn selected(&self) -> bool { self.selected } fn bounding_rect(&self) -> Rect { Rect::bounding_rect(self.data.start, self.data.end) } fn as_non_rigid(&self) -> Option<&dyn NonRigidTransformable> { Some(self as &dyn NonRigidTransformable) } fn as_non_rigid_mut(&mut self) -> Option<&mut dyn NonRigidTransformable> { Some(self as &mut dyn NonRigidTransformable) } } impl NonRigidTransformable for Wall { fn apply_matrix(&mut self, matrix: &Matrix3) { self.data.start = matrix.transform_point(&self.data.start.into()).into(); self.data.end = matrix.transform_point(&self.data.end.into()).into(); } } impl Deref for Wall { type Target = WallData; fn deref(&self) -> &Self::Target { &self.data } } impl DerefMut for Wall { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data } }