use std::{
fmt::Display,
mem::MaybeUninit,
ops::{Add, Sub},
};
use packo::*;
const CAT_INVENTORY: usize = 0;
const CAT_SPELLS: usize = 1;
pub type Entities = Packo<256, Entity, 2, u8>;
#[derive(Clone, Copy, Default)]
#[repr(C)]
pub enum Component {
#[default]
None = 0,
Spatial = 1 << 0,
Player = 1 << 1,
Life = 1 << 2,
Damage = 1 << 3,
Cost = 1 << 4,
Consume = 1 << 5,
}
const ALL_COMPONENTS: [Component; 6] = [
Component::Spatial,
Component::Player,
Component::Life,
Component::Damage,
Component::Cost,
Component::Consume,
];
impl Add for Component {
type Output = Components;
fn add(self, rhs: Self) -> Self::Output {
#[allow(clippy::suspicious_arithmetic_impl)]
Components(self as u8 | rhs as u8)
}
}
#[derive(Debug, Default)]
pub struct Components(u8);
impl Components {
pub fn has(&self, t: Component) -> bool {
self.0 & t as u8 > 0
}
pub fn add(&mut self, t: Component) {
self.0 |= t as u8;
}
pub fn rem(&mut self, t: Component) {
self.0 &= !(t as u8);
}
}
impl From<Component> for Components {
fn from(value: Component) -> Self {
Components(value as u8)
}
}
impl Add for Components {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
#[allow(clippy::suspicious_arithmetic_impl)]
Components(self.0 | rhs.0)
}
}
impl Sub for Components {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
#[allow(clippy::suspicious_arithmetic_impl)]
Components(self.0 & !rhs.0)
}
}
pub type VX = f32;
#[derive(Debug)]
pub struct Vec<const S: usize, T = VX>([T; S]);
impl<const S: usize, T> Default for Vec<S, T> {
fn default() -> Self {
Self(unsafe { MaybeUninit::zeroed().assume_init() })
}
}
pub type Vec2i = Vec<2, u8>;
pub type Vec2 = Vec<2>;
pub type Vec3 = Vec<3>;
pub type Vec4 = Vec<4>;
#[derive(Debug, Default)]
pub struct Spatial {
pub pos: Vec2i,
}
#[derive(Debug, Default)]
pub struct Entity {
pub id: u8,
pub components: Components,
pub spatial: Spatial,
pub life: u8,
pub damage: u8,
pub cost: u8,
}
impl Display for Entity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ID:{}//", self.id)?;
for c in ALL_COMPONENTS {
if self.components.has(c) {
match c {
Component::Spatial => write!(
f,
"POS:{},{}//",
self.spatial.pos.0[0],
self.spatial.pos.0[1],
)?,
Component::Player => f.write_str("Player//")?,
Component::Life => write!(f, "Life:{}//", self.life)?,
Component::Damage => write!(f, "Damage:{}//", self.damage)?,
Component::Cost => write!(f, "Cost:{}//", self.cost)?,
Component::Consume => write!(f, "Consumable//")?,
_ => {}
};
}
}
Ok(())
}
}
fn game_reset(e: &mut Entities) -> u8 {
e.reset();
let p = e.insert(Entity {
components: Component::Player + Component::Spatial + Component::Life.into(),
life: 100,
..Default::default()
});
e[p].id = p;
let potion = e.nestc(
p,
CAT_INVENTORY,
Entity {
components: Component::Life + Component::Consume,
life: 50,
..Default::default()
},
);
e[potion].id = potion;
let firebolt = e.nestc(
p,
CAT_SPELLS,
Entity {
components: Component::Damage + Component::Cost,
damage: 10,
cost: 5,
..Default::default()
},
);
e[firebolt].id = firebolt;
let heal = e.nestc(
p,
CAT_SPELLS,
Entity {
components: Component::Life + Component::Cost,
life: 10,
cost: 5,
..Default::default()
},
);
e[heal].id = heal;
p
}
fn main() {
let mut e = Entities::default();
let p = game_reset(&mut e);
println!("Player: {}", e[p]);
for e in e.childsc(p, CAT_INVENTORY) {
println!("Item: {e}");
}
for e in e.childsc(p, CAT_SPELLS) {
println!("Spell: {e}");
}
println!("{e}");
}