diff --git a/assets/common/npc_names.json b/assets/common/npc_names.json index bced2a7ad1..88b237ac4d 100644 --- a/assets/common/npc_names.json +++ b/assets/common/npc_names.json @@ -539,5 +539,19 @@ "generic": "Fungome" } } + }, + "dragon": { + "body": { + "keyword": "dragon", + "names": [ + "Smaug" + ] + }, + "species": { + "reddragon": { + "keyword": "reddragon", + "generic": "Reddragon" + } + } } } diff --git a/assets/voxygen/voxel/dragon_center_manifest.ron b/assets/voxygen/voxel/dragon_center_manifest.ron new file mode 100644 index 0000000000..a4f492c4e1 --- /dev/null +++ b/assets/voxygen/voxel/dragon_center_manifest.ron @@ -0,0 +1,46 @@ +({ + (Reddragon, Male): ( + head: ( + offset: (-7.0, -9.0, -5.5), + center: ("npc.reddragon.male.head"), + ), + chest_front: ( + offset: (-7.0, 4.5, 5.0), + center: ("npc.reddragon.male.chest_front"), + ), + chest_rear: ( + offset: (-7.0, -4.5, 5.0), + center: ("npc.reddragon.male.chest_rear"), + ), + tail_front: ( + offset: (-7.0, -4.5, -5.0), + center: ("npc.reddragon.male.tail_front"), + ), + tail_rear: ( + offset: (-7.0, -4.5, -5.0), + center: ("npc.reddragon.male.tail_rear"), + ) + ), + (Reddragon, Female): ( + head: ( + offset: (-7.0, -9.0, -5.5), + center: ("npc.reddragon.female.head"), + ), + chest_front: ( + offset: (-7.0, 4.5, 5.0), + center: ("npc.reddragon.female.chest_front"), + ), + chest_rear: ( + offset: (-7.0, -4.5, 5.0), + center: ("npc.reddragon.female.chest_rear"), + ), + tail_front: ( + offset: (-7.0, -4.5, -5.0), + center: ("npc.reddragon.female.tail_front"), + ), + tail_rear: ( + offset: (-7.0, -4.5, -5.0), + center: ("npc.reddragon.female.tail_rear"), + ) + ), +}) diff --git a/assets/voxygen/voxel/dragon_lateral_manifest.ron b/assets/voxygen/voxel/dragon_lateral_manifest.ron new file mode 100644 index 0000000000..d9e64fb684 --- /dev/null +++ b/assets/voxygen/voxel/dragon_lateral_manifest.ron @@ -0,0 +1,70 @@ +({ + (Reddragon, Male): ( + wing_in_l: ( + offset: (20.0, 20.0, 5.0), + lateral: ("npc.reddragon.male.wing_in_l"), + ), + wing_in_r: ( + offset: (20.0, 20.0, 5.0), + lateral: ("npc.reddragon.male.wing_in_r"), + ), + wing_out_l: ( + offset: (20.0, 20.0, 5.0), + lateral: ("npc.reddragon.male.wing_out_l"), + ), + wing_out_r: ( + offset: (20.0, 20.0, 5.0), + lateral: ("npc.reddragon.male.wing_out_r"), + ), + foot_fl: ( + offset: (-2.5, -4.0, -1.5), + lateral: ("npc.reddragon.male.foot_fl"), + ), + foot_fr: ( + offset: (-2.5, -4.0, -1.5), + lateral: ("npc.reddragon.male.foot_fr"), + ), + foot_bl: ( + offset: (-2.5, -4.0, -3.0), + lateral: ("npc.reddragon.male.foot_bl"), + ), + foot_br: ( + offset: (-2.5, -4.0, -3.0), + lateral: ("npc.reddragon.male.foot_br"), + ) + ), + (Reddragon, Female): ( + wing_in_l: ( + offset: (20.0, 20.0, 5.0), + lateral: ("npc.reddragon.female.wing_in_l"), + ), + wing_in_r: ( + offset: (20.0, 20.0, 5.0), + lateral: ("npc.reddragon.female.wing_in_r"), + ), + wing_out_l: ( + offset: (20.0, 20.0, 5.0), + lateral: ("npc.reddragon.female.wing_out_l"), + ), + wing_out_r: ( + offset: (20.0, 20.0, 5.0), + lateral: ("npc.reddragon.female.wing_out_r"), + ), + foot_fl: ( + offset: (-2.5, -4.0, -1.5), + lateral: ("npc.reddragon.female.foot_fl"), + ), + foot_fr: ( + offset: (-2.5, -4.0, -1.5), + lateral: ("npc.reddragon.female.foot_fr"), + ), + foot_bl: ( + offset: (-2.5, -4.0, -3.0), + lateral: ("npc.reddragon.female.foot_bl"), + ), + foot_br: ( + offset: (-2.5, -4.0, -3.0), + lateral: ("npc.reddragon.female.foot_br"), + ) + ), +}) \ No newline at end of file diff --git a/assets/voxygen/voxel/npc/dragon/wing_in_l.vox b/assets/voxygen/voxel/npc/dragon/wing_in_l.vox deleted file mode 100644 index 3d7e37036e..0000000000 Binary files a/assets/voxygen/voxel/npc/dragon/wing_in_l.vox and /dev/null differ diff --git a/assets/voxygen/voxel/npc/dragon/wing_in_r.vox b/assets/voxygen/voxel/npc/dragon/wing_in_r.vox deleted file mode 100644 index 249db770c8..0000000000 Binary files a/assets/voxygen/voxel/npc/dragon/wing_in_r.vox and /dev/null differ diff --git a/assets/voxygen/voxel/npc/dragon/wing_out_l.vox b/assets/voxygen/voxel/npc/dragon/wing_out_l.vox deleted file mode 100644 index f8b1875b49..0000000000 Binary files a/assets/voxygen/voxel/npc/dragon/wing_out_l.vox and /dev/null differ diff --git a/assets/voxygen/voxel/npc/dragon/wing_out_r.vox b/assets/voxygen/voxel/npc/dragon/wing_out_r.vox deleted file mode 100644 index 1690c8f95d..0000000000 Binary files a/assets/voxygen/voxel/npc/dragon/wing_out_r.vox and /dev/null differ diff --git a/assets/voxygen/voxel/npc/dragon/chest_front.vox b/assets/voxygen/voxel/npc/reddragon/female/chest_front.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/chest_front.vox rename to assets/voxygen/voxel/npc/reddragon/female/chest_front.vox diff --git a/assets/voxygen/voxel/npc/dragon/chest_rear.vox b/assets/voxygen/voxel/npc/reddragon/female/chest_rear.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/chest_rear.vox rename to assets/voxygen/voxel/npc/reddragon/female/chest_rear.vox diff --git a/assets/voxygen/voxel/npc/dragon/foot_bl.vox b/assets/voxygen/voxel/npc/reddragon/female/foot_bl.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/foot_bl.vox rename to assets/voxygen/voxel/npc/reddragon/female/foot_bl.vox diff --git a/assets/voxygen/voxel/npc/dragon/foot_br.vox b/assets/voxygen/voxel/npc/reddragon/female/foot_br.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/foot_br.vox rename to assets/voxygen/voxel/npc/reddragon/female/foot_br.vox diff --git a/assets/voxygen/voxel/npc/dragon/foot_fl.vox b/assets/voxygen/voxel/npc/reddragon/female/foot_fl.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/foot_fl.vox rename to assets/voxygen/voxel/npc/reddragon/female/foot_fl.vox diff --git a/assets/voxygen/voxel/npc/dragon/foot_fr.vox b/assets/voxygen/voxel/npc/reddragon/female/foot_fr.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/foot_fr.vox rename to assets/voxygen/voxel/npc/reddragon/female/foot_fr.vox diff --git a/assets/voxygen/voxel/npc/dragon/head.vox b/assets/voxygen/voxel/npc/reddragon/female/head.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/head.vox rename to assets/voxygen/voxel/npc/reddragon/female/head.vox diff --git a/assets/voxygen/voxel/npc/dragon/tail_front.vox b/assets/voxygen/voxel/npc/reddragon/female/tail_front.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/tail_front.vox rename to assets/voxygen/voxel/npc/reddragon/female/tail_front.vox diff --git a/assets/voxygen/voxel/npc/dragon/tail_rear.vox b/assets/voxygen/voxel/npc/reddragon/female/tail_rear.vox similarity index 100% rename from assets/voxygen/voxel/npc/dragon/tail_rear.vox rename to assets/voxygen/voxel/npc/reddragon/female/tail_rear.vox diff --git a/assets/voxygen/voxel/npc/reddragon/female/wing_in_l.vox b/assets/voxygen/voxel/npc/reddragon/female/wing_in_l.vox new file mode 100644 index 0000000000..4248691c50 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/female/wing_in_l.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/female/wing_in_r.vox b/assets/voxygen/voxel/npc/reddragon/female/wing_in_r.vox new file mode 100644 index 0000000000..10a75b0e8f Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/female/wing_in_r.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/female/wing_out_l.vox b/assets/voxygen/voxel/npc/reddragon/female/wing_out_l.vox new file mode 100644 index 0000000000..9a8a83f745 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/female/wing_out_l.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/female/wing_out_r.vox b/assets/voxygen/voxel/npc/reddragon/female/wing_out_r.vox new file mode 100644 index 0000000000..ed59f08f22 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/female/wing_out_r.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/chest_front.vox b/assets/voxygen/voxel/npc/reddragon/male/chest_front.vox new file mode 100644 index 0000000000..26f3dc5dc1 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/chest_front.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/chest_rear.vox b/assets/voxygen/voxel/npc/reddragon/male/chest_rear.vox new file mode 100644 index 0000000000..84114c625a Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/chest_rear.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/foot_bl.vox b/assets/voxygen/voxel/npc/reddragon/male/foot_bl.vox new file mode 100644 index 0000000000..fe7d64b1d7 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/foot_bl.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/foot_br.vox b/assets/voxygen/voxel/npc/reddragon/male/foot_br.vox new file mode 100644 index 0000000000..09d30e06b4 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/foot_br.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/foot_fl.vox b/assets/voxygen/voxel/npc/reddragon/male/foot_fl.vox new file mode 100644 index 0000000000..9d95cf5525 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/foot_fl.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/foot_fr.vox b/assets/voxygen/voxel/npc/reddragon/male/foot_fr.vox new file mode 100644 index 0000000000..d2988d546c Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/foot_fr.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/head.vox b/assets/voxygen/voxel/npc/reddragon/male/head.vox new file mode 100644 index 0000000000..0de9789f15 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/head.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/tail_front.vox b/assets/voxygen/voxel/npc/reddragon/male/tail_front.vox new file mode 100644 index 0000000000..7acfb83016 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/tail_front.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/tail_rear.vox b/assets/voxygen/voxel/npc/reddragon/male/tail_rear.vox new file mode 100644 index 0000000000..0d401ba908 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/tail_rear.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/wing_in_l.vox b/assets/voxygen/voxel/npc/reddragon/male/wing_in_l.vox new file mode 100644 index 0000000000..4248691c50 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/wing_in_l.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/wing_in_r.vox b/assets/voxygen/voxel/npc/reddragon/male/wing_in_r.vox new file mode 100644 index 0000000000..10a75b0e8f Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/wing_in_r.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/wing_out_l.vox b/assets/voxygen/voxel/npc/reddragon/male/wing_out_l.vox new file mode 100644 index 0000000000..9a8a83f745 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/wing_out_l.vox differ diff --git a/assets/voxygen/voxel/npc/reddragon/male/wing_out_r.vox b/assets/voxygen/voxel/npc/reddragon/male/wing_out_r.vox new file mode 100644 index 0000000000..ed59f08f22 Binary files /dev/null and b/assets/voxygen/voxel/npc/reddragon/male/wing_out_r.vox differ diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index 4545478126..a69cc9b961 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -60,6 +60,7 @@ pub struct AllBodies { pub biped_large: BodyData>, pub golem: BodyData>, pub critter: BodyData>, + pub dragon: BodyData>, } /// Can only retrieve body metadata by direct index. @@ -76,6 +77,7 @@ impl core::ops::Index for AllBodies &self.biped_large.body, NpcKind::StoneGolem => &self.golem.body, NpcKind::Rat => &self.critter.body, + NpcKind::Reddragon => &self.dragon.body, } } } diff --git a/common/src/comp/body/dragon.rs b/common/src/comp/body/dragon.rs index 94c23ce9b9..8591ba74e1 100644 --- a/common/src/comp/body/dragon.rs +++ b/common/src/comp/body/dragon.rs @@ -2,128 +2,69 @@ use rand::{seq::SliceRandom, thread_rng}; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Body { - pub head: Head, - pub chest_front: ChestFront, - pub chest_rear: ChestRear, - pub tail_front: TailFront, - pub tail_rear: TailRear, - pub wing_in_l: WingInL, - pub wing_in_r: WingInR, - pub wing_out_l: WingOutL, - pub wing_out_r: WingOutR, - pub foot_fl: FootFL, - pub foot_fr: FootFR, - pub foot_bl: FootBL, - pub foot_br: FootBR, + pub species: Species, + pub body_type: BodyType, } + impl Body { pub fn random() -> Self { let mut rng = thread_rng(); - Self { - head: *(&ALL_HEADS).choose(&mut rng).unwrap(), - chest_front: *(&ALL_CHEST_FRONTS).choose(&mut rng).unwrap(), - chest_rear: *(&ALL_CHEST_REARS).choose(&mut rng).unwrap(), - tail_front: *(&ALL_TAIL_FRONTS).choose(&mut rng).unwrap(), - tail_rear: *(&ALL_TAIL_REARS).choose(&mut rng).unwrap(), - wing_in_l: *(&ALL_WING_IN_LS).choose(&mut rng).unwrap(), - wing_in_r: *(&ALL_WING_IN_RS).choose(&mut rng).unwrap(), - wing_out_l: *(&ALL_WING_OUT_LS).choose(&mut rng).unwrap(), - wing_out_r: *(&ALL_WING_OUT_RS).choose(&mut rng).unwrap(), - foot_fl: *(&ALL_FOOT_FLS).choose(&mut rng).unwrap(), - foot_fr: *(&ALL_FOOT_FRS).choose(&mut rng).unwrap(), - foot_bl: *(&ALL_FOOT_BLS).choose(&mut rng).unwrap(), - foot_br: *(&ALL_FOOT_BRS).choose(&mut rng).unwrap(), + let species = *(&ALL_SPECIES).choose(&mut rng).unwrap(); + Self::random_with(&mut rng, &species) + } + + #[inline] + pub fn random_with(rng: &mut impl rand::Rng, &species: &Species) -> Self { + let body_type = *(&ALL_BODY_TYPES).choose(rng).unwrap(); + Self { species, body_type } + } +} + +impl From for super::Body { + fn from(body: Body) -> Self { super::Body::Dragon(body) } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[repr(u32)] +pub enum Species { + Reddragon = 0, +} + +/// Data representing per-species generic data. +/// +/// NOTE: Deliberately don't (yet?) implement serialize. +#[derive(Clone, Debug, Deserialize)] +pub struct AllSpecies { + pub reddragon: SpeciesMeta, +} + +impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies { + type Output = SpeciesMeta; + + #[inline] + fn index(&self, &index: &'a Species) -> &Self::Output { + match index { + Species::Reddragon => &self.reddragon, } } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum Head { - Default, +pub const ALL_SPECIES: [Species; 1] = [ + Species::Reddragon, +]; + +impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies { + type Item = Species; + + type IntoIter = impl Iterator; + + fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() } } -const ALL_HEADS: [Head; 1] = [Head::Default]; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[repr(u32)] -pub enum ChestFront { - Default, +pub enum BodyType { + Female = 0, + Male = 1, } -const ALL_CHEST_FRONTS: [ChestFront; 1] = [ChestFront::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum ChestRear { - Default, -} -const ALL_CHEST_REARS: [ChestRear; 1] = [ChestRear::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum TailFront { - Default, -} -const ALL_TAIL_FRONTS: [TailFront; 1] = [TailFront::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum TailRear { - Default, -} -const ALL_TAIL_REARS: [TailRear; 1] = [TailRear::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum WingInL { - Default, -} -const ALL_WING_IN_LS: [WingInL; 1] = [WingInL::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum WingInR { - Default, -} -const ALL_WING_IN_RS: [WingInR; 1] = [WingInR::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum WingOutL { - Default, -} -const ALL_WING_OUT_LS: [WingOutL; 1] = [WingOutL::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum WingOutR { - Default, -} -const ALL_WING_OUT_RS: [WingOutR; 1] = [WingOutR::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum FootFL { - Default, -} -const ALL_FOOT_FLS: [FootFL; 1] = [FootFL::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum FootFR { - Default, -} -const ALL_FOOT_FRS: [FootFR; 1] = [FootFR::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum FootBL { - Default, -} -const ALL_FOOT_BLS: [FootBL; 1] = [FootBL::Default]; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u32)] -pub enum FootBR { - Default, -} -const ALL_FOOT_BRS: [FootBR; 1] = [FootBR::Default]; +pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male]; diff --git a/common/src/generation.rs b/common/src/generation.rs index 22cf420021..15850ebb64 100644 --- a/common/src/generation.rs +++ b/common/src/generation.rs @@ -79,6 +79,9 @@ impl EntityInfo { Body::QuadrupedSmall(body) => { Some(get_npc_name(&NPC_NAMES.quadruped_small, body.species)) }, + Body::Dragon(body) => { + Some(get_npc_name(&NPC_NAMES.dragon, body.species)) + }, _ => None, } .map(|s| { diff --git a/common/src/npc.rs b/common/src/npc.rs index fc08070dea..97d42e9b43 100644 --- a/common/src/npc.rs +++ b/common/src/npc.rs @@ -15,9 +15,10 @@ pub enum NpcKind { Ogre, Rat, StoneGolem, + Reddragon, } -pub const ALL_NPCS: [NpcKind; 7] = [ +pub const ALL_NPCS: [NpcKind; 8] = [ NpcKind::Humanoid, NpcKind::Wolf, NpcKind::Pig, @@ -25,6 +26,7 @@ pub const ALL_NPCS: [NpcKind; 7] = [ NpcKind::Ogre, NpcKind::Rat, NpcKind::StoneGolem, + NpcKind::Reddragon, ]; /// Body-specific NPC name metadata. @@ -91,6 +93,7 @@ pub fn kind_to_body(kind: NpcKind) -> Body { NpcKind::Ogre => comp::biped_large::Body::random().into(), NpcKind::Rat => comp::critter::Body::random().into(), NpcKind::StoneGolem => comp::golem::Body::random().into(), + NpcKind::Reddragon => comp::critter::Body::random().into(), } } @@ -212,6 +215,14 @@ impl NpcBody { comp::golem::Body::random_with, ) }) + .or_else(|| { + parse( + s, + NpcKind::Reddragon, + &npc_names.dragon, + comp::dragon::Body::random_with, + ) + }) .ok_or(()) } } diff --git a/voxygen/src/anim/dragon/mod.rs b/voxygen/src/anim/dragon/mod.rs index 67cf9c5317..b997fab2f7 100644 --- a/voxygen/src/anim/dragon/mod.rs +++ b/voxygen/src/anim/dragon/mod.rs @@ -10,7 +10,7 @@ use crate::render::FigureBoneData; use common::comp::{self}; use vek::Vec3; -#[derive(Clone)] +#[derive(Clone, Default)] pub struct DragonSkeleton { head: Bone, chest_front: Bone, @@ -28,23 +28,7 @@ pub struct DragonSkeleton { } impl DragonSkeleton { - pub fn new() -> Self { - Self { - head: Bone::default(), - chest_front: Bone::default(), - chest_rear: Bone::default(), - tail_front: Bone::default(), - tail_rear: Bone::default(), - wing_in_l: Bone::default(), - wing_in_r: Bone::default(), - wing_out_l: Bone::default(), - wing_out_r: Bone::default(), - foot_fl: Bone::default(), - foot_fr: Bone::default(), - foot_bl: Bone::default(), - foot_br: Bone::default(), - } - } + pub fn new() -> Self { Self::default() } } impl Skeleton for DragonSkeleton { @@ -98,7 +82,17 @@ impl Skeleton for DragonSkeleton { } } -pub struct SkeletonAttr; +pub struct SkeletonAttr { + head: (f32, f32), + chest_front: (f32, f32), + chest_rear: (f32, f32), + tail_front: (f32, f32), + tail_rear: (f32, f32), + wing_in: (f32, f32), + wing_out: (f32, f32), + feet_f: (f32, f32, f32), + feet_b: (f32, f32, f32), +} impl<'a> std::convert::TryFrom<&'a comp::Body> for SkeletonAttr { type Error = (); @@ -112,9 +106,52 @@ impl<'a> std::convert::TryFrom<&'a comp::Body> for SkeletonAttr { } impl Default for SkeletonAttr { - fn default() -> Self { Self } + fn default() -> Self { + Self { + head: (0.0, 0.0), + chest_front: (0.0, 0.0), + chest_rear: (0.0, 0.0), + tail_front: (0.0, 0.0), + tail_rear: (0.0, 0.0), + wing_in: (0.0, 0.0), + wing_out: (0.0, 0.0), + feet_f: (0.0, 0.0, 0.0), + feet_b: (0.0, 0.0, 0.0), + } + } } impl<'a> From<&'a comp::dragon::Body> for SkeletonAttr { - fn from(_body: &'a comp::dragon::Body) -> Self { Self } -} + fn from(body: &'a comp::dragon::Body) -> Self { + use comp::dragon::Species::*; + Self { + head: match (body.species, body.body_type) { + (Reddragon, _) => (4.0, 3.0), + }, + chest_front: match (body.species, body.body_type) { + (Reddragon, _) => (0.0, 5.0), + }, + chest_rear: match (body.species, body.body_type) { + (Reddragon, _) => (0.0, 5.0), + }, + tail_front: match (body.species, body.body_type) { + (Reddragon, _) => (-3.0, 1.5), + }, + tail_rear: match (body.species, body.body_type) { + (Reddragon, _) => (-3.0, 1.5), + }, + wing_in: match (body.species, body.body_type) { + (Reddragon, _) => (2.75, 0.0), + }, + wing_out: match (body.species, body.body_type) { + (Reddragon, _) => (2.75, 0.0), + }, + feet_f: match (body.species, body.body_type) { + (Reddragon, _) => (2.0, -1.5, 4.0), + }, + feet_b: match (body.species, body.body_type) { + (Reddragon, _) => (2.0, -1.5, 4.0), + }, + } + } +} \ No newline at end of file diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index d06f72cd1e..4ca5547771 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -410,24 +410,83 @@ impl FigureModelCache { None, None, ], - Body::Dragon(body) => [ - Some(mesh_dragon_head(body.head, generate_mesh)), - Some(mesh_dragon_chest_front(body.chest_front, generate_mesh)), - Some(mesh_dragon_chest_rear(body.chest_rear, generate_mesh)), - Some(mesh_dragon_tail_front(body.tail_front, generate_mesh)), - Some(mesh_dragon_tail_rear(body.tail_rear, generate_mesh)), - Some(mesh_dragon_wing_in_l(body.wing_in_l, generate_mesh)), - Some(mesh_dragon_wing_in_r(body.wing_in_r, generate_mesh)), - Some(mesh_dragon_wing_out_l(body.wing_out_l, generate_mesh)), - Some(mesh_dragon_wing_out_r(body.wing_out_r, generate_mesh)), - Some(mesh_dragon_foot_fl(body.foot_fl, generate_mesh)), - Some(mesh_dragon_foot_fr(body.foot_fr, generate_mesh)), - Some(mesh_dragon_foot_bl(body.foot_bl, generate_mesh)), - Some(mesh_dragon_foot_br(body.foot_br, generate_mesh)), - None, - None, - None, - ], + Body::Dragon(body) => { + let dragon_center_spec = + DragonCenterSpec::load_watched(manifest_indicator); + let dragon_lateral_spec = + DragonLateralSpec::load_watched(manifest_indicator); + + [ + Some(dragon_center_spec.mesh_head( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_center_spec.mesh_chest_front( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_center_spec.mesh_chest_rear( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_center_spec.mesh_tail_front( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_center_spec.mesh_tail_rear( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_lateral_spec.mesh_wing_in_l( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_lateral_spec.mesh_wing_in_r( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_lateral_spec.mesh_wing_out_l( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_lateral_spec.mesh_wing_out_r( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_lateral_spec.mesh_foot_fl( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_lateral_spec.mesh_foot_fr( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_lateral_spec.mesh_foot_bl( + body.species, + body.body_type, + generate_mesh, + )), + Some(dragon_lateral_spec.mesh_foot_br( + body.species, + body.body_type, + generate_mesh, + )), + None, + None, + None, + ] + }, Body::BirdSmall(body) => [ Some(mesh_bird_small_head(body.head, generate_mesh)), Some(mesh_bird_small_torso(body.torso, generate_mesh)), diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 3b1debba8f..1bfd77b30f 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -6,7 +6,8 @@ use common::{ bird_medium::{BodyType as BMBodyType, Species as BMSpecies}, bird_small, critter::{BodyType as CBodyType, Species as CSpecies}, - dragon, fish_medium, fish_small, + dragon::{BodyType as DBodyType, Species as DSpecies}, + fish_medium, fish_small, golem::{BodyType as GBodyType, Species as GSpecies}, humanoid::{Body, BodyType, EyeColor, Race, Skin}, item::{ @@ -1865,173 +1866,345 @@ pub fn mesh_fish_medium_fin_r( ) } -pub fn mesh_dragon_head( - head: dragon::Head, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match head { - dragon::Head::Default => "npc.dragon.head", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) +//// + +#[derive(Serialize, Deserialize)] +pub struct DragonCenterSpec(HashMap<(DSpecies, DBodyType), SidedDCenterVoxSpec>); + +#[derive(Serialize, Deserialize)] +struct SidedDCenterVoxSpec { + head: DragonCenterSubSpec, + chest_front: DragonCenterSubSpec, + chest_rear: DragonCenterSubSpec, + tail_front: DragonCenterSubSpec, + tail_rear: DragonCenterSubSpec, +} +#[derive(Serialize, Deserialize)] +struct DragonCenterSubSpec { + offset: [f32; 3], // Should be relative to initial origin + center: VoxSimple, } -pub fn mesh_dragon_chest_front( - chest_front: dragon::ChestFront, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match chest_front { - dragon::ChestFront::Default => "npc.dragon.chest_front", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) +#[derive(Serialize, Deserialize)] +pub struct DragonLateralSpec(HashMap<(DSpecies, DBodyType), SidedDLateralVoxSpec>); + +#[derive(Serialize, Deserialize)] +struct SidedDLateralVoxSpec { + wing_in_l: DragonLateralSubSpec, + wing_in_r: DragonLateralSubSpec, + wing_out_l: DragonLateralSubSpec, + wing_out_r: DragonLateralSubSpec, + foot_fl: DragonLateralSubSpec, + foot_fr: DragonLateralSubSpec, + foot_bl: DragonLateralSubSpec, + foot_br: DragonLateralSubSpec, +} +#[derive(Serialize, Deserialize)] +struct DragonLateralSubSpec { + offset: [f32; 3], // Should be relative to initial origin + lateral: VoxSimple, } -pub fn mesh_dragon_chest_rear( - chest_rear: dragon::ChestRear, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match chest_rear { - dragon::ChestRear::Default => "npc.dragon.chest_rear", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) +impl Asset for DragonCenterSpec { + const ENDINGS: &'static [&'static str] = &["ron"]; + + fn parse(buf_reader: BufReader) -> Result { + ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) + } } -pub fn mesh_dragon_tail_front( - tail_front: dragon::TailFront, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match tail_front { - dragon::TailFront::Default => "npc.dragon.tail_front", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) +impl Asset for DragonLateralSpec { + const ENDINGS: &'static [&'static str] = &["ron"]; + + fn parse(buf_reader: BufReader) -> Result { + ron::de::from_reader(buf_reader).map_err(assets::Error::parse_error) + } } -pub fn mesh_dragon_tail_rear( - tail_rear: dragon::TailRear, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match tail_rear { - dragon::TailRear::Default => "npc.dragon.tail_rear", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) -} +impl DragonCenterSpec { + pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { + assets::load_watched::("voxygen.voxel.dragon_center_manifest", indicator) + .unwrap() + } -pub fn mesh_dragon_wing_in_l( - wing_in_l: dragon::WingInL, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match wing_in_l { - dragon::WingInL::Default => "npc.dragon.wing_in_l", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) -} + pub fn mesh_head( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No head specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let center = graceful_load_segment(&spec.head.center.0); -pub fn mesh_dragon_wing_in_r( - wing_in_r: dragon::WingInR, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match wing_in_r { - dragon::WingInR::Default => "npc.dragon.wing_in_r", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) -} + generate_mesh(¢er, Vec3::from(spec.head.offset)) + } -pub fn mesh_dragon_wing_out_l( - wing_out_l: dragon::WingOutL, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match wing_out_l { - dragon::WingOutL::Default => "npc.dragon.wing_out_l", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) -} + pub fn mesh_chest_front( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No chest front specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let center = graceful_load_segment(&spec.chest_front.center.0); -pub fn mesh_dragon_wing_out_r( - wing_out_r: dragon::WingOutR, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match wing_out_r { - dragon::WingOutR::Default => "npc.dragon.wing_out_r", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) -} + generate_mesh(¢er, Vec3::from(spec.chest_front.offset)) + } + + pub fn mesh_chest_rear( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No chest rear specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let center = graceful_load_segment(&spec.chest_rear.center.0); -pub fn mesh_dragon_foot_fl( - foot_fl: dragon::FootFL, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match foot_fl { - dragon::FootFL::Default => "npc.dragon.foot_fl", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) -} + generate_mesh(¢er, Vec3::from(spec.chest_rear.offset)) + } -pub fn mesh_dragon_foot_fr( - foot_fr: dragon::FootFR, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match foot_fr { - dragon::FootFR::Default => "npc.dragon.foot_fr", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) -} + pub fn mesh_tail_front( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No tail front specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let center = graceful_load_segment(&spec.tail_front.center.0); -pub fn mesh_dragon_foot_bl( - foot_bl: dragon::FootBL, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match foot_bl { - dragon::FootBL::Default => "npc.dragon.foot_bl", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) -} + generate_mesh(¢er, Vec3::from(spec.tail_front.offset)) + } -pub fn mesh_dragon_foot_br( - foot_br: dragon::FootBR, - generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, -) -> Mesh { - load_mesh( - match foot_br { - dragon::FootBR::Default => "npc.dragon.foot_br", - }, - Vec3::new(-7.0, -6.0, -6.0), - generate_mesh, - ) + pub fn mesh_tail_rear( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No tail rear specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let center = graceful_load_segment(&spec.tail_rear.center.0); + + generate_mesh(¢er, Vec3::from(spec.tail_rear.offset)) + } +} +impl DragonLateralSpec { + pub fn load_watched(indicator: &mut ReloadIndicator) -> Arc { + assets::load_watched::("voxygen.voxel.dragon_lateral_manifest", indicator) + .unwrap() + } + + pub fn mesh_wing_in_l( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No wing specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let lateral = graceful_load_segment(&spec.wing_in_l.lateral.0); + + generate_mesh(&lateral, Vec3::from(spec.wing_in_l.offset)) + } + + pub fn mesh_wing_in_r( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No wing specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let lateral = graceful_load_segment(&spec.wing_in_r.lateral.0); + + generate_mesh(&lateral, Vec3::from(spec.wing_in_r.offset)) + } + + pub fn mesh_wing_out_l( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No wing specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let lateral = graceful_load_segment(&spec.wing_out_l.lateral.0); + + generate_mesh(&lateral, Vec3::from(spec.wing_out_l.offset)) + } + + pub fn mesh_wing_out_r( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No wing specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let lateral = graceful_load_segment(&spec.wing_out_r.lateral.0); + + generate_mesh(&lateral, Vec3::from(spec.wing_out_r.offset)) + } + + pub fn mesh_foot_fl( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No foot specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let lateral = graceful_load_segment(&spec.foot_fl.lateral.0); + + generate_mesh(&lateral, Vec3::from(spec.foot_fl.offset)) + } + + pub fn mesh_foot_fr( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No foot specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let lateral = graceful_load_segment(&spec.foot_fr.lateral.0); + + generate_mesh(&lateral, Vec3::from(spec.foot_fr.offset)) + } + + pub fn mesh_foot_bl( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No foot specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let lateral = graceful_load_segment(&spec.foot_bl.lateral.0); + + generate_mesh(&lateral, Vec3::from(spec.foot_bl.offset)) + } + + pub fn mesh_foot_br( + &self, + species: DSpecies, + body_type: DBodyType, + generate_mesh: impl FnOnce(&Segment, Vec3) -> Mesh, + ) -> Mesh { + let spec = match self.0.get(&(species, body_type)) { + Some(spec) => spec, + None => { + error!( + "No foot specification exists for the combination of {:?} and {:?}", + species, body_type + ); + return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5), generate_mesh); + }, + }; + let lateral = graceful_load_segment(&spec.foot_br.lateral.0); + + generate_mesh(&lateral, Vec3::from(spec.foot_br.offset)) + } } //// diff --git a/world/src/lib.rs b/world/src/lib.rs index 6f47c7a311..41b8a54b36 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -21,7 +21,7 @@ use crate::{ util::{Grid, Sampler}, }; use common::{ - comp::{self, bird_medium, critter, quadruped_medium, quadruped_small}, + comp::{self, bird_medium, critter, quadruped_medium, quadruped_small, dragon}, generation::{ChunkSupplement, EntityInfo}, terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, vol::{ReadVol, RectVolSize, Vox, WriteVol},