mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Vroom Glider
- GlideBoost ability - Vroom Glider item - Made possible to attach ability_spec to gliders - Activate glider ability while Glide/GlideWield TODO: - make it visible in voxygen
This commit is contained in:
parent
7016ebfff3
commit
3283eb6916
@ -953,6 +953,11 @@
|
|||||||
secondary: Simple(None, "common.abilities.empty.basic"),
|
secondary: Simple(None, "common.abilities.empty.basic"),
|
||||||
abilities: [],
|
abilities: [],
|
||||||
),
|
),
|
||||||
|
Custom("Admin's Eagle"): (
|
||||||
|
primary: Simple(None, "common.abilities.debug.glide_speeder"),
|
||||||
|
secondary: Simple(None, "common.abilities.debug.glide_boost"),
|
||||||
|
abilities: [],
|
||||||
|
),
|
||||||
// Adlets
|
// Adlets
|
||||||
// TODO: Do we want to eventually convert these to simple variants of weapons?
|
// TODO: Do we want to eventually convert these to simple variants of weapons?
|
||||||
Custom("Adlet Hunter"): (
|
Custom("Adlet Hunter"): (
|
||||||
|
3
assets/common/abilities/debug/glide_boost.ron
Normal file
3
assets/common/abilities/debug/glide_boost.ron
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
GlideBoost(
|
||||||
|
booster: Upward(400.0),
|
||||||
|
)
|
3
assets/common/abilities/debug/glide_speeder.ron
Normal file
3
assets/common/abilities/debug/glide_speeder.ron
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
GlideBoost(
|
||||||
|
booster: Forward(0.75),
|
||||||
|
)
|
@ -3,4 +3,4 @@ Boost(
|
|||||||
only_up: true,
|
only_up: true,
|
||||||
speed: 250.0,
|
speed: 250.0,
|
||||||
max_exit_velocity: 70.0,
|
max_exit_velocity: 70.0,
|
||||||
)
|
)
|
||||||
|
@ -1974,6 +1974,9 @@
|
|||||||
Simple(
|
Simple(
|
||||||
"common.items.debug.admin",
|
"common.items.debug.admin",
|
||||||
): "armor-tabard-admin_tabard",
|
): "armor-tabard-admin_tabard",
|
||||||
|
Simple(
|
||||||
|
"common.items.debug.glider",
|
||||||
|
): "other-glider-vroom-debug",
|
||||||
Simple(
|
Simple(
|
||||||
"common.items.debug.admin_back",
|
"common.items.debug.admin_back",
|
||||||
): "armor-misc-back-admin_back",
|
): "armor-misc-back-admin_back",
|
||||||
@ -7099,4 +7102,4 @@
|
|||||||
),
|
),
|
||||||
): "weapon-hammer-hammer-cobalt-1h",
|
): "weapon-hammer-hammer-cobalt-1h",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
8
assets/common/items/debug/glider.ron
Normal file
8
assets/common/items/debug/glider.ron
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
ItemDef(
|
||||||
|
legacy_name: "Vroom Glider",
|
||||||
|
legacy_description: "goes brrr.",
|
||||||
|
kind: Glider,
|
||||||
|
quality: Debug,
|
||||||
|
tags: [],
|
||||||
|
ability_spec: Some(Custom("Admin's Eagle")),
|
||||||
|
)
|
@ -5,6 +5,7 @@
|
|||||||
(Item("common.items.debug.admin_sword"),1),
|
(Item("common.items.debug.admin_sword"),1),
|
||||||
(Item("common.items.debug.velorite_bow_debug"), 1),
|
(Item("common.items.debug.velorite_bow_debug"), 1),
|
||||||
(Item("common.items.debug.admin"),1),
|
(Item("common.items.debug.admin"),1),
|
||||||
|
(Item("common.items.debug.glider"),1),
|
||||||
(Item("common.items.debug.golden_cheese"),100),
|
(Item("common.items.debug.golden_cheese"),100),
|
||||||
],
|
],
|
||||||
"consumables": [
|
"consumables": [
|
||||||
|
@ -1,20 +1,7 @@
|
|||||||
common-abilities-debug-possess = Possessing Arrow
|
## Internal terms, currently only used in zh-Hans.
|
||||||
.desc = Shoots a poisonous arrow. Lets you control your target.
|
## If we remove them here, they also get auto-removed in zh-Hans,
|
||||||
common-abilities-debug-evolve = Evolve
|
## so please keep them, even when not used in English file.
|
||||||
.desc = You become your better self.
|
## See https://github.com/WeblateOrg/weblate/issues/9895
|
||||||
common-abilities-hammer-leap = Smash of Doom
|
|
||||||
.desc = An AOE attack with knockback. Leaps to position of cursor.
|
|
||||||
common-abilities-bow-shotgun = Burst
|
|
||||||
.desc = Launches a burst of arrows.
|
|
||||||
common-abilities-staff-fireshockwave = Ring of Fire
|
|
||||||
.desc = Ignites the ground with fiery shockwave.
|
|
||||||
common-abilities-sceptre-wardingaura = Warding Aura
|
|
||||||
.desc = Wards your allies against enemy attacks.
|
|
||||||
|
|
||||||
# Internal terms, currently only used in zh-Hans.
|
|
||||||
# If we remove them here, they also get auto-removed in zh-Hans,
|
|
||||||
# so please keep them, even when not used in English file.
|
|
||||||
# See https://github.com/WeblateOrg/weblate/issues/9895
|
|
||||||
|
|
||||||
-heavy_stance = ""
|
-heavy_stance = ""
|
||||||
-agile_stance = ""
|
-agile_stance = ""
|
||||||
@ -39,7 +26,27 @@ common-abilities-sceptre-wardingaura = Warding Aura
|
|||||||
-enter_stance = ""
|
-enter_stance = ""
|
||||||
-require_stance = ""
|
-require_stance = ""
|
||||||
|
|
||||||
# Sword abilities
|
## Debug abilities
|
||||||
|
common-abilities-debug-possess = Possessing Arrow
|
||||||
|
.desc = Shoots a poisonous arrow. Lets you control your target.
|
||||||
|
common-abilities-debug-evolve = Evolve
|
||||||
|
.desc = You become your better self.
|
||||||
|
common-abilities-debug-glide_boost = Vroom
|
||||||
|
.desc = Gives you the force to reach the sky
|
||||||
|
common-abilities-debug-glide_speeder = Vroom
|
||||||
|
.desc = Gives you the force to reach wherever your eyes look
|
||||||
|
|
||||||
|
## Hotbar abilities
|
||||||
|
common-abilities-hammer-leap = Smash of Doom
|
||||||
|
.desc = An AOE attack with knockback. Leaps to position of cursor.
|
||||||
|
common-abilities-bow-shotgun = Burst
|
||||||
|
.desc = Launches a burst of arrows
|
||||||
|
common-abilities-staff-fireshockwave = Ring of Fire
|
||||||
|
.desc = Ignites the ground with fiery shockwave.
|
||||||
|
common-abilities-sceptre-wardingaura = Warding Aura
|
||||||
|
.desc = Wards your allies against enemy attacks.
|
||||||
|
|
||||||
|
## Sword abilities
|
||||||
veloren-core-pseudo_abilities-sword-heavy_stance = Heavy Stance
|
veloren-core-pseudo_abilities-sword-heavy_stance = Heavy Stance
|
||||||
.desc = Attacks in this stance can stagger enemies and deal more damage to staggered enemies but are slower.
|
.desc = Attacks in this stance can stagger enemies and deal more damage to staggered enemies but are slower.
|
||||||
veloren-core-pseudo_abilities-sword-agile_stance = Agile Stance
|
veloren-core-pseudo_abilities-sword-agile_stance = Agile Stance
|
||||||
@ -295,7 +302,7 @@ common-abilities-sword-cleaving_sky_splitter = Sky Splitter
|
|||||||
A powerful strike that purportedly can even split the sky, but will split through enemies.
|
A powerful strike that purportedly can even split the sky, but will split through enemies.
|
||||||
Requires cleaving stance.
|
Requires cleaving stance.
|
||||||
|
|
||||||
# Axe abilities
|
## Axe abilities
|
||||||
common-abilities-axe-triple_chop = Triple Chop
|
common-abilities-axe-triple_chop = Triple Chop
|
||||||
.desc =
|
.desc =
|
||||||
Three quick strikes.
|
Three quick strikes.
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
## internal terms, currently only used in ES
|
||||||
|
## If we remove them here, they also get auto-removed in ES,
|
||||||
|
## so please keep them, even when not used in English file.
|
||||||
|
## See https://github.com/WeblateOrg/weblate/issues/9895
|
||||||
|
-hud-skill-sc_wardaura_title = ""
|
||||||
|
-hud-skill-bow_shotgun_title = ""
|
||||||
|
-hud-skill-st_shockwave_title = ""
|
||||||
|
|
||||||
|
## SkillTree UI
|
||||||
hud-rank_up = New skillpoint
|
hud-rank_up = New skillpoint
|
||||||
hud-skill-sp_available =
|
hud-skill-sp_available =
|
||||||
{ $number ->
|
{ $number ->
|
||||||
@ -13,11 +22,6 @@ hud-skill-inc_health = Increases your maximum health by { $boost } points.{ $SP
|
|||||||
hud-skill-inc_energy_title = Increase energy
|
hud-skill-inc_energy_title = Increase energy
|
||||||
hud-skill-inc_energy = Increases your maximum energy by { $boost } points.{ $SP }
|
hud-skill-inc_energy = Increases your maximum energy by { $boost } points.{ $SP }
|
||||||
|
|
||||||
# internally translations, used by ES file currently
|
|
||||||
-hud-skill-sc_wardaura_title = ""
|
|
||||||
-hud-skill-bow_shotgun_title = ""
|
|
||||||
-hud-skill-st_shockwave_title = ""
|
|
||||||
|
|
||||||
hud-skill-unlck_sword_title = Sword proficiency
|
hud-skill-unlck_sword_title = Sword proficiency
|
||||||
hud-skill-unlck_sword = Unlocks the sword skill tree.{ $SP }
|
hud-skill-unlck_sword = Unlocks the sword skill tree.{ $SP }
|
||||||
hud-skill-unlck_axe_title = Axe proficiency
|
hud-skill-unlck_axe_title = Axe proficiency
|
||||||
|
@ -51,3 +51,5 @@ weapon-sword-frost-admin_sword = Admin Greatsword
|
|||||||
|
|
||||||
weapon-bow-velorite-debug = Admin Velorite Bow
|
weapon-bow-velorite-debug = Admin Velorite Bow
|
||||||
.desc = Infused with Velorite power.
|
.desc = Infused with Velorite power.
|
||||||
|
other-glider-vroom-debug = Vroom Glider
|
||||||
|
.desc = goes brrr
|
||||||
|
@ -3816,6 +3816,10 @@
|
|||||||
"voxel.weapon.tool.broom_belzeshrub_purple",
|
"voxel.weapon.tool.broom_belzeshrub_purple",
|
||||||
(0.0, 0.0, 0.0), (-135.0, 90.0, 0.0), 1.1,
|
(0.0, 0.0, 0.0), (-135.0, 90.0, 0.0), 1.1,
|
||||||
),
|
),
|
||||||
|
Simple("common.items.debug.glider"): VoxTrans(
|
||||||
|
"voxel.glider.cloverleaf",
|
||||||
|
(-2.0, 0.0, 0.0), (-50.0, 30.0, 20.0), 0.9,
|
||||||
|
),
|
||||||
// Misc
|
// Misc
|
||||||
Simple("common.items.weapons.tool.golf_club"): VoxTrans(
|
Simple("common.items.weapons.tool.golf_club"): VoxTrans(
|
||||||
"voxel.weapon.tool.golf_club",
|
"voxel.weapon.tool.golf_club",
|
||||||
|
@ -68,5 +68,9 @@
|
|||||||
vox_spec: ("glider.winter_wings", (-26.0, -26.0, 0.0)),
|
vox_spec: ("glider.winter_wings", (-26.0, -26.0, 0.0)),
|
||||||
color: None
|
color: None
|
||||||
),
|
),
|
||||||
|
"common.items.debug.glider": (
|
||||||
|
vox_spec: ("glider.cloverleaf", (-19.0, -5.0, 0.0)),
|
||||||
|
color: None
|
||||||
|
),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -72,6 +72,25 @@ impl Default for ActiveAbilities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make it pub, for UI stuff, if you want
|
||||||
|
enum AbilitySource {
|
||||||
|
Weapons,
|
||||||
|
Glider,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbilitySource {
|
||||||
|
// Get all needed data here and pick the right ability source
|
||||||
|
//
|
||||||
|
// make it pub, for UI stuff, if you want
|
||||||
|
fn determine(char_state: Option<&CharacterState>) -> Self {
|
||||||
|
if char_state.is_some_and(|c| c.is_glide_wielded()) {
|
||||||
|
Self::Glider
|
||||||
|
} else {
|
||||||
|
Self::Weapons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveAbilities {
|
impl ActiveAbilities {
|
||||||
pub fn from_auxiliary(
|
pub fn from_auxiliary(
|
||||||
auxiliary_sets: HashMap<AuxiliaryKey, Vec<AuxiliaryAbility>>,
|
auxiliary_sets: HashMap<AuxiliaryKey, Vec<AuxiliaryAbility>>,
|
||||||
@ -176,7 +195,7 @@ impl ActiveAbilities {
|
|||||||
|
|
||||||
let ability_set = |equip_slot| {
|
let ability_set = |equip_slot| {
|
||||||
inv.and_then(|inv| inv.equipped(equip_slot))
|
inv.and_then(|inv| inv.equipped(equip_slot))
|
||||||
.map(|i| &i.item_config_expect().abilities)
|
.and_then(|i| i.item_config().map(|c| &c.abilities))
|
||||||
};
|
};
|
||||||
|
|
||||||
let scale_ability = |ability: CharacterAbility, equip_slot| {
|
let scale_ability = |ability: CharacterAbility, equip_slot| {
|
||||||
@ -194,100 +213,55 @@ impl ActiveAbilities {
|
|||||||
context_index,
|
context_index,
|
||||||
};
|
};
|
||||||
|
|
||||||
match ability {
|
let inst_ability = |slot: EquipSlot, offhand: bool| {
|
||||||
Ability::ToolGuard => {
|
ability_set(slot).and_then(|abilities| {
|
||||||
let equip_slot = combat::get_equip_slot_by_block_priority(inv);
|
use AbilityInput as I;
|
||||||
ability_set(equip_slot)
|
|
||||||
.and_then(|abilities| {
|
let dispatched = match input {
|
||||||
abilities
|
I::Guard => abilities.guard(Some(skill_set), context),
|
||||||
.guard(Some(skill_set), context)
|
I::Primary => abilities.primary(Some(skill_set), context),
|
||||||
.map(|(a, i)| (a.ability.clone(), i))
|
I::Secondary => abilities.secondary(Some(skill_set), context),
|
||||||
})
|
I::Auxiliary(index) => abilities.auxiliary(index, Some(skill_set), context),
|
||||||
.map(|(ability, i)| {
|
I::Movement => return None,
|
||||||
(
|
};
|
||||||
scale_ability(ability, equip_slot),
|
|
||||||
matches!(equip_slot, EquipSlot::ActiveOffhand),
|
dispatched
|
||||||
spec_ability(i),
|
.map(|(a, i)| (a.ability.clone(), i))
|
||||||
)
|
.map(|(a, i)| (scale_ability(a, slot), offhand, spec_ability(i)))
|
||||||
})
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let source = AbilitySource::determine(char_state);
|
||||||
|
match source {
|
||||||
|
AbilitySource::Glider => match ability {
|
||||||
|
Ability::ToolGuard => None,
|
||||||
|
Ability::ToolPrimary => inst_ability(EquipSlot::Glider, false),
|
||||||
|
Ability::ToolSecondary => inst_ability(EquipSlot::Glider, false),
|
||||||
|
Ability::SpeciesMovement => None,
|
||||||
|
Ability::MainWeaponAux(_) | Ability::OffWeaponAux(_) => None,
|
||||||
|
Ability::Empty => None,
|
||||||
|
},
|
||||||
|
AbilitySource::Weapons => match ability {
|
||||||
|
Ability::ToolGuard => {
|
||||||
|
let equip_slot = combat::get_equip_slot_by_block_priority(inv);
|
||||||
|
inst_ability(equip_slot, matches!(equip_slot, EquipSlot::ActiveOffhand))
|
||||||
|
},
|
||||||
|
Ability::ToolPrimary => inst_ability(EquipSlot::ActiveMainhand, false),
|
||||||
|
Ability::ToolSecondary => inst_ability(EquipSlot::ActiveOffhand, true)
|
||||||
|
.or_else(|| inst_ability(EquipSlot::ActiveMainhand, false)),
|
||||||
|
Ability::SpeciesMovement => matches!(body, Some(Body::Humanoid(_)))
|
||||||
|
.then(|| CharacterAbility::default_roll(char_state))
|
||||||
|
.map(|ability| {
|
||||||
|
(
|
||||||
|
ability.adjusted_by_skills(skill_set, None),
|
||||||
|
false,
|
||||||
|
spec_ability(None),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
Ability::MainWeaponAux(_) => inst_ability(EquipSlot::ActiveMainhand, false),
|
||||||
|
Ability::OffWeaponAux(_) => inst_ability(EquipSlot::ActiveOffhand, true),
|
||||||
|
Ability::Empty => None,
|
||||||
},
|
},
|
||||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
|
||||||
.and_then(|abilities| {
|
|
||||||
abilities
|
|
||||||
.primary(Some(skill_set), context)
|
|
||||||
.map(|(a, i)| (a.ability.clone(), i))
|
|
||||||
})
|
|
||||||
.map(|(ability, i)| {
|
|
||||||
(
|
|
||||||
scale_ability(ability, EquipSlot::ActiveMainhand),
|
|
||||||
false,
|
|
||||||
spec_ability(i),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand)
|
|
||||||
.and_then(|abilities| {
|
|
||||||
abilities
|
|
||||||
.secondary(Some(skill_set), context)
|
|
||||||
.map(|(a, i)| (a.ability.clone(), i))
|
|
||||||
})
|
|
||||||
.map(|(ability, i)| {
|
|
||||||
(
|
|
||||||
scale_ability(ability, EquipSlot::ActiveOffhand),
|
|
||||||
true,
|
|
||||||
spec_ability(i),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
ability_set(EquipSlot::ActiveMainhand)
|
|
||||||
.and_then(|abilities| {
|
|
||||||
abilities
|
|
||||||
.secondary(Some(skill_set), context)
|
|
||||||
.map(|(a, i)| (a.ability.clone(), i))
|
|
||||||
})
|
|
||||||
.map(|(ability, i)| {
|
|
||||||
(
|
|
||||||
scale_ability(ability, EquipSlot::ActiveMainhand),
|
|
||||||
false,
|
|
||||||
spec_ability(i),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
Ability::SpeciesMovement => matches!(body, Some(Body::Humanoid(_)))
|
|
||||||
.then(|| CharacterAbility::default_roll(char_state))
|
|
||||||
.map(|ability| {
|
|
||||||
(
|
|
||||||
ability.adjusted_by_skills(skill_set, None),
|
|
||||||
false,
|
|
||||||
spec_ability(None),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand)
|
|
||||||
.and_then(|abilities| {
|
|
||||||
abilities
|
|
||||||
.auxiliary(index, Some(skill_set), context)
|
|
||||||
.map(|(a, i)| (a.ability.clone(), i))
|
|
||||||
})
|
|
||||||
.map(|(ability, i)| {
|
|
||||||
(
|
|
||||||
scale_ability(ability, EquipSlot::ActiveMainhand),
|
|
||||||
false,
|
|
||||||
spec_ability(i),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
Ability::OffWeaponAux(index) => ability_set(EquipSlot::ActiveOffhand)
|
|
||||||
.and_then(|abilities| {
|
|
||||||
abilities
|
|
||||||
.auxiliary(index, Some(skill_set), context)
|
|
||||||
.map(|(a, i)| (a.ability.clone(), i))
|
|
||||||
})
|
|
||||||
.map(|(ability, i)| {
|
|
||||||
(
|
|
||||||
scale_ability(ability, EquipSlot::ActiveOffhand),
|
|
||||||
true,
|
|
||||||
spec_ability(i),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
Ability::Empty => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,9 +270,9 @@ impl ActiveAbilities {
|
|||||||
skill_set: Option<&'a SkillSet>,
|
skill_set: Option<&'a SkillSet>,
|
||||||
equip_slot: EquipSlot,
|
equip_slot: EquipSlot,
|
||||||
) -> impl Iterator<Item = usize> + 'a {
|
) -> impl Iterator<Item = usize> + 'a {
|
||||||
inv.and_then(|inv| inv.equipped(equip_slot))
|
inv.and_then(|inv| inv.equipped(equip_slot).and_then(|i| i.item_config()))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|i| &i.item_config_expect().abilities.abilities)
|
.flat_map(|config| &config.abilities.abilities)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(move |(i, a)| match a {
|
.filter_map(move |(i, a)| match a {
|
||||||
AbilityKind::Simple(skill, _) => skill
|
AbilityKind::Simple(skill, _) => skill
|
||||||
@ -338,6 +312,7 @@ impl ActiveAbilities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub enum AbilityInput {
|
pub enum AbilityInput {
|
||||||
Guard,
|
Guard,
|
||||||
Primary,
|
Primary,
|
||||||
@ -360,15 +335,29 @@ pub enum Ability {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ability {
|
impl Ability {
|
||||||
|
fn try_input(&self) -> Option<AbilityInput> {
|
||||||
|
let input = match self {
|
||||||
|
Self::ToolGuard => AbilityInput::Guard,
|
||||||
|
Self::ToolPrimary => AbilityInput::Primary,
|
||||||
|
Self::ToolSecondary => AbilityInput::Secondary,
|
||||||
|
Self::SpeciesMovement => AbilityInput::Movement,
|
||||||
|
Self::OffWeaponAux(idx) | Self::MainWeaponAux(idx) => AbilityInput::Auxiliary(*idx),
|
||||||
|
Self::Empty => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(input)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ability_id<'a>(
|
pub fn ability_id<'a>(
|
||||||
self,
|
self,
|
||||||
|
char_state: Option<&CharacterState>,
|
||||||
inv: Option<&'a Inventory>,
|
inv: Option<&'a Inventory>,
|
||||||
skillset: Option<&'a SkillSet>,
|
skill_set: Option<&'a SkillSet>,
|
||||||
context: &AbilityContext,
|
context: &AbilityContext,
|
||||||
) -> Option<&'a str> {
|
) -> Option<&'a str> {
|
||||||
let ability_set = |equip_slot| {
|
let ability_set = |equip_slot| {
|
||||||
inv.and_then(|inv| inv.equipped(equip_slot))
|
inv.and_then(|inv| inv.equipped(equip_slot))
|
||||||
.map(|i| &i.item_config_expect().abilities)
|
.and_then(|i| i.item_config().map(|c| &c.abilities))
|
||||||
};
|
};
|
||||||
|
|
||||||
let contextual_id = |kind: Option<&'a AbilityKind<_>>| -> Option<&'a str> {
|
let contextual_id = |kind: Option<&'a AbilityKind<_>>| -> Option<&'a str> {
|
||||||
@ -383,62 +372,60 @@ impl Ability {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
let inst_ability = |slot: EquipSlot| {
|
||||||
Ability::ToolGuard => ability_set(combat::get_equip_slot_by_block_priority(inv))
|
ability_set(slot).and_then(|abilities| {
|
||||||
.and_then(|abilities| {
|
use AbilityInput as I;
|
||||||
abilities
|
|
||||||
.guard(skillset, context)
|
let dispatched = match self.try_input()? {
|
||||||
.map(|a| a.0.id.as_str())
|
I::Guard => abilities.guard(skill_set, context),
|
||||||
.or_else(|| {
|
I::Primary => abilities.primary(skill_set, context),
|
||||||
abilities
|
I::Secondary => abilities.secondary(skill_set, context),
|
||||||
.guard
|
I::Auxiliary(index) => abilities.auxiliary(index, skill_set, context),
|
||||||
.as_ref()
|
I::Movement => return None,
|
||||||
.and_then(|g| contextual_id(Some(g)))
|
};
|
||||||
})
|
|
||||||
}),
|
dispatched
|
||||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
|
.map(|(a, _)| a.id.as_str())
|
||||||
abilities
|
.or_else(|| match self.try_input()? {
|
||||||
.primary(skillset, context)
|
I::Guard => abilities
|
||||||
.map(|a| a.0.id.as_str())
|
.guard
|
||||||
.or_else(|| contextual_id(Some(&abilities.primary)))
|
.as_ref()
|
||||||
}),
|
.and_then(|g| contextual_id(Some(g))),
|
||||||
Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand)
|
I::Primary => contextual_id(Some(&abilities.primary)),
|
||||||
.and_then(|abilities| {
|
I::Secondary => contextual_id(Some(&abilities.secondary)),
|
||||||
abilities
|
I::Auxiliary(index) => contextual_id(abilities.abilities.get(index)),
|
||||||
.secondary(skillset, context)
|
I::Movement => None,
|
||||||
.map(|a| a.0.id.as_str())
|
|
||||||
.or_else(|| contextual_id(Some(&abilities.secondary)))
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
|
|
||||||
abilities
|
|
||||||
.secondary(skillset, context)
|
|
||||||
.map(|a| a.0.id.as_str())
|
|
||||||
.or_else(|| contextual_id(Some(&abilities.secondary)))
|
|
||||||
})
|
})
|
||||||
}),
|
})
|
||||||
Ability::SpeciesMovement => None, // TODO: Make not None
|
};
|
||||||
Ability::MainWeaponAux(index) => {
|
|
||||||
ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
|
let source = AbilitySource::determine(char_state);
|
||||||
abilities
|
match source {
|
||||||
.auxiliary(index, skillset, context)
|
AbilitySource::Glider => match self {
|
||||||
.map(|a| a.0.id.as_str())
|
Ability::ToolGuard => None,
|
||||||
.or_else(|| contextual_id(abilities.abilities.get(index)))
|
Ability::ToolPrimary => inst_ability(EquipSlot::Glider),
|
||||||
})
|
Ability::ToolSecondary => inst_ability(EquipSlot::Glider),
|
||||||
|
Ability::SpeciesMovement => None, // TODO: Make not None
|
||||||
|
Ability::MainWeaponAux(_) | Ability::OffWeaponAux(_) => None,
|
||||||
|
Ability::Empty => None,
|
||||||
},
|
},
|
||||||
Ability::OffWeaponAux(index) => {
|
AbilitySource::Weapons => match self {
|
||||||
ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| {
|
Ability::ToolGuard => {
|
||||||
abilities
|
let equip_slot = combat::get_equip_slot_by_block_priority(inv);
|
||||||
.auxiliary(index, skillset, context)
|
inst_ability(equip_slot)
|
||||||
.map(|a| a.0.id.as_str())
|
},
|
||||||
.or_else(|| contextual_id(abilities.abilities.get(index)))
|
Ability::ToolPrimary => inst_ability(EquipSlot::ActiveMainhand),
|
||||||
})
|
Ability::ToolSecondary => inst_ability(EquipSlot::ActiveMainhand)
|
||||||
|
.or_else(|| inst_ability(EquipSlot::ActiveOffhand)),
|
||||||
|
Ability::SpeciesMovement => None, // TODO: Make not None
|
||||||
|
Ability::MainWeaponAux(_) => inst_ability(EquipSlot::ActiveMainhand),
|
||||||
|
Ability::OffWeaponAux(_) => inst_ability(EquipSlot::ActiveOffhand),
|
||||||
|
Ability::Empty => None,
|
||||||
},
|
},
|
||||||
Ability::Empty => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_from_tool(&self) -> bool {
|
pub fn is_from_wielded(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Ability::ToolPrimary
|
Ability::ToolPrimary
|
||||||
| Ability::ToolSecondary
|
| Ability::ToolSecondary
|
||||||
@ -449,6 +436,7 @@ impl Ability {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
||||||
pub enum GuardAbility {
|
pub enum GuardAbility {
|
||||||
Tool,
|
Tool,
|
||||||
@ -471,10 +459,14 @@ pub struct SpecifiedAbility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SpecifiedAbility {
|
impl SpecifiedAbility {
|
||||||
pub fn ability_id(self, inv: Option<&Inventory>) -> Option<&str> {
|
pub fn ability_id<'a>(
|
||||||
|
self,
|
||||||
|
char_state: Option<&CharacterState>,
|
||||||
|
inv: Option<&'a Inventory>,
|
||||||
|
) -> Option<&'a str> {
|
||||||
let ability_set = |equip_slot| {
|
let ability_set = |equip_slot| {
|
||||||
inv.and_then(|inv| inv.equipped(equip_slot))
|
inv.and_then(|inv| inv.equipped(equip_slot))
|
||||||
.map(|i| &i.item_config_expect().abilities)
|
.and_then(|i| i.item_config().map(|c| &c.abilities))
|
||||||
};
|
};
|
||||||
|
|
||||||
fn ability_id(spec_ability: SpecifiedAbility, ability: &AbilityKind<AbilityItem>) -> &str {
|
fn ability_id(spec_ability: SpecifiedAbility, ability: &AbilityKind<AbilityItem>) -> &str {
|
||||||
@ -490,23 +482,41 @@ impl SpecifiedAbility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.ability {
|
let inst_ability = |slot: EquipSlot| {
|
||||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
ability_set(slot).and_then(|abilities| {
|
||||||
.map(|abilities| ability_id(self, &abilities.primary)),
|
use AbilityInput as I;
|
||||||
Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand)
|
|
||||||
.map(|abilities| ability_id(self, &abilities.secondary))
|
let dispatched = match self.ability.try_input()? {
|
||||||
.or_else(|| {
|
I::Guard => abilities.guard.as_ref(),
|
||||||
ability_set(EquipSlot::ActiveMainhand)
|
I::Primary => Some(&abilities.primary),
|
||||||
.map(|abilities| ability_id(self, &abilities.secondary))
|
I::Secondary => Some(&abilities.secondary),
|
||||||
}),
|
I::Auxiliary(index) => abilities.abilities.get(index),
|
||||||
Ability::ToolGuard => ability_set(combat::get_equip_slot_by_block_priority(inv))
|
I::Movement => return None,
|
||||||
.and_then(|abilities| abilities.guard.as_ref().map(|a| ability_id(self, a))),
|
};
|
||||||
Ability::SpeciesMovement => None, // TODO: Make not None
|
dispatched.map(|a| ability_id(self, a))
|
||||||
Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand)
|
})
|
||||||
.and_then(|abilities| abilities.abilities.get(index).map(|a| ability_id(self, a))),
|
};
|
||||||
Ability::OffWeaponAux(index) => ability_set(EquipSlot::ActiveOffhand)
|
|
||||||
.and_then(|abilities| abilities.abilities.get(index).map(|a| ability_id(self, a))),
|
let source = AbilitySource::determine(char_state);
|
||||||
Ability::Empty => None,
|
match source {
|
||||||
|
AbilitySource::Glider => match self.ability {
|
||||||
|
Ability::ToolGuard => None,
|
||||||
|
Ability::ToolPrimary => inst_ability(EquipSlot::Glider),
|
||||||
|
Ability::ToolSecondary => inst_ability(EquipSlot::Glider),
|
||||||
|
Ability::SpeciesMovement => None,
|
||||||
|
Ability::MainWeaponAux(_) | Ability::OffWeaponAux(_) => None,
|
||||||
|
Ability::Empty => None,
|
||||||
|
},
|
||||||
|
AbilitySource::Weapons => match self.ability {
|
||||||
|
Ability::ToolGuard => inst_ability(combat::get_equip_slot_by_block_priority(inv)),
|
||||||
|
Ability::ToolPrimary => inst_ability(EquipSlot::ActiveMainhand),
|
||||||
|
Ability::ToolSecondary => inst_ability(EquipSlot::ActiveOffhand)
|
||||||
|
.or_else(|| inst_ability(EquipSlot::ActiveMainhand)),
|
||||||
|
Ability::SpeciesMovement => None, // TODO: Make not None
|
||||||
|
Ability::MainWeaponAux(_) => inst_ability(EquipSlot::ActiveMainhand),
|
||||||
|
Ability::OffWeaponAux(_) => inst_ability(EquipSlot::ActiveOffhand),
|
||||||
|
Ability::Empty => None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -514,13 +524,14 @@ impl SpecifiedAbility {
|
|||||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
||||||
pub enum PrimaryAbility {
|
pub enum PrimaryAbility {
|
||||||
Tool,
|
Tool,
|
||||||
|
Glider,
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PrimaryAbility> for Ability {
|
impl From<PrimaryAbility> for Ability {
|
||||||
fn from(primary: PrimaryAbility) -> Self {
|
fn from(primary: PrimaryAbility) -> Self {
|
||||||
match primary {
|
match primary {
|
||||||
PrimaryAbility::Tool => Ability::ToolPrimary,
|
PrimaryAbility::Tool | PrimaryAbility::Glider => Ability::ToolPrimary,
|
||||||
PrimaryAbility::Empty => Ability::Empty,
|
PrimaryAbility::Empty => Ability::Empty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,13 +540,14 @@ impl From<PrimaryAbility> for Ability {
|
|||||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
||||||
pub enum SecondaryAbility {
|
pub enum SecondaryAbility {
|
||||||
Tool,
|
Tool,
|
||||||
|
Glider,
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SecondaryAbility> for Ability {
|
impl From<SecondaryAbility> for Ability {
|
||||||
fn from(primary: SecondaryAbility) -> Self {
|
fn from(primary: SecondaryAbility) -> Self {
|
||||||
match primary {
|
match primary {
|
||||||
SecondaryAbility::Tool => Ability::ToolSecondary,
|
SecondaryAbility::Tool | SecondaryAbility::Glider => Ability::ToolSecondary,
|
||||||
SecondaryAbility::Empty => Ability::Empty,
|
SecondaryAbility::Empty => Ability::Empty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -708,6 +720,11 @@ pub enum CharacterAbility {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
meta: AbilityMeta,
|
meta: AbilityMeta,
|
||||||
},
|
},
|
||||||
|
GlideBoost {
|
||||||
|
booster: glide::Boost,
|
||||||
|
#[serde(default)]
|
||||||
|
meta: AbilityMeta,
|
||||||
|
},
|
||||||
DashMelee {
|
DashMelee {
|
||||||
energy_cost: f32,
|
energy_cost: f32,
|
||||||
energy_drain: f32,
|
energy_drain: f32,
|
||||||
@ -1125,6 +1142,7 @@ impl CharacterAbility {
|
|||||||
},
|
},
|
||||||
CharacterAbility::ComboMeleeDeprecated { .. }
|
CharacterAbility::ComboMeleeDeprecated { .. }
|
||||||
| CharacterAbility::Boost { .. }
|
| CharacterAbility::Boost { .. }
|
||||||
|
| CharacterAbility::GlideBoost { .. }
|
||||||
| CharacterAbility::BasicBeam { .. }
|
| CharacterAbility::BasicBeam { .. }
|
||||||
| CharacterAbility::Blink { .. }
|
| CharacterAbility::Blink { .. }
|
||||||
| CharacterAbility::Music { .. }
|
| CharacterAbility::Music { .. }
|
||||||
@ -1688,6 +1706,7 @@ impl CharacterAbility {
|
|||||||
*buildup_duration /= stats.speed;
|
*buildup_duration /= stats.speed;
|
||||||
*recover_duration /= stats.speed;
|
*recover_duration /= stats.speed;
|
||||||
},
|
},
|
||||||
|
GlideBoost { .. } => {},
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -1724,6 +1743,7 @@ impl CharacterAbility {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Boost { .. }
|
Boost { .. }
|
||||||
|
| GlideBoost { .. }
|
||||||
| ComboMeleeDeprecated { .. }
|
| ComboMeleeDeprecated { .. }
|
||||||
| Blink { .. }
|
| Blink { .. }
|
||||||
| Music { .. }
|
| Music { .. }
|
||||||
@ -1773,6 +1793,7 @@ impl CharacterAbility {
|
|||||||
| RiposteMelee { .. }
|
| RiposteMelee { .. }
|
||||||
| BasicBeam { .. }
|
| BasicBeam { .. }
|
||||||
| Boost { .. }
|
| Boost { .. }
|
||||||
|
| GlideBoost { .. }
|
||||||
| ComboMeleeDeprecated { .. }
|
| ComboMeleeDeprecated { .. }
|
||||||
| Blink { .. }
|
| Blink { .. }
|
||||||
| Music { .. }
|
| Music { .. }
|
||||||
@ -1801,6 +1822,7 @@ impl CharacterAbility {
|
|||||||
| SelfBuff { meta, .. }
|
| SelfBuff { meta, .. }
|
||||||
| BasicBeam { meta, .. }
|
| BasicBeam { meta, .. }
|
||||||
| Boost { meta, .. }
|
| Boost { meta, .. }
|
||||||
|
| GlideBoost { meta, .. }
|
||||||
| ComboMeleeDeprecated { meta, .. }
|
| ComboMeleeDeprecated { meta, .. }
|
||||||
| ComboMelee2 { meta, .. }
|
| ComboMelee2 { meta, .. }
|
||||||
| Blink { meta, .. }
|
| Blink { meta, .. }
|
||||||
@ -2312,6 +2334,13 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
|||||||
},
|
},
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
}),
|
}),
|
||||||
|
CharacterAbility::GlideBoost { booster, meta: _ } => {
|
||||||
|
let scale = data.body.dimensions().z.sqrt();
|
||||||
|
let mut glide_data = glide::Data::new(scale * 4.5, scale, *data.ori);
|
||||||
|
glide_data.booster = Some(*booster);
|
||||||
|
|
||||||
|
CharacterState::Glide(glide_data)
|
||||||
|
},
|
||||||
CharacterAbility::DashMelee {
|
CharacterAbility::DashMelee {
|
||||||
energy_cost: _,
|
energy_cost: _,
|
||||||
energy_drain,
|
energy_drain,
|
||||||
|
@ -228,6 +228,13 @@ impl CharacterState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_glide_wielded(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
CharacterState::Glide { .. } | CharacterState::GlideWield { .. }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_stealthy(&self) -> bool {
|
pub fn is_stealthy(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
|
@ -729,38 +729,47 @@ impl TryFrom<(&Item, &AbilityMap, &MaterialStatManifest)> for ItemConfig {
|
|||||||
// TODO: Either remove msm or use it as argument in fn kind
|
// TODO: Either remove msm or use it as argument in fn kind
|
||||||
(item, ability_map, _msm): (&Item, &AbilityMap, &MaterialStatManifest),
|
(item, ability_map, _msm): (&Item, &AbilityMap, &MaterialStatManifest),
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
if let ItemKind::Tool(tool) = &*item.kind() {
|
match &*item.kind() {
|
||||||
// If no custom ability set is specified, fall back to abilityset of tool kind.
|
ItemKind::Tool(tool) => {
|
||||||
let tool_default = |tool_kind| {
|
// If no custom ability set is specified, fall back to abilityset of tool kind.
|
||||||
let key = &AbilitySpec::Tool(tool_kind);
|
let tool_default = |tool_kind| {
|
||||||
ability_map.get_ability_set(key)
|
let key = &AbilitySpec::Tool(tool_kind);
|
||||||
};
|
ability_map.get_ability_set(key)
|
||||||
let abilities = if let Some(set_key) = item.ability_spec() {
|
};
|
||||||
if let Some(set) = ability_map.get_ability_set(&set_key) {
|
let abilities = if let Some(set_key) = item.ability_spec() {
|
||||||
|
if let Some(set) = ability_map.get_ability_set(&set_key) {
|
||||||
|
set.clone()
|
||||||
|
.modified_by_tool(tool, item.stats_durability_multiplier())
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Custom ability set: {:?} references non-existent set, falling back \
|
||||||
|
to default ability set.",
|
||||||
|
set_key
|
||||||
|
);
|
||||||
|
tool_default(tool.kind).cloned().unwrap_or_default()
|
||||||
|
}
|
||||||
|
} else if let Some(set) = tool_default(tool.kind) {
|
||||||
set.clone()
|
set.clone()
|
||||||
.modified_by_tool(tool, item.stats_durability_multiplier())
|
.modified_by_tool(tool, item.stats_durability_multiplier())
|
||||||
} else {
|
} else {
|
||||||
error!(
|
error!(
|
||||||
"Custom ability set: {:?} references non-existent set, falling back to \
|
"No ability set defined for tool: {:?}, falling back to default ability \
|
||||||
default ability set.",
|
set.",
|
||||||
set_key
|
tool.kind
|
||||||
);
|
);
|
||||||
tool_default(tool.kind).cloned().unwrap_or_default()
|
Default::default()
|
||||||
}
|
};
|
||||||
} else if let Some(set) = tool_default(tool.kind) {
|
|
||||||
set.clone()
|
|
||||||
.modified_by_tool(tool, item.stats_durability_multiplier())
|
|
||||||
} else {
|
|
||||||
error!(
|
|
||||||
"No ability set defined for tool: {:?}, falling back to default ability set.",
|
|
||||||
tool.kind
|
|
||||||
);
|
|
||||||
Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(ItemConfig { abilities })
|
Ok(ItemConfig { abilities })
|
||||||
} else {
|
},
|
||||||
Err(ItemConfigError::BadItemKind)
|
ItemKind::Glider => item
|
||||||
|
.ability_spec()
|
||||||
|
.and_then(|set_key| ability_map.get_ability_set(&set_key))
|
||||||
|
.map(|abilities| ItemConfig {
|
||||||
|
abilities: abilities.clone(),
|
||||||
|
})
|
||||||
|
.ok_or(ItemConfigError::BadItemKind),
|
||||||
|
_ => Err(ItemConfigError::BadItemKind),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1324,11 +1333,7 @@ impl Item {
|
|||||||
|
|
||||||
pub fn slots_mut(&mut self) -> &mut [InvSlot] { &mut self.slots }
|
pub fn slots_mut(&mut self) -> &mut [InvSlot] { &mut self.slots }
|
||||||
|
|
||||||
pub fn item_config_expect(&self) -> &ItemConfig {
|
pub fn item_config(&self) -> Option<&ItemConfig> { self.item_config.as_deref() }
|
||||||
self.item_config
|
|
||||||
.as_ref()
|
|
||||||
.expect("Item was expected to have an ItemConfig")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn free_slots(&self) -> usize { self.slots.iter().filter(|x| x.is_none()).count() }
|
pub fn free_slots(&self) -> usize { self.slots.iter().filter(|x| x.is_none()).count() }
|
||||||
|
|
||||||
|
@ -37,14 +37,13 @@ pub enum ToolKind {
|
|||||||
Farming,
|
Farming,
|
||||||
Pick,
|
Pick,
|
||||||
Shovel,
|
Shovel,
|
||||||
|
/// Music Instruments
|
||||||
|
Instrument,
|
||||||
// npcs
|
// npcs
|
||||||
/// Intended for invisible weapons (e.g. a creature using its claws or
|
/// Intended for invisible weapons (e.g. a creature using its claws or
|
||||||
/// biting)
|
/// biting)
|
||||||
Natural,
|
Natural,
|
||||||
/// This is an placeholder item, it is used by non-humanoid npcs to attack
|
/// This is an placeholder item, it is used by non-humanoid npcs to attack
|
||||||
/// Music Instruments
|
|
||||||
Instrument,
|
|
||||||
/// This is an placeholder item, it is used by non-humanoid npcs to attack
|
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,14 @@ use vek::*;
|
|||||||
|
|
||||||
const PITCH_SLOW_TIME: f32 = 0.5;
|
const PITCH_SLOW_TIME: f32 = 0.5;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum Boost {
|
||||||
|
/// Slowly increases XY speed
|
||||||
|
Forward(f32),
|
||||||
|
/// Gives Z impulse
|
||||||
|
Upward(f32),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
/// The aspect ratio is the ratio of the span squared to actual planform
|
/// The aspect ratio is the ratio of the span squared to actual planform
|
||||||
@ -28,6 +36,7 @@ pub struct Data {
|
|||||||
last_vel: Vel,
|
last_vel: Vel,
|
||||||
pub timer: Duration,
|
pub timer: Duration,
|
||||||
inputs_disabled: bool,
|
inputs_disabled: bool,
|
||||||
|
pub booster: Option<Boost>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Data {
|
impl Data {
|
||||||
@ -47,6 +56,7 @@ impl Data {
|
|||||||
last_vel: Vel::zero(),
|
last_vel: Vel::zero(),
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
inputs_disabled: true,
|
inputs_disabled: true,
|
||||||
|
booster: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,12 +85,32 @@ impl Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CharacterBehavior for Data {
|
impl CharacterBehavior for Data {
|
||||||
fn behavior(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
|
||||||
let mut update = StateUpdate::from(data);
|
let mut update = StateUpdate::from(data);
|
||||||
|
|
||||||
// If player is on ground, end glide
|
handle_glider_input_or(data, &mut update, output_events, |_, _| {});
|
||||||
|
|
||||||
|
// If switched state, let it do its thing
|
||||||
|
if !matches!(update.character, CharacterState::Glide { .. }) {
|
||||||
|
return update;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alternatively, we could end up in the same state, but gained booster
|
||||||
|
let gained_booster = if let CharacterState::Glide(Data {
|
||||||
|
booster: Some(booster),
|
||||||
|
..
|
||||||
|
}) = update.character
|
||||||
|
{
|
||||||
|
Some(booster)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// If player is on the ground and effectively doesn't have any gliding
|
||||||
|
// power left, end the glide
|
||||||
if data.physics.on_ground.is_some()
|
if data.physics.on_ground.is_some()
|
||||||
&& (data.vel.0 - data.physics.ground_vel).magnitude_squared() < 2_f32.powi(2)
|
&& (data.vel.0 - data.physics.ground_vel).magnitude_squared() < 2_f32.powi(2)
|
||||||
|
&& gained_booster.is_none()
|
||||||
{
|
{
|
||||||
update.character = CharacterState::GlideWield(glide_wield::Data::from(data));
|
update.character = CharacterState::GlideWield(glide_wield::Data::from(data));
|
||||||
} else if data.physics.in_liquid().is_some()
|
} else if data.physics.in_liquid().is_some()
|
||||||
@ -189,11 +219,34 @@ impl CharacterBehavior for Data {
|
|||||||
slerp_s,
|
slerp_s,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If we gained a booster
|
||||||
|
if let Some(booster) = gained_booster {
|
||||||
|
match booster {
|
||||||
|
Boost::Upward(speed) => {
|
||||||
|
update.vel.0.z += speed * data.dt.0;
|
||||||
|
},
|
||||||
|
Boost::Forward(speed) => {
|
||||||
|
if data.physics.on_ground.is_some() {
|
||||||
|
// quality of life hack: help with starting
|
||||||
|
//
|
||||||
|
// other velocities are intentionally ignored
|
||||||
|
update.vel.0.z += 500.0 * data.dt.0;
|
||||||
|
} else {
|
||||||
|
update.vel.0.x *= 1.0 + speed * data.dt.0;
|
||||||
|
update.vel.0.y *= 1.0 + speed * data.dt.0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
update.character = CharacterState::Glide(Self {
|
update.character = CharacterState::Glide(Self {
|
||||||
ori,
|
ori,
|
||||||
last_vel: *data.vel,
|
last_vel: *data.vel,
|
||||||
timer: tick_attack_or_default(data, self.timer, None),
|
timer: tick_attack_or_default(data, self.timer, None),
|
||||||
inputs_disabled,
|
inputs_disabled,
|
||||||
|
// booster is consumed, set to None
|
||||||
|
booster: None,
|
||||||
..*self
|
..*self
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ impl CharacterBehavior for Data {
|
|||||||
if input_is_pressed(data, InputKind::Roll) {
|
if input_is_pressed(data, InputKind::Roll) {
|
||||||
handle_input(data, output_events, &mut update, InputKind::Roll);
|
handle_input(data, output_events, &mut update, InputKind::Roll);
|
||||||
}
|
}
|
||||||
handle_wield(data, &mut update);
|
handle_glider_input_or(data, &mut update, output_events, handle_wield);
|
||||||
|
|
||||||
// If still in this state, do the things
|
// If still in this state, do the things
|
||||||
if matches!(update.character, CharacterState::GlideWield(_)) {
|
if matches!(update.character, CharacterState::GlideWield(_)) {
|
||||||
|
@ -95,7 +95,7 @@ impl CharacterBehavior for Data {
|
|||||||
.static_data
|
.static_data
|
||||||
.ability_info
|
.ability_info
|
||||||
.ability
|
.ability
|
||||||
.map_or(false, |a| a.ability.is_from_tool())
|
.map_or(false, |a| a.ability.is_from_wielded())
|
||||||
{
|
{
|
||||||
vec![BuffCategory::RemoveOnLoadoutChange]
|
vec![BuffCategory::RemoveOnLoadoutChange]
|
||||||
} else {
|
} else {
|
||||||
|
@ -1330,6 +1330,30 @@ pub fn handle_input(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Quality of Life hack
|
||||||
|
//
|
||||||
|
// Uses glider ability if has any, otherwise fallback
|
||||||
|
pub fn handle_glider_input_or(
|
||||||
|
data: &JoinData<'_>,
|
||||||
|
update: &mut StateUpdate,
|
||||||
|
output_events: &mut OutputEvents,
|
||||||
|
fallback_fn: fn(&JoinData<'_>, &mut StateUpdate),
|
||||||
|
) {
|
||||||
|
if data
|
||||||
|
.inventory
|
||||||
|
.and_then(|inv| inv.equipped(EquipSlot::Glider))
|
||||||
|
.and_then(|glider| glider.item_config())
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
fallback_fn(data, update);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(input) = data.controller.queued_inputs.keys().next() {
|
||||||
|
handle_ability(data, update, output_events, *input);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn attempt_input(
|
pub fn attempt_input(
|
||||||
data: &JoinData<'_>,
|
data: &JoinData<'_>,
|
||||||
output_events: &mut OutputEvents,
|
output_events: &mut OutputEvents,
|
||||||
|
@ -162,8 +162,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
CharacterState::Idle(_)
|
CharacterState::Idle(_)
|
||||||
| CharacterState::Talk
|
| CharacterState::Talk
|
||||||
| CharacterState::Dance
|
| CharacterState::Dance
|
||||||
| CharacterState::Glide(_)
|
|
||||||
| CharacterState::Skate(_)
|
| CharacterState::Skate(_)
|
||||||
|
| CharacterState::Glide(_)
|
||||||
| CharacterState::GlideWield(_)
|
| CharacterState::GlideWield(_)
|
||||||
| CharacterState::Wielding(_)
|
| CharacterState::Wielding(_)
|
||||||
| CharacterState::Equipping(_)
|
| CharacterState::Equipping(_)
|
||||||
|
@ -852,7 +852,12 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
Some(self.inventory),
|
Some(self.inventory),
|
||||||
Some(self.skill_set),
|
Some(self.skill_set),
|
||||||
)
|
)
|
||||||
.ability_id(Some(self.inventory), Some(self.skill_set), self.context);
|
.ability_id(
|
||||||
|
None,
|
||||||
|
Some(self.inventory),
|
||||||
|
Some(self.skill_set),
|
||||||
|
self.context,
|
||||||
|
);
|
||||||
let (ability_title, ability_desc) = if let Some(ability_id) = ability_id {
|
let (ability_title, ability_desc) = if let Some(ability_id) = ability_id {
|
||||||
util::ability_description(ability_id, self.localized_strings)
|
util::ability_description(ability_id, self.localized_strings)
|
||||||
} else {
|
} else {
|
||||||
@ -935,6 +940,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
.map(|a| {
|
.map(|a| {
|
||||||
(
|
(
|
||||||
Ability::from(a).ability_id(
|
Ability::from(a).ability_id(
|
||||||
|
None,
|
||||||
Some(self.inventory),
|
Some(self.inventory),
|
||||||
Some(self.skill_set),
|
Some(self.skill_set),
|
||||||
self.context,
|
self.context,
|
||||||
@ -951,6 +957,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
.map(|a| {
|
.map(|a| {
|
||||||
(
|
(
|
||||||
Ability::from(a).ability_id(
|
Ability::from(a).ability_id(
|
||||||
|
None,
|
||||||
Some(self.inventory),
|
Some(self.inventory),
|
||||||
Some(self.skill_set),
|
Some(self.skill_set),
|
||||||
self.context,
|
self.context,
|
||||||
|
@ -1043,6 +1043,7 @@ impl<'a> Skillbar<'a> {
|
|||||||
.get(i)
|
.get(i)
|
||||||
.and_then(|a| {
|
.and_then(|a| {
|
||||||
Ability::from(*a).ability_id(
|
Ability::from(*a).ability_id(
|
||||||
|
self.char_state,
|
||||||
Some(inventory),
|
Some(inventory),
|
||||||
Some(skill_set),
|
Some(skill_set),
|
||||||
contexts,
|
contexts,
|
||||||
@ -1118,6 +1119,7 @@ impl<'a> Skillbar<'a> {
|
|||||||
|
|
||||||
let primary_ability_id = self.active_abilities.and_then(|a| {
|
let primary_ability_id = self.active_abilities.and_then(|a| {
|
||||||
Ability::from(a.primary).ability_id(
|
Ability::from(a.primary).ability_id(
|
||||||
|
self.char_state,
|
||||||
Some(self.inventory),
|
Some(self.inventory),
|
||||||
Some(self.skillset),
|
Some(self.skillset),
|
||||||
self.context,
|
self.context,
|
||||||
@ -1148,6 +1150,7 @@ impl<'a> Skillbar<'a> {
|
|||||||
|
|
||||||
let secondary_ability_id = self.active_abilities.and_then(|a| {
|
let secondary_ability_id = self.active_abilities.and_then(|a| {
|
||||||
Ability::from(a.secondary).ability_id(
|
Ability::from(a.secondary).ability_id(
|
||||||
|
self.char_state,
|
||||||
Some(self.inventory),
|
Some(self.inventory),
|
||||||
Some(self.skillset),
|
Some(self.skillset),
|
||||||
self.context,
|
self.context,
|
||||||
|
@ -168,7 +168,12 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
|
|||||||
a.auxiliary_set(Some(inventory), Some(skillset))
|
a.auxiliary_set(Some(inventory), Some(skillset))
|
||||||
.get(i)
|
.get(i)
|
||||||
.and_then(|a| {
|
.and_then(|a| {
|
||||||
Ability::from(*a).ability_id(Some(inventory), Some(skillset), contexts)
|
Ability::from(*a).ability_id(
|
||||||
|
*char_state,
|
||||||
|
Some(inventory),
|
||||||
|
Some(skillset),
|
||||||
|
contexts,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -257,9 +262,9 @@ impl<'a> SlotKey<AbilitiesSource<'a>, img_ids::Imgs> for AbilitySlot {
|
|||||||
Some(inventory),
|
Some(inventory),
|
||||||
Some(skillset),
|
Some(skillset),
|
||||||
)
|
)
|
||||||
.ability_id(Some(inventory), Some(skillset), contexts),
|
.ability_id(None, Some(inventory), Some(skillset), contexts),
|
||||||
Self::Ability(ability) => {
|
Self::Ability(ability) => {
|
||||||
Ability::from(*ability).ability_id(Some(inventory), Some(skillset), contexts)
|
Ability::from(*ability).ability_id(None, Some(inventory), Some(skillset), contexts)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -590,6 +590,9 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
|
|||||||
"common.abilities.music.washboard" => imgs.instrument,
|
"common.abilities.music.washboard" => imgs.instrument,
|
||||||
"common.abilities.music.steeltonguedrum" => imgs.instrument,
|
"common.abilities.music.steeltonguedrum" => imgs.instrument,
|
||||||
"common.abilities.music.shamisen" => imgs.instrument,
|
"common.abilities.music.shamisen" => imgs.instrument,
|
||||||
|
// Glider
|
||||||
|
"common.abilities.debug.glide_boost" => imgs.flyingrod_m2,
|
||||||
|
"common.abilities.debug.glide_speeder" => imgs.flyingrod_m1,
|
||||||
_ => imgs.not_found,
|
_ => imgs.not_found,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1062,7 +1062,7 @@ impl FigureMgr {
|
|||||||
let ability_id = character.and_then(|c| {
|
let ability_id = character.and_then(|c| {
|
||||||
c.ability_info()
|
c.ability_info()
|
||||||
.and_then(|a| a.ability)
|
.and_then(|a| a.ability)
|
||||||
.and_then(|a| a.ability_id(inventory))
|
.and_then(|a| a.ability_id(Some(c), inventory))
|
||||||
});
|
});
|
||||||
|
|
||||||
let move_dir = {
|
let move_dir = {
|
||||||
|
Loading…
Reference in New Issue
Block a user