mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'isse/crustacean-skeleton' into 'master'
crustacean-skeleton and crab See merge request veloren/veloren!4200
This commit is contained in:
commit
18fd06fd88
@ -565,6 +565,12 @@
|
|||||||
Simple(None, "common.abilities.custom.arthropods.dagonite.leapshockwave"),
|
Simple(None, "common.abilities.custom.arthropods.dagonite.leapshockwave"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
// Crustaceans
|
||||||
|
Custom("Crab"): (
|
||||||
|
primary: Simple(None, "common.abilities.custom.crab.triplestrike"),
|
||||||
|
secondary: Simple(None, "common.abilities.custom.crab.triplestrike"),
|
||||||
|
abilities: [],
|
||||||
|
),
|
||||||
/// TODO: Organize the rest into further catagories and give purple tier droppers+ custom skillsets
|
/// TODO: Organize the rest into further catagories and give purple tier droppers+ custom skillsets
|
||||||
Custom("Turret"): (
|
Custom("Turret"): (
|
||||||
primary: Simple(None, "common.abilities.custom.turret.arrows"),
|
primary: Simple(None, "common.abilities.custom.turret.arrows"),
|
||||||
|
65
assets/common/abilities/custom/crab/triplestrike.ron
Normal file
65
assets/common/abilities/custom/crab/triplestrike.ron
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
ComboMelee2(
|
||||||
|
strikes: [
|
||||||
|
(
|
||||||
|
melee_constructor: (
|
||||||
|
kind: Slash(
|
||||||
|
damage: 5,
|
||||||
|
poise: 5,
|
||||||
|
knockback: 0,
|
||||||
|
energy_regen: 0,
|
||||||
|
),
|
||||||
|
range: 1.1,
|
||||||
|
angle: 30.0,
|
||||||
|
),
|
||||||
|
buildup_duration: 1.3,
|
||||||
|
swing_duration: 0.07,
|
||||||
|
hit_timing: 0.5,
|
||||||
|
recover_duration: 0.6,
|
||||||
|
movement: (
|
||||||
|
swing: Some(Forward(0.5)),
|
||||||
|
),
|
||||||
|
ori_modifier: 0.65,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
melee_constructor: (
|
||||||
|
kind: Slash(
|
||||||
|
damage: 8,
|
||||||
|
poise: 8,
|
||||||
|
knockback: 1,
|
||||||
|
energy_regen: 0,
|
||||||
|
),
|
||||||
|
range: 1.1,
|
||||||
|
angle: 30.0,
|
||||||
|
),
|
||||||
|
buildup_duration: 0.8,
|
||||||
|
swing_duration: 0.07,
|
||||||
|
hit_timing: 0.5,
|
||||||
|
recover_duration: 0.6,
|
||||||
|
movement: (
|
||||||
|
swing: Some(Forward(0.5)),
|
||||||
|
),
|
||||||
|
ori_modifier: 0.65,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
melee_constructor: (
|
||||||
|
kind: Slash(
|
||||||
|
damage: 12,
|
||||||
|
poise: 9,
|
||||||
|
knockback: 1,
|
||||||
|
energy_regen: 0,
|
||||||
|
),
|
||||||
|
range: 1.1,
|
||||||
|
angle: 30.0,
|
||||||
|
),
|
||||||
|
buildup_duration: 0.8,
|
||||||
|
swing_duration: 0.07,
|
||||||
|
hit_timing: 0.5,
|
||||||
|
recover_duration: 0.6,
|
||||||
|
movement: (
|
||||||
|
swing: Some(Forward(0.5)),
|
||||||
|
),
|
||||||
|
ori_modifier: 0.65,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
energy_cost_per_strike: 0,
|
||||||
|
)
|
11
assets/common/entity/wild/peaceful/crab.ron
Normal file
11
assets/common/entity/wild/peaceful/crab.ron
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#![enable(implicit_some)]
|
||||||
|
(
|
||||||
|
name: Automatic,
|
||||||
|
body: RandomWith("crab"),
|
||||||
|
alignment: Alignment(Wild),
|
||||||
|
loot: LootTable("common.loot_tables.creature.crustacean.crab"),
|
||||||
|
inventory: (
|
||||||
|
loadout: FromBody,
|
||||||
|
),
|
||||||
|
meta: [],
|
||||||
|
)
|
20
assets/common/items/npc_weapons/unique/crab_pincer.ron
Normal file
20
assets/common/items/npc_weapons/unique/crab_pincer.ron
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
ItemDef(
|
||||||
|
name: "Crab Pincer",
|
||||||
|
description: "testing123",
|
||||||
|
kind: Tool((
|
||||||
|
kind: Natural,
|
||||||
|
hands: Two,
|
||||||
|
stats: (
|
||||||
|
equip_time_secs: 0.5,
|
||||||
|
power: 1.0,
|
||||||
|
effect_power: 1.0,
|
||||||
|
speed: 1.0,
|
||||||
|
range: 1.0,
|
||||||
|
energy_efficiency: 1.0,
|
||||||
|
buff_strength: 1.0,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
quality: Low,
|
||||||
|
tags: [],
|
||||||
|
ability_spec: Some(Custom("Crab")),
|
||||||
|
)
|
4
assets/common/loot_tables/creature/crustacean/crab.ron
Normal file
4
assets/common/loot_tables/creature/crustacean/crab.ron
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
(1.0, Item("common.items.crafting_ing.animal_misc.viscous_ooze")),
|
||||||
|
(2.0, MultiDrop(Item("common.items.crafting_ing.animal_misc.strong_pincer"), 1, 2)),
|
||||||
|
]
|
@ -1417,4 +1417,16 @@
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
crustacean: (
|
||||||
|
body: (
|
||||||
|
keyword: "crustacean",
|
||||||
|
names_0: ["Ferris"],
|
||||||
|
),
|
||||||
|
species: (
|
||||||
|
crab: (
|
||||||
|
keyword: "crab",
|
||||||
|
generic: "Crab",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
30
assets/voxygen/voxel/crustacean_central_manifest.ron
Normal file
30
assets/voxygen/voxel/crustacean_central_manifest.ron
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
({
|
||||||
|
(Crab, Male): (
|
||||||
|
chest: (
|
||||||
|
offset: (-5.0, -4.5, 2.0),
|
||||||
|
central: ("npc.crab.crab"),
|
||||||
|
),
|
||||||
|
tail_f: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
|
),
|
||||||
|
tail_b: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(Crab, Female): (
|
||||||
|
chest: (
|
||||||
|
offset: (-5.0, -4.5, 2.0),
|
||||||
|
central: ("npc.crab.crab"),
|
||||||
|
),
|
||||||
|
tail_f: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
|
),
|
||||||
|
tail_b: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
})
|
127
assets/voxygen/voxel/crustacean_lateral_manifest.ron
Normal file
127
assets/voxygen/voxel/crustacean_lateral_manifest.ron
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
|
||||||
|
({
|
||||||
|
(Crab, Male): (
|
||||||
|
arm_l: (
|
||||||
|
offset: (-6.0, 0.5, 2.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 1,
|
||||||
|
),
|
||||||
|
pincer_l0: (
|
||||||
|
offset: (-9.0, 2.5, 1.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 5,
|
||||||
|
),
|
||||||
|
pincer_l1: (
|
||||||
|
offset: (-5.0, 4.5, 2.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 6,
|
||||||
|
),
|
||||||
|
arm_r: (
|
||||||
|
offset: (3.0, 0.5, 2.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 1,
|
||||||
|
),
|
||||||
|
pincer_r0: (
|
||||||
|
offset: (2.0, 2.5, 1.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 5,
|
||||||
|
),
|
||||||
|
pincer_r1: (
|
||||||
|
offset: (2.0, 4.5, 2.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 6,
|
||||||
|
),
|
||||||
|
leg_fl: (
|
||||||
|
offset: (-8.5, -2.5, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 4,
|
||||||
|
),
|
||||||
|
leg_cl: (
|
||||||
|
offset: (-8.5, -2.5, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 3,
|
||||||
|
),
|
||||||
|
leg_bl: (
|
||||||
|
offset: (-7.5, -3.0, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 2,
|
||||||
|
),
|
||||||
|
leg_fr: (
|
||||||
|
offset: (3.5, -2.5, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 4,
|
||||||
|
),
|
||||||
|
leg_cr: (
|
||||||
|
offset: (3.5, -2.5, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 3,
|
||||||
|
),
|
||||||
|
leg_br: (
|
||||||
|
offset: (2.5, -3.0, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(Crab, Female): (
|
||||||
|
arm_l: (
|
||||||
|
offset: (-6.0, 0.5, 2.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 1,
|
||||||
|
),
|
||||||
|
pincer_l0: (
|
||||||
|
offset: (-9.0, 2.5, 1.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 5,
|
||||||
|
),
|
||||||
|
pincer_l1: (
|
||||||
|
offset: (-5.0, 4.5, 2.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 6,
|
||||||
|
),
|
||||||
|
arm_r: (
|
||||||
|
offset: (3.0, 0.5, 2.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 1,
|
||||||
|
),
|
||||||
|
pincer_r0: (
|
||||||
|
offset: (2.0, 2.5, 1.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 5,
|
||||||
|
),
|
||||||
|
pincer_r1: (
|
||||||
|
offset: (2.0, 4.5, 2.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 6,
|
||||||
|
),
|
||||||
|
leg_fl: (
|
||||||
|
offset: (-8.5, -2.5, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 4,
|
||||||
|
),
|
||||||
|
leg_cl: (
|
||||||
|
offset: (-8.5, -2.5, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 3,
|
||||||
|
),
|
||||||
|
leg_bl: (
|
||||||
|
offset: (-7.5, -3.0, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 2,
|
||||||
|
),
|
||||||
|
leg_fr: (
|
||||||
|
offset: (3.5, -2.5, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 4,
|
||||||
|
),
|
||||||
|
leg_cr: (
|
||||||
|
offset: (3.5, -2.5, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 3,
|
||||||
|
),
|
||||||
|
leg_br: (
|
||||||
|
offset: (2.5, -3.0, 0.0),
|
||||||
|
lateral: ("npc.crab.crab"),
|
||||||
|
model_index: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
})
|
BIN
assets/voxygen/voxel/npc/crab/crab.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/npc/crab/crab.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -5,6 +5,7 @@ SpawnEntry (
|
|||||||
Pack(
|
Pack(
|
||||||
groups: [
|
groups: [
|
||||||
(3, (1, 3, "common.entity.wild.aggressive.sea_crocodile")),
|
(3, (1, 3, "common.entity.wild.aggressive.sea_crocodile")),
|
||||||
|
(3, (8, 16, "common.entity.wild.peaceful.crab")),
|
||||||
(1, (1, 1, "common.entity.wild.aggressive.reefsnapper")),
|
(1, (1, 1, "common.entity.wild.aggressive.reefsnapper")),
|
||||||
],
|
],
|
||||||
spawn_mode: Land,
|
spawn_mode: Land,
|
||||||
|
@ -14,6 +14,7 @@ SpawnEntry (
|
|||||||
Pack(
|
Pack(
|
||||||
groups: [
|
groups: [
|
||||||
(2, (1, 1, "common.entity.wild.peaceful.kelpie")),
|
(2, (1, 1, "common.entity.wild.peaceful.kelpie")),
|
||||||
|
(2, (8, 16, "common.entity.wild.peaceful.crab")),
|
||||||
(2, (1, 1, "common.entity.wild.aggressive.crocodile")),
|
(2, (1, 1, "common.entity.wild.aggressive.crocodile")),
|
||||||
],
|
],
|
||||||
spawn_mode: Land,
|
spawn_mode: Land,
|
||||||
|
@ -380,6 +380,7 @@ impl<'a> From<&'a Body> for Psyche {
|
|||||||
arthropod::Species::Dagonite => 0.2,
|
arthropod::Species::Dagonite => 0.2,
|
||||||
arthropod::Species::Emberfly => 0.1,
|
arthropod::Species::Emberfly => 0.1,
|
||||||
},
|
},
|
||||||
|
Body::Crustacean(_) => 0.0,
|
||||||
},
|
},
|
||||||
sight_dist: match body {
|
sight_dist: match body {
|
||||||
Body::BirdLarge(_) => 250.0,
|
Body::BirdLarge(_) => 250.0,
|
||||||
|
@ -3,6 +3,7 @@ pub mod biped_large;
|
|||||||
pub mod biped_small;
|
pub mod biped_small;
|
||||||
pub mod bird_large;
|
pub mod bird_large;
|
||||||
pub mod bird_medium;
|
pub mod bird_medium;
|
||||||
|
pub mod crustacean;
|
||||||
pub mod dragon;
|
pub mod dragon;
|
||||||
pub mod fish_medium;
|
pub mod fish_medium;
|
||||||
pub mod fish_small;
|
pub mod fish_small;
|
||||||
@ -52,6 +53,7 @@ make_case_elim!(
|
|||||||
Ship(body: ship::Body) = 14,
|
Ship(body: ship::Body) = 14,
|
||||||
Arthropod(body: arthropod::Body) = 15,
|
Arthropod(body: arthropod::Body) = 15,
|
||||||
ItemDrop(body: item_drop::Body) = 16,
|
ItemDrop(body: item_drop::Body) = 16,
|
||||||
|
Crustacean(body: crustacean::Body) = 17,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -101,6 +103,7 @@ pub struct AllBodies<BodyMeta, SpeciesMeta> {
|
|||||||
pub quadruped_low: BodyData<BodyMeta, quadruped_low::AllSpecies<SpeciesMeta>>,
|
pub quadruped_low: BodyData<BodyMeta, quadruped_low::AllSpecies<SpeciesMeta>>,
|
||||||
pub ship: BodyData<BodyMeta, ()>,
|
pub ship: BodyData<BodyMeta, ()>,
|
||||||
pub arthropod: BodyData<BodyMeta, arthropod::AllSpecies<SpeciesMeta>>,
|
pub arthropod: BodyData<BodyMeta, arthropod::AllSpecies<SpeciesMeta>>,
|
||||||
|
pub crustacean: BodyData<BodyMeta, crustacean::AllSpecies<SpeciesMeta>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<BodyMeta, SpeciesMeta> AllBodies<BodyMeta, SpeciesMeta> {
|
impl<BodyMeta, SpeciesMeta> AllBodies<BodyMeta, SpeciesMeta> {
|
||||||
@ -124,6 +127,7 @@ impl<BodyMeta, SpeciesMeta> AllBodies<BodyMeta, SpeciesMeta> {
|
|||||||
Body::Theropod(b) => &self.theropod.species[&b.species],
|
Body::Theropod(b) => &self.theropod.species[&b.species],
|
||||||
Body::QuadrupedLow(b) => &self.quadruped_low.species[&b.species],
|
Body::QuadrupedLow(b) => &self.quadruped_low.species[&b.species],
|
||||||
Body::Arthropod(b) => &self.arthropod.species[&b.species],
|
Body::Arthropod(b) => &self.arthropod.species[&b.species],
|
||||||
|
Body::Crustacean(b) => &self.crustacean.species[&b.species],
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -150,6 +154,7 @@ impl<BodyMeta, SpeciesMeta> core::ops::Index<NpcKind> for AllBodies<BodyMeta, Sp
|
|||||||
NpcKind::Reddragon => &self.dragon.body,
|
NpcKind::Reddragon => &self.dragon.body,
|
||||||
NpcKind::Crocodile => &self.quadruped_low.body,
|
NpcKind::Crocodile => &self.quadruped_low.body,
|
||||||
NpcKind::Tarantula => &self.arthropod.body,
|
NpcKind::Tarantula => &self.arthropod.body,
|
||||||
|
NpcKind::Crab => &self.crustacean.body,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,6 +183,7 @@ impl<'a, BodyMeta, SpeciesMeta> core::ops::Index<&'a Body> for AllBodies<BodyMet
|
|||||||
Body::QuadrupedLow(_) => &self.quadruped_low.body,
|
Body::QuadrupedLow(_) => &self.quadruped_low.body,
|
||||||
Body::Arthropod(_) => &self.arthropod.body,
|
Body::Arthropod(_) => &self.arthropod.body,
|
||||||
Body::Ship(_) => &self.ship.body,
|
Body::Ship(_) => &self.ship.body,
|
||||||
|
Body::Crustacean(_) => &self.crustacean.body,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,6 +260,10 @@ impl Body {
|
|||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Body::Ship(_) => false,
|
Body::Ship(_) => false,
|
||||||
|
Body::Crustacean(b1) => match other {
|
||||||
|
Body::Crustacean(b2) => b1.species == b2.species,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,6 +479,8 @@ impl Body {
|
|||||||
},
|
},
|
||||||
Body::Ship(ship) => ship.mass().0,
|
Body::Ship(ship) => ship.mass().0,
|
||||||
Body::Arthropod(_) => 200.0,
|
Body::Arthropod(_) => 200.0,
|
||||||
|
// TODO: mass
|
||||||
|
Body::Crustacean(_) => 50.0,
|
||||||
};
|
};
|
||||||
Mass(m)
|
Mass(m)
|
||||||
}
|
}
|
||||||
@ -641,6 +653,7 @@ impl Body {
|
|||||||
bird_medium::Species::Puffin => Vec3::new(1.0, 1.0, 1.0),
|
bird_medium::Species::Puffin => Vec3::new(1.0, 1.0, 1.0),
|
||||||
bird_medium::Species::Toucan => Vec3::new(2.1, 1.1, 1.2),
|
bird_medium::Species::Toucan => Vec3::new(2.1, 1.1, 1.2),
|
||||||
},
|
},
|
||||||
|
Body::Crustacean(_) => Vec3::new(1.2, 1.2, 0.7),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,6 +978,7 @@ impl Body {
|
|||||||
_ => 70,
|
_ => 70,
|
||||||
},
|
},
|
||||||
Body::Ship(_) => 1000,
|
Body::Ship(_) => 1000,
|
||||||
|
Body::Crustacean(_) => 40,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1135,7 +1149,13 @@ impl Body {
|
|||||||
pub fn can_strafe(&self) -> bool {
|
pub fn can_strafe(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
Body::Humanoid(_) | Body::BipedSmall(_) | Body::BipedLarge(_)
|
Body::Humanoid(_)
|
||||||
|
| Body::BipedSmall(_)
|
||||||
|
| Body::BipedLarge(_)
|
||||||
|
| Body::Crustacean(crustacean::Body {
|
||||||
|
species: crustacean::Species::Crab,
|
||||||
|
..
|
||||||
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
66
common/src/comp/body/crustacean.rs
Normal file
66
common/src/comp/body/crustacean.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use rand::{seq::SliceRandom, thread_rng};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct Body {
|
||||||
|
pub species: Species,
|
||||||
|
pub body_type: BodyType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Body {
|
||||||
|
pub fn random() -> Self {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
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<Body> for super::Body {
|
||||||
|
fn from(body: Body) -> Self { super::Body::Crustacean(body) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum Species {
|
||||||
|
Crab = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Data representing per-species generic data.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct AllSpecies<SpeciesMeta> {
|
||||||
|
pub crab: SpeciesMeta,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies<SpeciesMeta> {
|
||||||
|
type Output = SpeciesMeta;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, &index: &'a Species) -> &Self::Output {
|
||||||
|
match index {
|
||||||
|
Species::Crab => &self.crab,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ALL_SPECIES: [Species; 1] = [Species::Crab];
|
||||||
|
|
||||||
|
impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
|
||||||
|
type IntoIter = std::iter::Copied<std::slice::Iter<'static, Self::Item>>;
|
||||||
|
type Item = Species;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter { ALL_SPECIES.iter().copied() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum BodyType {
|
||||||
|
Female = 0,
|
||||||
|
Male = 1,
|
||||||
|
}
|
||||||
|
pub const ALL_BODY_TYPES: [BodyType; 2] = [BodyType::Female, BodyType::Male];
|
@ -263,7 +263,7 @@ impl Body {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Cross-section, zero-lift angle; exclude the fins (width * 0.2)
|
// Cross-section, zero-lift angle; exclude the fins (width * 0.2)
|
||||||
Body::FishMedium(_) | Body::FishSmall(_) => {
|
Body::FishMedium(_) | Body::FishSmall(_) | Body::Crustacean(_) => {
|
||||||
let dim = self.dimensions().map(|a| a * 0.5 * scale);
|
let dim = self.dimensions().map(|a| a * 0.5 * scale);
|
||||||
// "A Simple Method to Determine Drag Coefficients in Aquatic Animals",
|
// "A Simple Method to Determine Drag Coefficients in Aquatic Animals",
|
||||||
// D. Bilo and W. Nachtigall, 1980
|
// D. Bilo and W. Nachtigall, 1980
|
||||||
|
@ -855,6 +855,10 @@ fn default_main_tool(body: &Body) -> Item {
|
|||||||
"common.items.npc_weapons.unique.birdmediumbasic",
|
"common.items.npc_weapons.unique.birdmediumbasic",
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
|
Body::Crustacean(_) => Some(Item::new_from_asset_expect(
|
||||||
|
"common.items.npc_weapons.unique.crab_pincer",
|
||||||
|
)),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,9 +52,9 @@ pub use self::{
|
|||||||
aura::{Aura, AuraChange, AuraKind, Auras},
|
aura::{Aura, AuraChange, AuraKind, Auras},
|
||||||
beam::Beam,
|
beam::Beam,
|
||||||
body::{
|
body::{
|
||||||
arthropod, biped_large, biped_small, bird_large, bird_medium, dragon, fish_medium,
|
arthropod, biped_large, biped_small, bird_large, bird_medium, crustacean, dragon,
|
||||||
fish_small, golem, humanoid, item_drop, object, quadruped_low, quadruped_medium,
|
fish_medium, fish_small, golem, humanoid, item_drop, object, quadruped_low,
|
||||||
quadruped_small, ship, theropod, AllBodies, Body, BodyData,
|
quadruped_medium, quadruped_small, ship, theropod, AllBodies, Body, BodyData,
|
||||||
},
|
},
|
||||||
buff::{
|
buff::{
|
||||||
Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffKey, BuffKind, BuffSource, Buffs,
|
Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffKey, BuffKind, BuffSource, Buffs,
|
||||||
|
@ -469,6 +469,7 @@ impl EntityInfo {
|
|||||||
Body::Golem(body) => Some(get_npc_name(&npc_names.golem, body.species)),
|
Body::Golem(body) => Some(get_npc_name(&npc_names.golem, body.species)),
|
||||||
Body::BipedLarge(body) => Some(get_npc_name(&npc_names.biped_large, body.species)),
|
Body::BipedLarge(body) => Some(get_npc_name(&npc_names.biped_large, body.species)),
|
||||||
Body::Arthropod(body) => Some(get_npc_name(&npc_names.arthropod, body.species)),
|
Body::Arthropod(body) => Some(get_npc_name(&npc_names.arthropod, body.species)),
|
||||||
|
Body::Crustacean(body) => Some(get_npc_name(&npc_names.crustacean, body.species)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
self.name = name.map(|name| {
|
self.name = name.map(|name| {
|
||||||
|
@ -23,9 +23,10 @@ pub enum NpcKind {
|
|||||||
Reddragon,
|
Reddragon,
|
||||||
Crocodile,
|
Crocodile,
|
||||||
Tarantula,
|
Tarantula,
|
||||||
|
Crab,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ALL_NPCS: [NpcKind; 14] = [
|
pub const ALL_NPCS: [NpcKind; 15] = [
|
||||||
NpcKind::Humanoid,
|
NpcKind::Humanoid,
|
||||||
NpcKind::Wolf,
|
NpcKind::Wolf,
|
||||||
NpcKind::Pig,
|
NpcKind::Pig,
|
||||||
@ -40,6 +41,7 @@ pub const ALL_NPCS: [NpcKind; 14] = [
|
|||||||
NpcKind::Reddragon,
|
NpcKind::Reddragon,
|
||||||
NpcKind::Crocodile,
|
NpcKind::Crocodile,
|
||||||
NpcKind::Tarantula,
|
NpcKind::Tarantula,
|
||||||
|
NpcKind::Crab,
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Body-specific NPC name metadata.
|
/// Body-specific NPC name metadata.
|
||||||
@ -136,6 +138,7 @@ pub fn kind_to_body(kind: NpcKind) -> Body {
|
|||||||
NpcKind::Reddragon => comp::dragon::Body::random().into(),
|
NpcKind::Reddragon => comp::dragon::Body::random().into(),
|
||||||
NpcKind::Crocodile => comp::quadruped_low::Body::random().into(),
|
NpcKind::Crocodile => comp::quadruped_low::Body::random().into(),
|
||||||
NpcKind::Tarantula => comp::arthropod::Body::random().into(),
|
NpcKind::Tarantula => comp::arthropod::Body::random().into(),
|
||||||
|
NpcKind::Crab => comp::crustacean::Body::random().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,6 +317,14 @@ impl NpcBody {
|
|||||||
comp::arthropod::Body::random_with,
|
comp::arthropod::Body::random_with,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
parse(
|
||||||
|
s,
|
||||||
|
NpcKind::Crab,
|
||||||
|
&npc_names.crustacean,
|
||||||
|
comp::crustacean::Body::random_with,
|
||||||
|
)
|
||||||
|
})
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,7 @@ impl Body {
|
|||||||
arthropod::Species::Dagonite => 70.0,
|
arthropod::Species::Dagonite => 70.0,
|
||||||
arthropod::Species::Emberfly => 75.0,
|
arthropod::Species::Emberfly => 75.0,
|
||||||
},
|
},
|
||||||
|
Body::Crustacean(_) => 80.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,6 +233,7 @@ impl Body {
|
|||||||
Body::Ship(ship) if ship.has_water_thrust() => 5.0 / self.dimensions().y,
|
Body::Ship(ship) if ship.has_water_thrust() => 5.0 / self.dimensions().y,
|
||||||
Body::Ship(_) => 6.0 / self.dimensions().y,
|
Body::Ship(_) => 6.0 / self.dimensions().y,
|
||||||
Body::Arthropod(_) => 3.5,
|
Body::Arthropod(_) => 3.5,
|
||||||
|
Body::Crustacean(_) => 3.5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,6 +278,7 @@ impl Body {
|
|||||||
},
|
},
|
||||||
Body::QuadrupedSmall(_) => 1500.0 * self.mass().0,
|
Body::QuadrupedSmall(_) => 1500.0 * self.mass().0,
|
||||||
Body::Arthropod(_) => 500.0 * self.mass().0,
|
Body::Arthropod(_) => 500.0 * self.mass().0,
|
||||||
|
Body::Crustacean(_) => 400.0 * self.mass().0,
|
||||||
} * front_profile,
|
} * front_profile,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
56
voxygen/anim/src/crustacean/alpha.rs
Normal file
56
voxygen/anim/src/crustacean/alpha.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CrustaceanSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::states::utils::StageSection;
|
||||||
|
|
||||||
|
pub struct AlphaAnimation;
|
||||||
|
|
||||||
|
impl Animation for AlphaAnimation {
|
||||||
|
type Dependency<'a> = (f32, f32, Option<StageSection>, f32);
|
||||||
|
type Skeleton = CrustaceanSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"crustacean_alpha\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_alpha")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(_velocity, global_time, stage_section, timer): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
_rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
let (movement1, movement2, movement3) = match stage_section {
|
||||||
|
Some(StageSection::Buildup) => (anim_time.powi(2), 0.0, 0.0),
|
||||||
|
Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0),
|
||||||
|
Some(StageSection::Recover) => (1.0, 1.0, anim_time),
|
||||||
|
_ => (0.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
let pullback = 1.0 - movement3;
|
||||||
|
let subtract = global_time - timer;
|
||||||
|
let check = subtract - subtract.trunc();
|
||||||
|
let _mirror = (check - 0.5).signum();
|
||||||
|
let _movement1abs = movement1 * pullback;
|
||||||
|
let _movement2abs = movement2 * pullback;
|
||||||
|
let _movement3abs = movement3 * pullback;
|
||||||
|
|
||||||
|
next.arm_l.orientation = Quaternion::rotation_x(anim_time);
|
||||||
|
|
||||||
|
next.chest.scale = Vec3::one() * s_a.scaler;
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1);
|
||||||
|
|
||||||
|
next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
|
||||||
|
next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
|
||||||
|
next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
93
voxygen/anim/src/crustacean/combomelee.rs
Normal file
93
voxygen/anim/src/crustacean/combomelee.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CrustaceanSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::states::utils::{AbilityInfo, StageSection};
|
||||||
|
|
||||||
|
pub struct ComboAnimation;
|
||||||
|
impl Animation for ComboAnimation {
|
||||||
|
type Dependency<'a> = (
|
||||||
|
Option<&'a str>,
|
||||||
|
Option<StageSection>,
|
||||||
|
Option<AbilityInfo>,
|
||||||
|
usize,
|
||||||
|
f32,
|
||||||
|
Vec3<f32>,
|
||||||
|
f32,
|
||||||
|
);
|
||||||
|
type Skeleton = CrustaceanSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"crustacean_combo\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_combo")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(ability_id, stage_section, _ability_info, current_strike, global_time, velocity, timer): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
rate: &mut f32,
|
||||||
|
_s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
*rate = 1.0;
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
let multi_strike_pullback = 1.0
|
||||||
|
- if matches!(stage_section, Some(StageSection::Recover)) {
|
||||||
|
anim_time.powi(4)
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
for strike in 0..=current_strike {
|
||||||
|
match ability_id {
|
||||||
|
Some("common.abilities.custom.crab.triplestrike") => {
|
||||||
|
let (movement1base, movement2base, movement3) = match stage_section {
|
||||||
|
Some(StageSection::Buildup) => (anim_time.sqrt(), 0.0, 0.0),
|
||||||
|
Some(StageSection::Action) => (1.0, anim_time.powi(4), 0.0),
|
||||||
|
Some(StageSection::Recover) => (1.0, 1.0, anim_time),
|
||||||
|
_ => (0.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
let pullback = multi_strike_pullback;
|
||||||
|
let subtract = global_time - timer;
|
||||||
|
let check = subtract - subtract.trunc();
|
||||||
|
let mirror = (check - 0.5).signum();
|
||||||
|
let twitch3 = (mirror * movement3 * 9.0).sin();
|
||||||
|
let _movement1 = mirror * movement1base * pullback;
|
||||||
|
let _movement2 = mirror * movement2base * pullback;
|
||||||
|
let movement1abs = movement1base * pullback;
|
||||||
|
let movement2abs = movement2base * pullback;
|
||||||
|
let mirror_var = if strike == 1 { -mirror } else { mirror };
|
||||||
|
if velocity.xy().magnitude() > 0.1 {
|
||||||
|
next.chest.orientation = Quaternion::rotation_z(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
next.chest.orientation = Quaternion::rotation_x(
|
||||||
|
movement1abs * 0.3 + movement2abs * -0.2 + (twitch3 / 5.0),
|
||||||
|
);
|
||||||
|
next.arm_r.orientation =
|
||||||
|
Quaternion::rotation_z(movement1abs * -0.8 + movement2abs * 1.0)
|
||||||
|
* Quaternion::rotation_x(movement1abs * 0.4 + movement2abs * 0.3);
|
||||||
|
next.arm_r.position = Vec3::new(
|
||||||
|
0.0,
|
||||||
|
7.0 * movement1abs - 3.0 * movement2abs,
|
||||||
|
-0.8 * mirror_var,
|
||||||
|
);
|
||||||
|
next.pincer_r1.position =
|
||||||
|
Vec3::new(0.0, -3.0 * movement1abs + 4.0 * movement2abs, 0.0);
|
||||||
|
|
||||||
|
next.arm_l.orientation =
|
||||||
|
Quaternion::rotation_z(movement1abs * 0.8 + movement2abs * -1.0)
|
||||||
|
* Quaternion::rotation_x(movement1abs * 0.4 + movement2abs * 0.3);
|
||||||
|
next.arm_l.position = Vec3::new(
|
||||||
|
0.0,
|
||||||
|
7.0 * movement1abs - 3.0 * movement2abs,
|
||||||
|
0.8 * mirror_var,
|
||||||
|
);
|
||||||
|
next.pincer_l1.position =
|
||||||
|
Vec3::new(0.0, -3.0 * movement1abs + 4.0 * movement2abs, 0.0);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
65
voxygen/anim/src/crustacean/idle.rs
Normal file
65
voxygen/anim/src/crustacean/idle.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CrustaceanSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct IdleAnimation;
|
||||||
|
|
||||||
|
impl Animation for IdleAnimation {
|
||||||
|
type Dependency<'a> = f32;
|
||||||
|
type Skeleton = CrustaceanSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"crustacean_idle\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_idle")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
_global_time: Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
_rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
next.chest.scale = Vec3::one() * s_a.scaler;
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1);
|
||||||
|
|
||||||
|
let arm = (anim_time * 0.2).sin() * 0.03;
|
||||||
|
let clasp_l =
|
||||||
|
(((anim_time * 0.1).fract() * 2.0 - 1.0) * (anim_time * 2.0).sin().powi(2)).powi(16);
|
||||||
|
let clasp_r = (((anim_time * 0.105 + 33.0).fract() * 2.0 - 1.0)
|
||||||
|
* (anim_time * 1.95 + 20.0).sin().powi(2))
|
||||||
|
.powi(16);
|
||||||
|
|
||||||
|
next.arm_l.position = Vec3::zero();
|
||||||
|
next.arm_l.orientation = Quaternion::rotation_x(arm);
|
||||||
|
next.arm_r.position = Vec3::zero();
|
||||||
|
next.arm_r.orientation = Quaternion::rotation_x(arm);
|
||||||
|
|
||||||
|
next.pincer_l0.position = Vec3::zero();
|
||||||
|
next.pincer_l1.position = Vec3::zero();
|
||||||
|
next.pincer_l1.orientation = Quaternion::rotation_z(clasp_l * 0.15);
|
||||||
|
next.pincer_r0.position = Vec3::zero();
|
||||||
|
next.pincer_r1.position = Vec3::zero();
|
||||||
|
next.pincer_r1.orientation = Quaternion::rotation_z(-clasp_r * 0.15);
|
||||||
|
|
||||||
|
next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fl.orientation = Quaternion::rotation_z(s_a.leg_ori.0);
|
||||||
|
next.leg_fr.orientation = Quaternion::rotation_z(-s_a.leg_ori.0);
|
||||||
|
|
||||||
|
next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cl.orientation = Quaternion::rotation_z(s_a.leg_ori.1);
|
||||||
|
next.leg_cr.orientation = Quaternion::rotation_z(-s_a.leg_ori.1);
|
||||||
|
|
||||||
|
next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_bl.orientation = Quaternion::rotation_z(s_a.leg_ori.2);
|
||||||
|
next.leg_br.orientation = Quaternion::rotation_z(-s_a.leg_ori.2);
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
54
voxygen/anim/src/crustacean/jump.rs
Normal file
54
voxygen/anim/src/crustacean/jump.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CrustaceanSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct JumpAnimation;
|
||||||
|
|
||||||
|
impl Animation for JumpAnimation {
|
||||||
|
type Dependency<'a> = (f32, Vec3<f32>, Vec3<f32>, f32, Vec3<f32>);
|
||||||
|
type Skeleton = CrustaceanSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"crustacean_jump\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_jump")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(_velocity, _orientation, _last_ori, _global_time, _avg_vel): Self::Dependency<'_>,
|
||||||
|
_anim_time: f32,
|
||||||
|
_rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
next.chest.scale = Vec3::one() * s_a.scaler;
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1);
|
||||||
|
|
||||||
|
let up_rot = 0.2;
|
||||||
|
|
||||||
|
next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fl.orientation =
|
||||||
|
Quaternion::rotation_z(s_a.leg_ori.0) * Quaternion::rotation_y(up_rot);
|
||||||
|
next.leg_fr.orientation =
|
||||||
|
Quaternion::rotation_z(-s_a.leg_ori.0) * Quaternion::rotation_y(-up_rot);
|
||||||
|
|
||||||
|
next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cl.orientation =
|
||||||
|
Quaternion::rotation_z(s_a.leg_ori.1) * Quaternion::rotation_y(up_rot);
|
||||||
|
next.leg_cr.orientation =
|
||||||
|
Quaternion::rotation_z(-s_a.leg_ori.1) * Quaternion::rotation_y(-up_rot);
|
||||||
|
|
||||||
|
next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_bl.orientation =
|
||||||
|
Quaternion::rotation_z(s_a.leg_ori.2) * Quaternion::rotation_y(up_rot);
|
||||||
|
next.leg_br.orientation =
|
||||||
|
Quaternion::rotation_z(-s_a.leg_ori.2) * Quaternion::rotation_y(-up_rot);
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
143
voxygen/anim/src/crustacean/mod.rs
Normal file
143
voxygen/anim/src/crustacean/mod.rs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
mod alpha;
|
||||||
|
mod combomelee;
|
||||||
|
mod idle;
|
||||||
|
mod jump;
|
||||||
|
mod run;
|
||||||
|
mod stunned;
|
||||||
|
mod swim;
|
||||||
|
|
||||||
|
// Reexports
|
||||||
|
pub use self::{
|
||||||
|
alpha::AlphaAnimation, combomelee::ComboAnimation, idle::IdleAnimation, jump::JumpAnimation,
|
||||||
|
run::RunAnimation, stunned::StunnedAnimation, swim::SwimAnimation,
|
||||||
|
};
|
||||||
|
|
||||||
|
use common::comp::{self};
|
||||||
|
|
||||||
|
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton};
|
||||||
|
|
||||||
|
pub type Body = comp::crustacean::Body;
|
||||||
|
|
||||||
|
skeleton_impls!(struct CrustaceanSkeleton {
|
||||||
|
+ chest,
|
||||||
|
+ tail_f,
|
||||||
|
+ tail_b,
|
||||||
|
+ arm_l,
|
||||||
|
+ pincer_l0,
|
||||||
|
+ pincer_l1,
|
||||||
|
+ arm_r,
|
||||||
|
+ pincer_r0,
|
||||||
|
+ pincer_r1,
|
||||||
|
+ leg_fl,
|
||||||
|
+ leg_cl,
|
||||||
|
+ leg_bl,
|
||||||
|
+ leg_fr,
|
||||||
|
+ leg_cr,
|
||||||
|
+ leg_br,
|
||||||
|
});
|
||||||
|
|
||||||
|
impl Skeleton for CrustaceanSkeleton {
|
||||||
|
type Attr = SkeletonAttr;
|
||||||
|
type Body = Body;
|
||||||
|
|
||||||
|
const BONE_COUNT: usize = 15;
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const COMPUTE_FN: &'static [u8] = b"crustacean_compute_s\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_compute_s")]
|
||||||
|
|
||||||
|
fn compute_matrices_inner(
|
||||||
|
&self,
|
||||||
|
base_mat: Mat4<f32>,
|
||||||
|
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
|
||||||
|
body: Self::Body,
|
||||||
|
) -> Offsets {
|
||||||
|
let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 6.0);
|
||||||
|
|
||||||
|
let chest_mat = base_mat * Mat4::<f32>::from(self.chest);
|
||||||
|
let tail_f_mat = chest_mat * Mat4::<f32>::from(self.tail_f);
|
||||||
|
let tail_b_mat = chest_mat * Mat4::<f32>::from(self.tail_b);
|
||||||
|
let arm_l_mat = chest_mat * Mat4::<f32>::from(self.arm_l);
|
||||||
|
let pincer_l0_mat = arm_l_mat * Mat4::<f32>::from(self.pincer_l0);
|
||||||
|
let pincer_l1_mat = pincer_l0_mat * Mat4::<f32>::from(self.pincer_l1);
|
||||||
|
let arm_r_mat = chest_mat * Mat4::<f32>::from(self.arm_r);
|
||||||
|
let pincer_r0_mat = arm_r_mat * Mat4::<f32>::from(self.pincer_r0);
|
||||||
|
let pincer_r1_mat = pincer_r0_mat * Mat4::<f32>::from(self.pincer_r1);
|
||||||
|
let leg_fl_mat = chest_mat * Mat4::<f32>::from(self.leg_fl);
|
||||||
|
let leg_cl_mat = chest_mat * Mat4::<f32>::from(self.leg_cl);
|
||||||
|
let leg_bl_mat = chest_mat * Mat4::<f32>::from(self.leg_bl);
|
||||||
|
let leg_fr_mat = chest_mat * Mat4::<f32>::from(self.leg_fr);
|
||||||
|
let leg_cr_mat = chest_mat * Mat4::<f32>::from(self.leg_cr);
|
||||||
|
let leg_br_mat = chest_mat * Mat4::<f32>::from(self.leg_br);
|
||||||
|
|
||||||
|
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
|
||||||
|
make_bone(chest_mat),
|
||||||
|
make_bone(tail_f_mat),
|
||||||
|
make_bone(tail_b_mat),
|
||||||
|
make_bone(arm_l_mat),
|
||||||
|
make_bone(pincer_l0_mat),
|
||||||
|
make_bone(pincer_l1_mat),
|
||||||
|
make_bone(arm_r_mat),
|
||||||
|
make_bone(pincer_r0_mat),
|
||||||
|
make_bone(pincer_r1_mat),
|
||||||
|
make_bone(leg_fl_mat),
|
||||||
|
make_bone(leg_cl_mat),
|
||||||
|
make_bone(leg_bl_mat),
|
||||||
|
make_bone(leg_fr_mat),
|
||||||
|
make_bone(leg_cr_mat),
|
||||||
|
make_bone(leg_br_mat),
|
||||||
|
];
|
||||||
|
|
||||||
|
// TODO: mount points
|
||||||
|
//use comp::arthropod::Species::*;
|
||||||
|
let (mount_bone_mat, mount_bone_ori) = (chest_mat, self.chest.orientation);
|
||||||
|
// Offset from the mounted bone's origin.
|
||||||
|
// Note: This could be its own bone if we need to animate it independently.
|
||||||
|
let mount_position = (mount_bone_mat * Vec4::from_point(mount_point(&body)))
|
||||||
|
.homogenized()
|
||||||
|
.xyz();
|
||||||
|
// NOTE: We apply the ori from base_mat externally so we don't need to worry
|
||||||
|
// about it here for now.
|
||||||
|
let mount_orientation = mount_bone_ori;
|
||||||
|
|
||||||
|
Offsets {
|
||||||
|
lantern: None,
|
||||||
|
viewpoint: Some((chest_mat * Vec4::new(0.0, 7.0, 0.0, 1.0)).xyz()),
|
||||||
|
mount_bone: Transform {
|
||||||
|
position: mount_position,
|
||||||
|
orientation: mount_orientation,
|
||||||
|
scale: Vec3::one(),
|
||||||
|
},
|
||||||
|
primary_trail_mat: None,
|
||||||
|
secondary_trail_mat: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SkeletonAttr {
|
||||||
|
chest: (f32, f32),
|
||||||
|
leg_f: (f32, f32, f32),
|
||||||
|
leg_c: (f32, f32, f32),
|
||||||
|
leg_b: (f32, f32, f32),
|
||||||
|
leg_ori: (f32, f32, f32),
|
||||||
|
scaler: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Body> for SkeletonAttr {
|
||||||
|
fn from(_value: &Body) -> Self {
|
||||||
|
Self {
|
||||||
|
chest: (0.0, 0.0),
|
||||||
|
leg_f: (0.0, 0.0, 0.0),
|
||||||
|
leg_c: (0.0, 0.0, 0.0),
|
||||||
|
leg_b: (0.0, 0.0, 0.0),
|
||||||
|
leg_ori: (-0.4, 0.0, 0.4),
|
||||||
|
scaler: 0.62,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mount_point(_body: &Body) -> Vec3<f32> {
|
||||||
|
// TODO: mount points
|
||||||
|
//use comp::arthropod::{BodyType::*, Species::*};
|
||||||
|
(0.0, -6.0, 6.0).into()
|
||||||
|
}
|
100
voxygen/anim/src/crustacean/run.rs
Normal file
100
voxygen/anim/src/crustacean/run.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CrustaceanSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
pub struct RunAnimation;
|
||||||
|
|
||||||
|
impl Animation for RunAnimation {
|
||||||
|
type Dependency<'a> = (Vec3<f32>, Vec3<f32>, Vec3<f32>, f32, Vec3<f32>, f32);
|
||||||
|
type Skeleton = CrustaceanSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"crustacean_run\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_run")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(velocity, orientation, _last_ori, _global_time, avg_vel, acc_vel): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
let speed = (Vec2::<f32>::from(velocity).magnitude()).min(22.0);
|
||||||
|
*rate = 1.0;
|
||||||
|
|
||||||
|
let speednorm = speed / 13.0;
|
||||||
|
|
||||||
|
let direction = velocity.y * 0.098 * orientation.y + velocity.x * 0.098 * orientation.x;
|
||||||
|
|
||||||
|
let side =
|
||||||
|
(velocity.x * -0.098 * orientation.y + velocity.y * 0.098 * orientation.x) * -1.0;
|
||||||
|
let sideabs = side.abs();
|
||||||
|
|
||||||
|
let mixed_vel = (acc_vel + anim_time * 6.0) * 0.8; //sets run frequency using speed, with anim_time setting a floor
|
||||||
|
|
||||||
|
//create a mix between a sine and a square wave
|
||||||
|
//(controllable with ratio variable)
|
||||||
|
let ratio = 0.1;
|
||||||
|
let wave1 = (mixed_vel).sin();
|
||||||
|
let wave2 = (mixed_vel - PI / 2.0).sin();
|
||||||
|
let wave3 = (mixed_vel + PI / 2.0).sin();
|
||||||
|
let wave4 = (mixed_vel + PI).sin();
|
||||||
|
let slow_wave = (mixed_vel / 20.0).sin();
|
||||||
|
let foot1 = wave1.abs().powf(ratio) * wave1.signum();
|
||||||
|
let foot2 = wave2.abs().powf(ratio) * wave2.signum();
|
||||||
|
let foot3 = wave3.abs().powf(ratio) * wave3.signum();
|
||||||
|
let foot4 = wave4.abs().powf(ratio) * wave4.signum();
|
||||||
|
let turn = slow_wave.abs().powf(ratio) * slow_wave.signum();
|
||||||
|
|
||||||
|
let x_tilt = avg_vel.z.atan2(avg_vel.xy().magnitude()) * speednorm;
|
||||||
|
|
||||||
|
next.chest.scale = Vec3::one() * s_a.scaler;
|
||||||
|
|
||||||
|
let up_rot = 0.3;
|
||||||
|
let sideways = (PI / 2.0) * turn;
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + x_tilt);
|
||||||
|
next.chest.orientation = Quaternion::rotation_x((mixed_vel).sin().max(0.0) * 0.06 + x_tilt)
|
||||||
|
* Quaternion::rotation_z(sideways + ((mixed_vel + PI / 2.0).sin() * 0.06));
|
||||||
|
|
||||||
|
next.arm_l.orientation = Quaternion::rotation_x(1.0)
|
||||||
|
* Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(0.3 - foot2 * 0.1 * direction);
|
||||||
|
next.arm_r.orientation = Quaternion::rotation_x(1.0)
|
||||||
|
* Quaternion::rotation_y(-foot1.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(-0.2 - foot3 * 0.1 * direction);
|
||||||
|
|
||||||
|
next.arm_l.position = Vec3::new(0.0, 5.0, 0.0);
|
||||||
|
next.arm_r.position = Vec3::new(0.0, 5.0, 0.0);
|
||||||
|
|
||||||
|
next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fl.orientation = Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(s_a.leg_ori.0 + foot2 * 0.1 * direction);
|
||||||
|
next.leg_fr.orientation = Quaternion::rotation_y(-foot1.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(-s_a.leg_ori.0 - foot3 * 0.1 * direction);
|
||||||
|
|
||||||
|
next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cl.orientation = Quaternion::rotation_x(foot4 * 0.1 * direction)
|
||||||
|
* Quaternion::rotation_y(foot1.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(s_a.leg_ori.1 + foot3 * 0.2 * direction);
|
||||||
|
next.leg_cr.orientation = Quaternion::rotation_x(foot1 * 0.1 * direction)
|
||||||
|
* Quaternion::rotation_y(foot1.min(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(-s_a.leg_ori.1 - foot2 * 0.2 * direction);
|
||||||
|
|
||||||
|
next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_bl.orientation = Quaternion::rotation_x(foot4 * 0.2)
|
||||||
|
* Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(s_a.leg_ori.2 + foot3 * 0.2 * -direction);
|
||||||
|
next.leg_br.orientation = Quaternion::rotation_x(foot1 * 0.2 * direction)
|
||||||
|
* Quaternion::rotation_y(foot4.min(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(-s_a.leg_ori.2 - foot2 * 0.2 * -direction);
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
72
voxygen/anim/src/crustacean/stunned.rs
Normal file
72
voxygen/anim/src/crustacean/stunned.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CrustaceanSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::states::utils::StageSection;
|
||||||
|
|
||||||
|
pub struct StunnedAnimation;
|
||||||
|
|
||||||
|
impl Animation for StunnedAnimation {
|
||||||
|
type Dependency<'a> = (f32, f32, Option<StageSection>, f32);
|
||||||
|
type Skeleton = CrustaceanSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"crustacean_stunned\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_stunned")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(_velocity, global_time, stage_section, timer): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
_rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
let (_movement1base, movement2, twitch) = match stage_section {
|
||||||
|
Some(StageSection::Buildup) => (anim_time.powf(0.1), 0.0, anim_time),
|
||||||
|
Some(StageSection::Recover) => (1.0, anim_time.powf(4.0), 1.0),
|
||||||
|
_ => (0.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pullback = (1.0 - movement2) * 0.1;
|
||||||
|
|
||||||
|
let subtract = global_time - timer;
|
||||||
|
let check = subtract - subtract.trunc();
|
||||||
|
let mirror = (check - 0.5).signum();
|
||||||
|
let twitch1 = mirror * (twitch * 5.0).cos() * pullback;
|
||||||
|
let twitch2 = mirror * (twitch * 5.0).sin() * pullback;
|
||||||
|
|
||||||
|
next.chest.scale = Vec3::one() * s_a.scaler;
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1);
|
||||||
|
|
||||||
|
next.arm_l.orientation = Quaternion::rotation_x(-twitch2 * 1.2);
|
||||||
|
next.arm_r.orientation = Quaternion::rotation_x(twitch2 * 1.2);
|
||||||
|
next.pincer_l1.orientation = Quaternion::rotation_z(0.17);
|
||||||
|
next.pincer_r1.orientation = Quaternion::rotation_z(-0.17);
|
||||||
|
|
||||||
|
next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
|
||||||
|
next.leg_fl.orientation =
|
||||||
|
Quaternion::rotation_z(s_a.leg_ori.0) * Quaternion::rotation_x(twitch1 * 0.8 + 0.4);
|
||||||
|
next.leg_fr.orientation =
|
||||||
|
Quaternion::rotation_z(-s_a.leg_ori.0) * Quaternion::rotation_x(-twitch1 * 0.8 - 0.4);
|
||||||
|
|
||||||
|
next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cl.orientation =
|
||||||
|
Quaternion::rotation_z(s_a.leg_ori.1) * Quaternion::rotation_y(twitch2 * 0.4 + 0.4);
|
||||||
|
next.leg_cr.orientation =
|
||||||
|
Quaternion::rotation_z(-s_a.leg_ori.1) * Quaternion::rotation_y(-twitch2 * 0.4 - 0.4);
|
||||||
|
|
||||||
|
next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_bl.orientation =
|
||||||
|
Quaternion::rotation_z(s_a.leg_ori.2) * Quaternion::rotation_y(twitch2 * 0.4 + 0.4);
|
||||||
|
next.leg_br.orientation =
|
||||||
|
Quaternion::rotation_z(-s_a.leg_ori.2) * Quaternion::rotation_y(-twitch2 * 0.4 - 0.4);
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
99
voxygen/anim/src/crustacean/swim.rs
Normal file
99
voxygen/anim/src/crustacean/swim.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CrustaceanSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
pub struct SwimAnimation;
|
||||||
|
|
||||||
|
impl Animation for SwimAnimation {
|
||||||
|
type Dependency<'a> = (Vec3<f32>, Vec3<f32>, Vec3<f32>, f32, Vec3<f32>, f32);
|
||||||
|
type Skeleton = CrustaceanSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"crustacean_swim\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "crustacean_swim")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(velocity, orientation, _last_ori, _global_time, avg_vel, acc_vel): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
let speed = (Vec2::<f32>::from(velocity).magnitude()).min(22.0);
|
||||||
|
*rate = 1.0;
|
||||||
|
|
||||||
|
let speednorm = speed / 13.0;
|
||||||
|
|
||||||
|
let direction = velocity.y * 0.098 * orientation.y + velocity.x * 0.098 * orientation.x;
|
||||||
|
|
||||||
|
let side =
|
||||||
|
(velocity.x * -0.098 * orientation.y + velocity.y * 0.098 * orientation.x) * -1.0;
|
||||||
|
let sideabs = side.abs();
|
||||||
|
|
||||||
|
let mixed_vel = (acc_vel + anim_time * 6.0) * 0.8; //sets run frequency using speed, with anim_time setting a floor
|
||||||
|
|
||||||
|
//create a mix between a sine and a square wave
|
||||||
|
//(controllable with ratio variable)
|
||||||
|
let ratio = 0.1;
|
||||||
|
let wave1 = (mixed_vel).sin();
|
||||||
|
let wave2 = (mixed_vel - PI / 2.0).sin();
|
||||||
|
let wave3 = (mixed_vel + PI / 2.0).sin();
|
||||||
|
let wave4 = (mixed_vel + PI).sin();
|
||||||
|
|
||||||
|
let foot1 = wave1.abs().powf(ratio) * wave1.signum();
|
||||||
|
let foot2 = wave2.abs().powf(ratio) * wave2.signum();
|
||||||
|
let foot3 = wave3.abs().powf(ratio) * wave3.signum();
|
||||||
|
let foot4 = wave4.abs().powf(ratio) * wave4.signum();
|
||||||
|
|
||||||
|
let x_tilt = avg_vel.z.atan2(avg_vel.xy().magnitude()) * speednorm;
|
||||||
|
|
||||||
|
next.chest.scale = Vec3::one() * s_a.scaler;
|
||||||
|
|
||||||
|
let up_rot = 0.3;
|
||||||
|
let turnaround = PI;
|
||||||
|
let swim = -0.3 * foot2;
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + x_tilt);
|
||||||
|
next.chest.orientation = Quaternion::rotation_x((mixed_vel).sin().max(0.0) * 0.06 + x_tilt)
|
||||||
|
* Quaternion::rotation_z(turnaround + ((mixed_vel + PI / 2.0).sin() * 0.06));
|
||||||
|
|
||||||
|
next.arm_l.orientation = Quaternion::rotation_x(0.1 * foot3)
|
||||||
|
* Quaternion::rotation_y(foot4.max(sideabs * -1.0) * up_rot)
|
||||||
|
* Quaternion::rotation_z((PI / -5.0) + 0.3 - foot2 * 0.1 * direction);
|
||||||
|
next.arm_r.orientation = Quaternion::rotation_x(0.1 * foot3)
|
||||||
|
* Quaternion::rotation_y(-foot1.max(sideabs * -1.0) * up_rot)
|
||||||
|
* Quaternion::rotation_z((PI / 5.0) + -0.2 - foot3 * 0.1 * direction);
|
||||||
|
|
||||||
|
next.arm_l.position = Vec3::new(0.0, -1.0, 0.0);
|
||||||
|
next.arm_r.position = Vec3::new(0.0, -1.0, 0.0);
|
||||||
|
next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2 + 1.0);
|
||||||
|
next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2 + 1.0);
|
||||||
|
next.leg_fl.orientation = Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(swim + s_a.leg_ori.0 + foot2 * 0.1 * -direction);
|
||||||
|
next.leg_fr.orientation = Quaternion::rotation_y(-foot1.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(-swim + -s_a.leg_ori.0 - foot3 * 0.1 * -direction);
|
||||||
|
|
||||||
|
next.leg_cl.position = Vec3::new(-s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cr.position = Vec3::new(s_a.leg_c.0, s_a.leg_c.1, s_a.leg_c.2);
|
||||||
|
next.leg_cl.orientation = Quaternion::rotation_x(foot4 * 0.1 * -direction)
|
||||||
|
* Quaternion::rotation_y(foot1.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(swim + s_a.leg_ori.1 + foot3 * 0.2 * -direction);
|
||||||
|
next.leg_cr.orientation = Quaternion::rotation_x(foot1 * 0.1 * -direction)
|
||||||
|
* Quaternion::rotation_y(foot1.min(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(-swim + -s_a.leg_ori.1 - foot2 * 0.2 * -direction);
|
||||||
|
|
||||||
|
next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
|
||||||
|
next.leg_bl.orientation = Quaternion::rotation_x(foot4 * 0.2)
|
||||||
|
* Quaternion::rotation_y(foot4.max(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(swim + s_a.leg_ori.2 + foot3 * 0.2 * direction);
|
||||||
|
next.leg_br.orientation = Quaternion::rotation_x(foot1 * 0.2 * -direction)
|
||||||
|
* Quaternion::rotation_y(foot4.min(sideabs * -0.5) * up_rot)
|
||||||
|
* Quaternion::rotation_z(-swim + -s_a.leg_ori.2 - foot2 * 0.2 * direction);
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
@ -53,6 +53,7 @@ pub mod biped_small;
|
|||||||
pub mod bird_large;
|
pub mod bird_large;
|
||||||
pub mod bird_medium;
|
pub mod bird_medium;
|
||||||
pub mod character;
|
pub mod character;
|
||||||
|
pub mod crustacean;
|
||||||
pub mod dragon;
|
pub mod dragon;
|
||||||
pub mod fish_medium;
|
pub mod fish_medium;
|
||||||
pub mod fish_small;
|
pub mod fish_small;
|
||||||
|
@ -788,6 +788,7 @@ fn body_species(body: &Body) -> String {
|
|||||||
Body::QuadrupedLow(body) => format!("{:?}", body.species),
|
Body::QuadrupedLow(body) => format!("{:?}", body.species),
|
||||||
Body::Arthropod(body) => format!("{:?}", body.species),
|
Body::Arthropod(body) => format!("{:?}", body.species),
|
||||||
Body::Ship(body) => format!("{:?}", body),
|
Body::Ship(body) => format!("{:?}", body),
|
||||||
|
Body::Crustacean(body) => format!("{:?}", body.species),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ use common::{
|
|||||||
biped_small,
|
biped_small,
|
||||||
bird_large::{self, BodyType as BLABodyType, Species as BLASpecies},
|
bird_large::{self, BodyType as BLABodyType, Species as BLASpecies},
|
||||||
bird_medium::{self, BodyType as BMBodyType, Species as BMSpecies},
|
bird_medium::{self, BodyType as BMBodyType, Species as BMSpecies},
|
||||||
|
crustacean::{self, BodyType as CBodyType, Species as CSpecies},
|
||||||
dragon::{self, BodyType as DBodyType, Species as DSpecies},
|
dragon::{self, BodyType as DBodyType, Species as DSpecies},
|
||||||
fish_medium::{self, BodyType as FMBodyType, Species as FMSpecies},
|
fish_medium::{self, BodyType as FMBodyType, Species as FMSpecies},
|
||||||
fish_small::{self, BodyType as FSBodyType, Species as FSSpecies},
|
fish_small::{self, BodyType as FSBodyType, Species as FSSpecies},
|
||||||
@ -2688,6 +2689,385 @@ impl ArthropodLateralSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//////
|
//////
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct CrustaceanCentralSpec(HashMap<(CSpecies, CBodyType), CrustCentralVoxSpec>);
|
||||||
|
impl_concatenate_for_wrapper!(CrustaceanCentralSpec);
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct CrustCentralVoxSpec {
|
||||||
|
chest: CrustaceanCentralSubSpec,
|
||||||
|
tail_f: CrustaceanCentralSubSpec,
|
||||||
|
tail_b: CrustaceanCentralSubSpec,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct CrustaceanCentralSubSpec {
|
||||||
|
offset: [f32; 3], // Should be relative to initial origin
|
||||||
|
central: VoxSimple,
|
||||||
|
#[serde(default)]
|
||||||
|
model_index: u32,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct CrustaceanLateralSpec(HashMap<(CSpecies, CBodyType), CrustLateralVoxSpec>);
|
||||||
|
impl_concatenate_for_wrapper!(CrustaceanLateralSpec);
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct CrustLateralVoxSpec {
|
||||||
|
arm_l: CrustaceanLateralSubSpec,
|
||||||
|
pincer_l0: CrustaceanLateralSubSpec,
|
||||||
|
pincer_l1: CrustaceanLateralSubSpec,
|
||||||
|
arm_r: CrustaceanLateralSubSpec,
|
||||||
|
pincer_r0: CrustaceanLateralSubSpec,
|
||||||
|
pincer_r1: CrustaceanLateralSubSpec,
|
||||||
|
leg_fl: CrustaceanLateralSubSpec,
|
||||||
|
leg_cl: CrustaceanLateralSubSpec,
|
||||||
|
leg_bl: CrustaceanLateralSubSpec,
|
||||||
|
leg_fr: CrustaceanLateralSubSpec,
|
||||||
|
leg_cr: CrustaceanLateralSubSpec,
|
||||||
|
leg_br: CrustaceanLateralSubSpec,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct CrustaceanLateralSubSpec {
|
||||||
|
offset: [f32; 3], // Should be relative to initial origin
|
||||||
|
lateral: VoxSimple,
|
||||||
|
#[serde(default)]
|
||||||
|
model_index: u32,
|
||||||
|
}
|
||||||
|
make_vox_spec!(
|
||||||
|
crustacean::Body,
|
||||||
|
struct CrustaceanSpec {
|
||||||
|
central: CrustaceanCentralSpec = "voxygen.voxel.crustacean_central_manifest",
|
||||||
|
lateral: CrustaceanLateralSpec = "voxygen.voxel.crustacean_lateral_manifest",
|
||||||
|
},
|
||||||
|
|FigureKey { body, extra, .. }, spec| {
|
||||||
|
let third_person = extra.as_ref().and_then(|loadout| loadout.third_person.as_ref());
|
||||||
|
|
||||||
|
[
|
||||||
|
third_person.map(|_| {
|
||||||
|
spec.central.read().0.mesh_chest(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
Some(spec.central.read().0.mesh_tail_f(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.central.read().0.mesh_tail_b(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_arm_l(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_pincer_l0(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_pincer_l1(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_arm_r(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_pincer_r0(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_pincer_r1(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_leg_fl(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_leg_cl(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_leg_bl(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_leg_fr(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_leg_cr(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
Some(spec.lateral.read().0.mesh_leg_br(
|
||||||
|
body.species,
|
||||||
|
body.body_type,
|
||||||
|
)),
|
||||||
|
None,
|
||||||
|
]
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
impl CrustaceanCentralSpec {
|
||||||
|
fn mesh_chest(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No chest specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let central = graceful_load_segment(&spec.chest.central.0, spec.chest.model_index);
|
||||||
|
|
||||||
|
(central, Vec3::from(spec.chest.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_tail_f(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No front tail specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let central = graceful_load_segment(&spec.tail_f.central.0, spec.tail_f.model_index);
|
||||||
|
|
||||||
|
(central, Vec3::from(spec.tail_f.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_tail_b(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No back tail specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let central = graceful_load_segment(&spec.tail_b.central.0, spec.tail_b.model_index);
|
||||||
|
|
||||||
|
(central, Vec3::from(spec.tail_b.offset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl CrustaceanLateralSpec {
|
||||||
|
fn mesh_arm_l(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No left arm specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral =
|
||||||
|
graceful_load_segment_flipped(&spec.arm_l.lateral.0, true, spec.arm_l.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.arm_l.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_pincer_l0(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No left major pincer specification exists for the combination of {:?} and \
|
||||||
|
{:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral = graceful_load_segment_flipped(
|
||||||
|
&spec.pincer_l0.lateral.0,
|
||||||
|
true,
|
||||||
|
spec.pincer_l0.model_index,
|
||||||
|
);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.pincer_l0.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_pincer_l1(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No left minor pincer specification exists for the combination of {:?} and \
|
||||||
|
{:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral = graceful_load_segment_flipped(
|
||||||
|
&spec.pincer_l1.lateral.0,
|
||||||
|
true,
|
||||||
|
spec.pincer_l1.model_index,
|
||||||
|
);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.pincer_l1.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_arm_r(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No right arm specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral = graceful_load_segment(&spec.arm_r.lateral.0, spec.arm_r.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.arm_r.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_pincer_r0(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No right major pincer specification exists for the combination of {:?} and \
|
||||||
|
{:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral = graceful_load_segment(&spec.pincer_r0.lateral.0, spec.pincer_r0.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.pincer_r0.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_pincer_r1(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No right minor pincer specification exists for the combination of {:?} and \
|
||||||
|
{:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral = graceful_load_segment(&spec.pincer_r1.lateral.0, spec.pincer_r1.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.pincer_r1.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_leg_fl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No front left leg specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral =
|
||||||
|
graceful_load_segment_flipped(&spec.leg_fl.lateral.0, true, spec.leg_fl.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.leg_fl.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_leg_cl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No center left leg specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral =
|
||||||
|
graceful_load_segment_flipped(&spec.leg_cl.lateral.0, true, spec.leg_cl.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.leg_cl.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_leg_bl(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No back left leg specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral =
|
||||||
|
graceful_load_segment_flipped(&spec.leg_bl.lateral.0, true, spec.leg_bl.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.leg_bl.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_leg_fr(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No front right leg specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral = graceful_load_segment(&spec.leg_fr.lateral.0, spec.leg_fr.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.leg_fr.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_leg_cr(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No center right leg specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral = graceful_load_segment(&spec.leg_cr.lateral.0, spec.leg_cr.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.leg_cr.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mesh_leg_br(&self, species: CSpecies, body_type: CBodyType) -> BoneMeshes {
|
||||||
|
let spec = match self.0.get(&(species, body_type)) {
|
||||||
|
Some(spec) => spec,
|
||||||
|
None => {
|
||||||
|
error!(
|
||||||
|
"No back right leg specification exists for the combination of {:?} and {:?}",
|
||||||
|
species, body_type
|
||||||
|
);
|
||||||
|
return load_mesh("not_found", Vec3::new(-5.0, -5.0, -2.5));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let lateral = graceful_load_segment(&spec.leg_br.lateral.0, spec.leg_br.model_index);
|
||||||
|
|
||||||
|
(lateral, Vec3::from(spec.leg_br.offset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct FishMediumCentralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMCentralVoxSpec>);
|
struct FishMediumCentralSpec(HashMap<(FMSpecies, FMBodyType), SidedFMCentralVoxSpec>);
|
||||||
impl_concatenate_for_wrapper!(FishMediumCentralSpec);
|
impl_concatenate_for_wrapper!(FishMediumCentralSpec);
|
||||||
|
@ -28,11 +28,11 @@ use crate::{
|
|||||||
use anim::{
|
use anim::{
|
||||||
arthropod::ArthropodSkeleton, biped_large::BipedLargeSkeleton, biped_small::BipedSmallSkeleton,
|
arthropod::ArthropodSkeleton, biped_large::BipedLargeSkeleton, biped_small::BipedSmallSkeleton,
|
||||||
bird_large::BirdLargeSkeleton, bird_medium::BirdMediumSkeleton, character::CharacterSkeleton,
|
bird_large::BirdLargeSkeleton, bird_medium::BirdMediumSkeleton, character::CharacterSkeleton,
|
||||||
dragon::DragonSkeleton, fish_medium::FishMediumSkeleton, fish_small::FishSmallSkeleton,
|
crustacean::CrustaceanSkeleton, dragon::DragonSkeleton, fish_medium::FishMediumSkeleton,
|
||||||
golem::GolemSkeleton, item_drop::ItemDropSkeleton, object::ObjectSkeleton,
|
fish_small::FishSmallSkeleton, golem::GolemSkeleton, item_drop::ItemDropSkeleton,
|
||||||
quadruped_low::QuadrupedLowSkeleton, quadruped_medium::QuadrupedMediumSkeleton,
|
object::ObjectSkeleton, quadruped_low::QuadrupedLowSkeleton,
|
||||||
quadruped_small::QuadrupedSmallSkeleton, ship::ShipSkeleton, theropod::TheropodSkeleton,
|
quadruped_medium::QuadrupedMediumSkeleton, quadruped_small::QuadrupedSmallSkeleton,
|
||||||
Animation, Skeleton,
|
ship::ShipSkeleton, theropod::TheropodSkeleton, Animation, Skeleton,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
@ -213,6 +213,7 @@ struct FigureMgrStates {
|
|||||||
ship_states: HashMap<EcsEntity, FigureState<ShipSkeleton, BoundTerrainLocals>>,
|
ship_states: HashMap<EcsEntity, FigureState<ShipSkeleton, BoundTerrainLocals>>,
|
||||||
volume_states: HashMap<EcsEntity, FigureState<VolumeKey, BoundTerrainLocals>>,
|
volume_states: HashMap<EcsEntity, FigureState<VolumeKey, BoundTerrainLocals>>,
|
||||||
arthropod_states: HashMap<EcsEntity, FigureState<ArthropodSkeleton>>,
|
arthropod_states: HashMap<EcsEntity, FigureState<ArthropodSkeleton>>,
|
||||||
|
crustacean_states: HashMap<EcsEntity, FigureState<CrustaceanSkeleton>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FigureMgrStates {
|
impl FigureMgrStates {
|
||||||
@ -236,6 +237,7 @@ impl FigureMgrStates {
|
|||||||
ship_states: HashMap::new(),
|
ship_states: HashMap::new(),
|
||||||
volume_states: HashMap::new(),
|
volume_states: HashMap::new(),
|
||||||
arthropod_states: HashMap::new(),
|
arthropod_states: HashMap::new(),
|
||||||
|
crustacean_states: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,6 +313,10 @@ impl FigureMgrStates {
|
|||||||
.arthropod_states
|
.arthropod_states
|
||||||
.get_mut(entity)
|
.get_mut(entity)
|
||||||
.map(DerefMut::deref_mut),
|
.map(DerefMut::deref_mut),
|
||||||
|
Body::Crustacean(_) => self
|
||||||
|
.crustacean_states
|
||||||
|
.get_mut(entity)
|
||||||
|
.map(DerefMut::deref_mut),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,6 +351,7 @@ impl FigureMgrStates {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Body::Arthropod(_) => self.arthropod_states.remove(entity).map(|e| e.meta),
|
Body::Arthropod(_) => self.arthropod_states.remove(entity).map(|e| e.meta),
|
||||||
|
Body::Crustacean(_) => self.crustacean_states.remove(entity).map(|e| e.meta),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,6 +375,7 @@ impl FigureMgrStates {
|
|||||||
self.ship_states.retain(|k, v| f(k, &mut *v));
|
self.ship_states.retain(|k, v| f(k, &mut *v));
|
||||||
self.volume_states.retain(|k, v| f(k, &mut *v));
|
self.volume_states.retain(|k, v| f(k, &mut *v));
|
||||||
self.arthropod_states.retain(|k, v| f(k, &mut *v));
|
self.arthropod_states.retain(|k, v| f(k, &mut *v));
|
||||||
|
self.crustacean_states.retain(|k, v| f(k, &mut *v));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(&self) -> usize {
|
fn count(&self) -> usize {
|
||||||
@ -390,6 +398,7 @@ impl FigureMgrStates {
|
|||||||
+ self.ship_states.len()
|
+ self.ship_states.len()
|
||||||
+ self.volume_states.len()
|
+ self.volume_states.len()
|
||||||
+ self.arthropod_states.len()
|
+ self.arthropod_states.len()
|
||||||
|
+ self.crustacean_states.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_visible(&self) -> usize {
|
fn count_visible(&self) -> usize {
|
||||||
@ -472,6 +481,11 @@ impl FigureMgrStates {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, c)| c.visible())
|
.filter(|(_, c)| c.visible())
|
||||||
.count()
|
.count()
|
||||||
|
+ self
|
||||||
|
.crustacean_states
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, c)| c.visible())
|
||||||
|
.count()
|
||||||
+ self.ship_states.iter().filter(|(_, c)| c.visible()).count()
|
+ self.ship_states.iter().filter(|(_, c)| c.visible()).count()
|
||||||
+ self
|
+ self
|
||||||
.volume_states
|
.volume_states
|
||||||
@ -524,6 +538,7 @@ pub struct FigureMgr {
|
|||||||
golem_model_cache: FigureModelCache<GolemSkeleton>,
|
golem_model_cache: FigureModelCache<GolemSkeleton>,
|
||||||
volume_model_cache: FigureModelCache<VolumeKey>,
|
volume_model_cache: FigureModelCache<VolumeKey>,
|
||||||
arthropod_model_cache: FigureModelCache<ArthropodSkeleton>,
|
arthropod_model_cache: FigureModelCache<ArthropodSkeleton>,
|
||||||
|
crustacean_model_cache: FigureModelCache<CrustaceanSkeleton>,
|
||||||
states: FigureMgrStates,
|
states: FigureMgrStates,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,6 +564,7 @@ impl FigureMgr {
|
|||||||
golem_model_cache: FigureModelCache::new(),
|
golem_model_cache: FigureModelCache::new(),
|
||||||
volume_model_cache: FigureModelCache::new(),
|
volume_model_cache: FigureModelCache::new(),
|
||||||
arthropod_model_cache: FigureModelCache::new(),
|
arthropod_model_cache: FigureModelCache::new(),
|
||||||
|
crustacean_model_cache: FigureModelCache::new(),
|
||||||
states: FigureMgrStates::default(),
|
states: FigureMgrStates::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -574,6 +590,7 @@ impl FigureMgr {
|
|||||||
|| self.golem_model_cache.watcher_reloaded()
|
|| self.golem_model_cache.watcher_reloaded()
|
||||||
|| self.volume_model_cache.watcher_reloaded()
|
|| self.volume_model_cache.watcher_reloaded()
|
||||||
|| self.arthropod_model_cache.watcher_reloaded()
|
|| self.arthropod_model_cache.watcher_reloaded()
|
||||||
|
|| self.crustacean_model_cache.watcher_reloaded()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clean(&mut self, tick: u64) {
|
pub fn clean(&mut self, tick: u64) {
|
||||||
@ -600,6 +617,7 @@ impl FigureMgr {
|
|||||||
self.golem_model_cache.clear_models();
|
self.golem_model_cache.clear_models();
|
||||||
self.volume_model_cache.clear_models();
|
self.volume_model_cache.clear_models();
|
||||||
self.arthropod_model_cache.clear_models();
|
self.arthropod_model_cache.clear_models();
|
||||||
|
self.crustacean_model_cache.clear_models();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.model_cache.clean(&mut self.atlas, tick);
|
self.model_cache.clean(&mut self.atlas, tick);
|
||||||
@ -622,6 +640,7 @@ impl FigureMgr {
|
|||||||
self.golem_model_cache.clean(&mut self.atlas, tick);
|
self.golem_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.volume_model_cache.clean(&mut self.atlas, tick);
|
self.volume_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.arthropod_model_cache.clean(&mut self.atlas, tick);
|
self.arthropod_model_cache.clean(&mut self.atlas, tick);
|
||||||
|
self.crustacean_model_cache.clean(&mut self.atlas, tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_lighting(&mut self, scene_data: &SceneData) {
|
pub fn update_lighting(&mut self, scene_data: &SceneData) {
|
||||||
@ -4828,6 +4847,182 @@ impl FigureMgr {
|
|||||||
body,
|
body,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
Body::Crustacean(body) => {
|
||||||
|
let (model, skeleton_attr) = self.crustacean_model_cache.get_or_create_model(
|
||||||
|
renderer,
|
||||||
|
&mut self.atlas,
|
||||||
|
body,
|
||||||
|
inventory,
|
||||||
|
(),
|
||||||
|
tick,
|
||||||
|
viewpoint_camera_mode,
|
||||||
|
viewpoint_character_state,
|
||||||
|
&slow_jobs,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
let state = self
|
||||||
|
.states
|
||||||
|
.crustacean_states
|
||||||
|
.entry(entity)
|
||||||
|
.or_insert_with(|| {
|
||||||
|
FigureState::new(renderer, CrustaceanSkeleton::default(), body)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Average velocity relative to the current ground
|
||||||
|
let rel_avg_vel = state.avg_vel - physics.ground_vel;
|
||||||
|
|
||||||
|
let (character, last_character) = match (character, last_character) {
|
||||||
|
(Some(c), Some(l)) => (c, l),
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !character.same_variant(&last_character.0) {
|
||||||
|
state.state_time = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_base = match (
|
||||||
|
physics.on_ground.is_some(),
|
||||||
|
rel_vel.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
|
||||||
|
physics.in_liquid().is_some(), // In water
|
||||||
|
) {
|
||||||
|
// Standing
|
||||||
|
(true, false, false) => anim::crustacean::IdleAnimation::update_skeleton(
|
||||||
|
&CrustaceanSkeleton::default(),
|
||||||
|
time,
|
||||||
|
state.state_time,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
),
|
||||||
|
// Running
|
||||||
|
(true, true, false) => anim::crustacean::RunAnimation::update_skeleton(
|
||||||
|
&CrustaceanSkeleton::default(),
|
||||||
|
(
|
||||||
|
rel_vel,
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
rel_avg_vel,
|
||||||
|
state.acc_vel,
|
||||||
|
),
|
||||||
|
state.state_time,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
),
|
||||||
|
// In air
|
||||||
|
(false, _, false) => anim::crustacean::JumpAnimation::update_skeleton(
|
||||||
|
&CrustaceanSkeleton::default(),
|
||||||
|
(
|
||||||
|
rel_vel.magnitude(),
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
rel_avg_vel,
|
||||||
|
),
|
||||||
|
state.state_time,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
),
|
||||||
|
//Swimming
|
||||||
|
(_, _, true) => anim::crustacean::SwimAnimation::update_skeleton(
|
||||||
|
&CrustaceanSkeleton::default(),
|
||||||
|
(
|
||||||
|
rel_vel,
|
||||||
|
// TODO: Update to use the quaternion.
|
||||||
|
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||||
|
time,
|
||||||
|
rel_avg_vel,
|
||||||
|
state.acc_vel,
|
||||||
|
),
|
||||||
|
state.state_time,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let target_bones = match &character {
|
||||||
|
CharacterState::ComboMelee2(s) => {
|
||||||
|
let timer = s.timer.as_secs_f32();
|
||||||
|
let current_strike = s.completed_strikes % s.static_data.strikes.len();
|
||||||
|
let strike_data = s.static_data.strikes[current_strike];
|
||||||
|
let progress = match s.stage_section {
|
||||||
|
StageSection::Buildup => {
|
||||||
|
timer / strike_data.buildup_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Action => {
|
||||||
|
timer / strike_data.swing_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Recover => {
|
||||||
|
timer / strike_data.recover_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
anim::crustacean::ComboAnimation::update_skeleton(
|
||||||
|
&target_base,
|
||||||
|
(
|
||||||
|
ability_id,
|
||||||
|
Some(s.stage_section),
|
||||||
|
Some(s.static_data.ability_info),
|
||||||
|
current_strike,
|
||||||
|
time,
|
||||||
|
rel_avg_vel,
|
||||||
|
state.state_time,
|
||||||
|
),
|
||||||
|
progress,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
CharacterState::Stunned(s) => {
|
||||||
|
let stage_time = s.timer.as_secs_f32();
|
||||||
|
let stage_progress = match s.stage_section {
|
||||||
|
StageSection::Buildup => {
|
||||||
|
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
StageSection::Recover => {
|
||||||
|
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||||
|
},
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
match s.static_data.poise_state {
|
||||||
|
PoiseState::Normal
|
||||||
|
| PoiseState::Interrupted
|
||||||
|
| PoiseState::Stunned
|
||||||
|
| PoiseState::Dazed
|
||||||
|
| PoiseState::KnockedDown => {
|
||||||
|
anim::crustacean::StunnedAnimation::update_skeleton(
|
||||||
|
&target_base,
|
||||||
|
(
|
||||||
|
rel_vel.magnitude(),
|
||||||
|
time,
|
||||||
|
Some(s.stage_section),
|
||||||
|
state.state_time,
|
||||||
|
),
|
||||||
|
stage_progress,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// TODO!
|
||||||
|
_ => target_base,
|
||||||
|
};
|
||||||
|
|
||||||
|
state.skeleton = Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
|
||||||
|
state.update(
|
||||||
|
renderer,
|
||||||
|
trail_mgr,
|
||||||
|
&mut update_buf,
|
||||||
|
&common_params,
|
||||||
|
state_animation_rate,
|
||||||
|
model,
|
||||||
|
body,
|
||||||
|
);
|
||||||
|
},
|
||||||
Body::BirdLarge(body) => {
|
Body::BirdLarge(body) => {
|
||||||
let (model, skeleton_attr) = self.bird_large_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.bird_large_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
@ -6876,6 +7071,7 @@ impl FigureMgr {
|
|||||||
golem_model_cache,
|
golem_model_cache,
|
||||||
volume_model_cache,
|
volume_model_cache,
|
||||||
arthropod_model_cache,
|
arthropod_model_cache,
|
||||||
|
crustacean_model_cache,
|
||||||
states:
|
states:
|
||||||
FigureMgrStates {
|
FigureMgrStates {
|
||||||
character_states,
|
character_states,
|
||||||
@ -6896,6 +7092,7 @@ impl FigureMgr {
|
|||||||
ship_states,
|
ship_states,
|
||||||
volume_states,
|
volume_states,
|
||||||
arthropod_states,
|
arthropod_states,
|
||||||
|
crustacean_states,
|
||||||
},
|
},
|
||||||
} = self;
|
} = self;
|
||||||
let atlas = atlas_;
|
let atlas = atlas_;
|
||||||
@ -7166,6 +7363,25 @@ impl FigureMgr {
|
|||||||
.map(ModelEntryRef::Figure),
|
.map(ModelEntryRef::Figure),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
Body::Crustacean(body) => crustacean_states
|
||||||
|
.get(&entity)
|
||||||
|
.filter(|state| filter_state(state))
|
||||||
|
.map(move |state| {
|
||||||
|
(
|
||||||
|
state.bound(),
|
||||||
|
crustacean_model_cache
|
||||||
|
.get_model(
|
||||||
|
atlas,
|
||||||
|
body,
|
||||||
|
inventory,
|
||||||
|
tick,
|
||||||
|
viewpoint_camera_mode,
|
||||||
|
character_state,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.map(ModelEntryRef::Figure),
|
||||||
|
)
|
||||||
|
}),
|
||||||
Body::Object(body) => object_states
|
Body::Object(body) => object_states
|
||||||
.get(&entity)
|
.get(&entity)
|
||||||
.filter(|state| filter_state(state))
|
.filter(|state| filter_state(state))
|
||||||
@ -7422,6 +7638,11 @@ impl FigureMgr {
|
|||||||
.item_drop_states
|
.item_drop_states
|
||||||
.get(&entity)
|
.get(&entity)
|
||||||
.and_then(|state| state.viewpoint_offset),
|
.and_then(|state| state.viewpoint_offset),
|
||||||
|
Body::Crustacean(_) => self
|
||||||
|
.states
|
||||||
|
.crustacean_states
|
||||||
|
.get(&entity)
|
||||||
|
.and_then(|state| state.viewpoint_offset),
|
||||||
})
|
})
|
||||||
.map(|viewpoint| viewpoint.into())
|
.map(|viewpoint| viewpoint.into())
|
||||||
.unwrap_or_else(Vec3::zero)
|
.unwrap_or_else(Vec3::zero)
|
||||||
|
Loading…
Reference in New Issue
Block a user