361 lines
10 KiB
Rust
361 lines
10 KiB
Rust
use bevy_ecs::prelude::*;
|
|
|
|
pub use crate::entity_registry::EntityInfo;
|
|
pub use crate::passives::{DrugCooldown, Education, FactionUpgrades, Merits};
|
|
pub use crate::player::PlayerStrategy;
|
|
use crate::weapon::Japanese;
|
|
pub use crate::weapon::{bonus::WeaponBonus, temp::Temp, WeaponCategory, WeaponMod, WeaponSlot};
|
|
use crate::{
|
|
armour::EquippedArmour,
|
|
passives::PassiveBundle,
|
|
player::PlayerBundle,
|
|
weapon::{AmmoWeaponBundle, DamagingWeaponBundle, WeaponBundle, WeaponVerb},
|
|
};
|
|
use crate::{
|
|
armour::{ArmourBundle, Immunities, Immunity, Set},
|
|
weapon::bonus::WeaponBonusBundle,
|
|
};
|
|
use crate::{
|
|
hierarchy::HierarchyBuilder,
|
|
player::stats::{Defence, Dexterity, Speed, StatBundle, Strength},
|
|
};
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
pub struct Stats {
|
|
pub str: f32,
|
|
pub def: f32,
|
|
pub spd: f32,
|
|
pub dex: f32,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
pub struct WeaponAmmo {
|
|
pub clips: u16,
|
|
pub clip_size: u16,
|
|
pub rate_of_fire: [u16; 2],
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
pub struct WeaponBonusInfo {
|
|
pub bonus: WeaponBonus,
|
|
pub value: f32,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
pub struct Weapon {
|
|
pub name: String,
|
|
pub cat: WeaponCategory,
|
|
pub dmg: f32,
|
|
pub acc: f32,
|
|
pub ammo: WeaponAmmo,
|
|
pub mods: Vec<WeaponMod>,
|
|
pub bonuses: Vec<WeaponBonusInfo>,
|
|
pub experience: f32,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
pub struct MeleeWeapon {
|
|
pub name: String,
|
|
pub cat: WeaponCategory,
|
|
pub japanese: bool,
|
|
pub dmg: f32,
|
|
pub acc: f32,
|
|
pub bonuses: Vec<WeaponBonusInfo>,
|
|
pub experience: f32,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
#[derive(Default)]
|
|
pub struct Weapons {
|
|
pub primary: Option<Weapon>,
|
|
pub secondary: Option<Weapon>,
|
|
pub melee: Option<MeleeWeapon>,
|
|
pub temp: Option<Temp>,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
#[derive(Default)]
|
|
pub struct Armour {
|
|
pub armour_value: f32,
|
|
pub name: String,
|
|
pub coverage: [f32; 10],
|
|
pub immunities: Vec<Immunity>,
|
|
pub set: Option<Set>,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
#[derive(Default)]
|
|
pub struct ArmourPieces {
|
|
pub helmet: Option<Armour>,
|
|
pub body: Option<Armour>,
|
|
pub pants: Option<Armour>,
|
|
pub gloves: Option<Armour>,
|
|
pub boots: Option<Armour>,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Deserialize))]
|
|
pub struct Player {
|
|
pub name: String,
|
|
pub id: usize,
|
|
pub level: u16,
|
|
pub stats: Stats,
|
|
pub merits: Option<Merits>,
|
|
pub education: Option<Education>,
|
|
pub weapons: Weapons,
|
|
pub armour: ArmourPieces,
|
|
pub faction: Option<FactionUpgrades>,
|
|
pub drug: Option<DrugCooldown>,
|
|
pub strategy: PlayerStrategy,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Serialize))]
|
|
#[derive(Debug)]
|
|
pub struct Counter {
|
|
pub value: u64,
|
|
pub entity: EntityInfo,
|
|
pub label: &'static str,
|
|
}
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Serialize))]
|
|
#[derive(Debug)]
|
|
pub struct Histogram {
|
|
pub values: Vec<u32>,
|
|
pub entity: EntityInfo,
|
|
pub label: &'static str,
|
|
}
|
|
|
|
impl Player {
|
|
pub(crate) fn spawn(self, world: &mut World) -> EntityWorldMut<'_> {
|
|
let primary = self.weapons.primary.map(|w| {
|
|
let primary = world
|
|
.spawn((
|
|
WeaponBundle::new(
|
|
w.name,
|
|
self.id * 100 + 3,
|
|
WeaponVerb::Fired,
|
|
WeaponSlot::Primary,
|
|
),
|
|
DamagingWeaponBundle::new(w.dmg, w.acc, w.mods, w.experience, w.cat),
|
|
AmmoWeaponBundle::new(w.ammo.clips, w.ammo.clip_size, w.ammo.rate_of_fire),
|
|
))
|
|
.id();
|
|
|
|
if !w.bonuses.is_empty() {
|
|
for bonus in w.bonuses {
|
|
world
|
|
.spawn(WeaponBonusBundle::new(bonus.bonus, bonus.value))
|
|
.set_parent(primary);
|
|
}
|
|
}
|
|
|
|
primary
|
|
});
|
|
|
|
let secondary = self.weapons.secondary.map(|w| {
|
|
let secondary = world
|
|
.spawn((
|
|
WeaponBundle::new(
|
|
w.name,
|
|
self.id * 100 + 4,
|
|
WeaponVerb::Fired,
|
|
WeaponSlot::Secondary,
|
|
),
|
|
DamagingWeaponBundle::new(w.dmg, w.acc, w.mods, w.experience, w.cat),
|
|
AmmoWeaponBundle::new(w.ammo.clips, w.ammo.clip_size, w.ammo.rate_of_fire),
|
|
))
|
|
.id();
|
|
|
|
if !w.bonuses.is_empty() {
|
|
for bonus in w.bonuses {
|
|
world
|
|
.spawn(WeaponBonusBundle::new(bonus.bonus, bonus.value))
|
|
.set_parent(secondary);
|
|
}
|
|
}
|
|
|
|
secondary
|
|
});
|
|
|
|
let melee = self.weapons.melee.map(|w| {
|
|
let mut melee = world.spawn((
|
|
WeaponBundle::new(
|
|
w.name,
|
|
self.id * 100 + 5,
|
|
WeaponVerb::Hit,
|
|
WeaponSlot::Melee,
|
|
),
|
|
DamagingWeaponBundle::new(w.dmg, w.acc, Vec::default(), w.experience, w.cat),
|
|
));
|
|
if w.japanese {
|
|
melee.insert(Japanese);
|
|
}
|
|
let melee = melee.id();
|
|
|
|
if !w.bonuses.is_empty() {
|
|
for bonus in w.bonuses {
|
|
world
|
|
.spawn(WeaponBonusBundle::new(bonus.bonus, bonus.value))
|
|
.set_parent(melee);
|
|
}
|
|
}
|
|
|
|
melee
|
|
});
|
|
|
|
let temporary = self
|
|
.weapons
|
|
.temp
|
|
.map(|t| t.spawn(world, self.id * 100 + 2).id());
|
|
|
|
let fists = world
|
|
.spawn((
|
|
WeaponBundle::fists(self.id * 100),
|
|
DamagingWeaponBundle::fists(),
|
|
))
|
|
.id();
|
|
|
|
let kick = world
|
|
.spawn((
|
|
WeaponBundle::kick(self.id * 100 + 1),
|
|
DamagingWeaponBundle::kick(),
|
|
))
|
|
.id();
|
|
|
|
let weapons = crate::player::Weapons {
|
|
primary,
|
|
secondary,
|
|
melee,
|
|
temporary,
|
|
fists: Some(fists),
|
|
kick: Some(kick),
|
|
};
|
|
|
|
let helmet = self.armour.helmet.map(|h| {
|
|
let mut helmet = world.spawn(ArmourBundle::new(h.name, h.coverage, h.armour_value));
|
|
if let Some(set) = h.set {
|
|
helmet.insert(set);
|
|
}
|
|
if !h.immunities.is_empty() {
|
|
helmet.insert(Immunities(h.immunities));
|
|
}
|
|
helmet.id()
|
|
});
|
|
|
|
let body = self.armour.body.map(|b| {
|
|
let mut body = world.spawn(ArmourBundle::new(b.name, b.coverage, b.armour_value));
|
|
if let Some(set) = b.set {
|
|
body.insert(set);
|
|
}
|
|
body.id()
|
|
});
|
|
|
|
let pants = self.armour.pants.map(|p| {
|
|
let mut pants = world.spawn(ArmourBundle::new(p.name, p.coverage, p.armour_value));
|
|
if let Some(set) = p.set {
|
|
pants.insert(set);
|
|
}
|
|
pants.id()
|
|
});
|
|
|
|
let gloves = self.armour.gloves.map(|g| {
|
|
let mut gloves = world.spawn(ArmourBundle::new(g.name, g.coverage, g.armour_value));
|
|
if let Some(set) = g.set {
|
|
gloves.insert(set);
|
|
}
|
|
gloves.id()
|
|
});
|
|
|
|
let boots = self.armour.boots.map(|b| {
|
|
let mut boots = world.spawn(ArmourBundle::new(b.name, b.coverage, b.armour_value));
|
|
if let Some(set) = b.set {
|
|
boots.insert(set);
|
|
}
|
|
boots.id()
|
|
});
|
|
|
|
let armour = EquippedArmour {
|
|
head: helmet,
|
|
body,
|
|
legs: pants,
|
|
hands: gloves,
|
|
feet: boots,
|
|
};
|
|
|
|
let mut player = world.spawn((
|
|
PlayerBundle::new(self.name, self.id, self.level, self.strategy),
|
|
StatBundle::<Strength>::new(self.stats.str),
|
|
StatBundle::<Defence>::new(self.stats.def),
|
|
StatBundle::<Speed>::new(self.stats.spd),
|
|
StatBundle::<Dexterity>::new(self.stats.dex),
|
|
weapons,
|
|
armour,
|
|
PassiveBundle {
|
|
merits: self.merits.unwrap_or_default(),
|
|
education: self.education.unwrap_or_default(),
|
|
faction: self.faction.unwrap_or_default(),
|
|
},
|
|
));
|
|
|
|
if let Some(drug) = self.drug {
|
|
player.insert(drug);
|
|
}
|
|
|
|
player
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_spawn_player() {
|
|
let mut world = World::new();
|
|
|
|
let player = Player {
|
|
name: "Test".to_owned(),
|
|
id: 0,
|
|
level: 10,
|
|
stats: Stats {
|
|
str: 10.0,
|
|
def: 10.0,
|
|
spd: 10.0,
|
|
dex: 10.0,
|
|
},
|
|
merits: Default::default(),
|
|
education: Default::default(),
|
|
faction: Default::default(),
|
|
drug: None,
|
|
strategy: PlayerStrategy::AlwaysFists,
|
|
weapons: Weapons {
|
|
primary: Some(Weapon {
|
|
name: "Test".to_owned(),
|
|
cat: WeaponCategory::Rifle,
|
|
dmg: 50.0,
|
|
acc: 50.0,
|
|
ammo: WeaponAmmo {
|
|
clips: 3,
|
|
clip_size: 25,
|
|
rate_of_fire: [3, 5],
|
|
},
|
|
mods: Vec::default(),
|
|
bonuses: Vec::default(),
|
|
experience: 100.0,
|
|
}),
|
|
..Default::default()
|
|
},
|
|
armour: ArmourPieces {
|
|
helmet: Some(Armour {
|
|
name: "Test".to_owned(),
|
|
armour_value: 50.0,
|
|
coverage: [0.0, 0.0, 0.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0],
|
|
immunities: Vec::default(),
|
|
set: None,
|
|
}),
|
|
..Default::default()
|
|
},
|
|
};
|
|
|
|
player.spawn(&mut world);
|
|
}
|
|
}
|