mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
fmt
This commit is contained in:
parent
e8a5de4e65
commit
b644ff7668
@ -80,7 +80,13 @@ impl Clock {
|
||||
if self.last_dts.len() >= NUMBER_OF_DELTAS_COMPARED {
|
||||
// Take the median of the last few tick times
|
||||
let mut dts = [0.0; NUMBER_OF_DELTAS_COMPARED];
|
||||
for (i, dt) in self.last_dts.iter().rev().take(NUMBER_OF_DELTAS_COMPARED).enumerate() {
|
||||
for (i, dt) in self
|
||||
.last_dts
|
||||
.iter()
|
||||
.rev()
|
||||
.take(NUMBER_OF_DELTAS_COMPARED)
|
||||
.enumerate()
|
||||
{
|
||||
dts[i] = **dt;
|
||||
}
|
||||
dts.sort_by_key(|x| ordered_float::OrderedFloat(*x));
|
||||
|
@ -824,9 +824,7 @@ impl ServerChatCommand {
|
||||
}
|
||||
|
||||
/// Produce an iterator over all the available commands
|
||||
pub fn iter() -> impl Iterator<Item = Self> + Clone {
|
||||
<Self as IntoEnumIterator>::iter()
|
||||
}
|
||||
pub fn iter() -> impl Iterator<Item = Self> + Clone { <Self as IntoEnumIterator>::iter() }
|
||||
|
||||
/// A message that explains what the command does
|
||||
pub fn help_string(&self) -> String {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{combat::DamageContributor, comp, uid::Uid, DamageSource, terrain::SpriteKind};
|
||||
use crate::{combat::DamageContributor, comp, terrain::SpriteKind, uid::Uid, DamageSource};
|
||||
use comp::{beam, item::Reagent, poise::PoiseState, skillset::SkillGroupKind, UtteranceKind};
|
||||
use hashbrown::HashSet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -77,7 +77,6 @@ where
|
||||
let max = (self.to - self.from).magnitude();
|
||||
|
||||
for _ in 0..self.max_iter {
|
||||
|
||||
// Allow one iteration above max.
|
||||
if dist > max {
|
||||
break;
|
||||
|
@ -110,7 +110,6 @@ impl SkillSetBuilder {
|
||||
/// 2) If added skill already applied
|
||||
/// 3) If added skill wasn't applied at the end
|
||||
pub fn with_skill(mut self, skill: Skill, level: u16) -> Self {
|
||||
|
||||
let Some(group) = skill.skill_group_kind() else {
|
||||
let err = format!(
|
||||
"Tried to add skill: {:?} which does not have an associated skill group.",
|
||||
|
@ -96,7 +96,11 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
},
|
||||
StageSection::Action => {
|
||||
if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input))
|
||||
if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& (self.static_data.energy_drain <= f32::EPSILON
|
||||
|| update.energy.current() > 0.0)
|
||||
{
|
||||
|
@ -1,9 +1,7 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{character_state::OutputEvents, CharacterState, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
},
|
||||
states::behavior::{CharacterBehavior, JoinData},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -76,7 +74,11 @@ impl CharacterBehavior for Data {
|
||||
},
|
||||
StageSection::Action => {
|
||||
if self.static_data.can_hold
|
||||
&& self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
// Block
|
||||
update.character = CharacterState::BasicBlock(Data {
|
||||
|
@ -118,7 +118,12 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
} else {
|
||||
// Done
|
||||
if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) {
|
||||
if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
reset_state(self, data, output_events, &mut update);
|
||||
} else {
|
||||
end_melee_ability(data, &mut update);
|
||||
@ -145,11 +150,6 @@ fn reset_state(
|
||||
update: &mut StateUpdate,
|
||||
) {
|
||||
if let Some(input) = data.static_data.ability_info.input {
|
||||
handle_input(
|
||||
join,
|
||||
output_events,
|
||||
update,
|
||||
input,
|
||||
);
|
||||
handle_input(join, output_events, update, input);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
combat::CombatEffect,
|
||||
comp::{
|
||||
character_state::OutputEvents, Body, CharacterState, LightEmitter, Pos,
|
||||
ProjectileConstructor, StateUpdate,
|
||||
},
|
||||
combat::CombatEffect,
|
||||
event::ServerEvent,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
@ -127,7 +127,12 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
} else {
|
||||
// Done
|
||||
if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) {
|
||||
if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
reset_state(self, data, output_events, &mut update);
|
||||
} else {
|
||||
end_ability(data, &mut update);
|
||||
@ -154,11 +159,6 @@ fn reset_state(
|
||||
update: &mut StateUpdate,
|
||||
) {
|
||||
if let Some(input) = data.static_data.ability_info.input {
|
||||
handle_input(
|
||||
join,
|
||||
output_events,
|
||||
update,
|
||||
input,
|
||||
);
|
||||
handle_input(join, output_events, update, input);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
self, character_state::OutputEvents, item::{tool::AbilityMap, MaterialStatManifest}, ActiveAbilities, Beam,
|
||||
Body, CharacterState, Combo, ControlAction, Controller, ControllerInputs, Density, Energy,
|
||||
Health, InputAttr, InputKind, Inventory, InventoryAction, Mass, Melee, Ori, PhysicsState,
|
||||
Pos, SkillSet, StateUpdate, Stats, Vel,
|
||||
self,
|
||||
character_state::OutputEvents,
|
||||
item::{tool::AbilityMap, MaterialStatManifest},
|
||||
ActiveAbilities, Beam, Body, CharacterState, Combo, ControlAction, Controller,
|
||||
ControllerInputs, Density, Energy, Health, InputAttr, InputKind, Inventory,
|
||||
InventoryAction, Mass, Melee, Ori, PhysicsState, Pos, SkillSet, StateUpdate, Stats, Vel,
|
||||
},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
@ -56,8 +58,8 @@ pub trait CharacterBehavior {
|
||||
fn talk(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
|
||||
StateUpdate::from(data)
|
||||
}
|
||||
// start_input has custom implementation in the following character states that may also need to be modified when changes are made here:
|
||||
// ComboMelee2
|
||||
// start_input has custom implementation in the following character states that
|
||||
// may also need to be modified when changes are made here: ComboMelee2
|
||||
fn start_input(
|
||||
&self,
|
||||
data: &JoinData,
|
||||
|
@ -46,7 +46,12 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
} else {
|
||||
// Done
|
||||
if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) {
|
||||
if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
reset_state(self, data, output_events, &mut update);
|
||||
} else {
|
||||
update.vel.0 = update.vel.0.try_normalized().unwrap_or_default()
|
||||
@ -70,11 +75,6 @@ fn reset_state(
|
||||
update: &mut StateUpdate,
|
||||
) {
|
||||
if let Some(input) = data.static_data.ability_info.input {
|
||||
handle_input(
|
||||
join,
|
||||
output_events,
|
||||
update,
|
||||
input,
|
||||
);
|
||||
handle_input(join, output_events, update, input);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
comp::{character_state::OutputEvents, CharacterState, MeleeConstructor, StateUpdate},
|
||||
combat::CombatEffect,
|
||||
comp::{character_state::OutputEvents, CharacterState, MeleeConstructor, StateUpdate},
|
||||
event::LocalEvent,
|
||||
outcome::Outcome,
|
||||
states::{
|
||||
@ -61,7 +61,11 @@ impl CharacterBehavior for Data {
|
||||
|
||||
match self.stage_section {
|
||||
StageSection::Charge => {
|
||||
if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input))
|
||||
if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& update.energy.current() >= self.static_data.energy_cost
|
||||
&& self.timer < self.static_data.charge_duration
|
||||
{
|
||||
@ -80,7 +84,11 @@ impl CharacterBehavior for Data {
|
||||
update
|
||||
.energy
|
||||
.change_by(-self.static_data.energy_drain * data.dt.0);
|
||||
} else if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input))
|
||||
} else if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& update.energy.current() >= self.static_data.energy_cost
|
||||
{
|
||||
// Maintains charge
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
combat::CombatEffect,
|
||||
comp::{
|
||||
character_state::OutputEvents, projectile::ProjectileConstructor, Body, CharacterState,
|
||||
LightEmitter, Pos, StateUpdate,
|
||||
},
|
||||
combat::CombatEffect,
|
||||
event::ServerEvent,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
@ -99,7 +99,13 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
},
|
||||
StageSection::Charge => {
|
||||
if !self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) && !self.exhausted {
|
||||
if !self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& !self.exhausted
|
||||
{
|
||||
let charge_frac = self.charge_frac();
|
||||
let arrow = ProjectileConstructor::Arrow {
|
||||
damage: self.static_data.initial_damage
|
||||
@ -142,7 +148,11 @@ impl CharacterBehavior for Data {
|
||||
..*self
|
||||
});
|
||||
} else if self.timer < self.static_data.charge_duration
|
||||
&& self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
// Charges
|
||||
update.character = CharacterState::ChargedRanged(Data {
|
||||
@ -154,7 +164,12 @@ impl CharacterBehavior for Data {
|
||||
update
|
||||
.energy
|
||||
.change_by(-self.static_data.energy_drain * data.dt.0);
|
||||
} else if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) {
|
||||
} else if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
// Holds charge
|
||||
update.character = CharacterState::ChargedRanged(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
|
@ -2,7 +2,8 @@ use crate::{
|
||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||
comp::{
|
||||
character_state::OutputEvents,
|
||||
tool::{Stats, ToolKind}, melee::MultiTarget,
|
||||
melee::MultiTarget,
|
||||
tool::{Stats, ToolKind},
|
||||
CharacterState, Melee, StateUpdate,
|
||||
},
|
||||
states::{
|
||||
@ -341,7 +342,12 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
} else {
|
||||
// Done
|
||||
if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) {
|
||||
if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
reset_state(self, data, output_events, &mut update);
|
||||
} else {
|
||||
end_melee_ability(data, &mut update);
|
||||
@ -362,12 +368,11 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
impl Data {
|
||||
/// Index should be `self.stage - 1`, however in cases of client-server desync
|
||||
/// this can cause panics. This ensures that `self.stage - 1` is valid, and if it
|
||||
/// isn't, index of 0 is used, which is always safe.
|
||||
/// Index should be `self.stage - 1`, however in cases of client-server
|
||||
/// desync this can cause panics. This ensures that `self.stage - 1` is
|
||||
/// valid, and if it isn't, index of 0 is used, which is always safe.
|
||||
pub fn stage_index(&self) -> usize {
|
||||
self
|
||||
.static_data
|
||||
self.static_data
|
||||
.stage_data
|
||||
.get(self.stage as usize - 1)
|
||||
.map_or(0, |_| self.stage as usize - 1)
|
||||
@ -381,12 +386,7 @@ fn reset_state(
|
||||
update: &mut StateUpdate,
|
||||
) {
|
||||
if let Some(input) = data.static_data.ability_info.input {
|
||||
handle_input(
|
||||
join,
|
||||
output_events,
|
||||
update,
|
||||
input,
|
||||
);
|
||||
handle_input(join, output_events, update, input);
|
||||
|
||||
if let CharacterState::ComboMelee(c) = &mut update.character {
|
||||
c.stage = (data.stage % data.static_data.num_stages) + 1;
|
||||
|
@ -1,11 +1,15 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
character_state::OutputEvents, tool::Stats, CharacterState, InputKind,
|
||||
MeleeConstructor, StateUpdate, InputAttr, InventoryAction, slot::{Slot, EquipSlot},
|
||||
character_state::OutputEvents,
|
||||
slot::{EquipSlot, Slot},
|
||||
tool::Stats,
|
||||
CharacterState, InputAttr, InputKind, InventoryAction, MeleeConstructor, StateUpdate,
|
||||
},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*, idle, wielding,
|
||||
idle,
|
||||
utils::*,
|
||||
wielding,
|
||||
},
|
||||
uid::Uid,
|
||||
};
|
||||
@ -117,7 +121,10 @@ impl CharacterBehavior for Data {
|
||||
let ability_input = if self.static_data.is_stance {
|
||||
InputKind::Primary
|
||||
} else {
|
||||
self.static_data.ability_info.input.unwrap_or(InputKind::Primary)
|
||||
self.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.unwrap_or(InputKind::Primary)
|
||||
};
|
||||
|
||||
handle_orientation(data, &mut update, 1.0, None);
|
||||
@ -133,7 +140,8 @@ impl CharacterBehavior for Data {
|
||||
|
||||
match self.stage_section {
|
||||
Some(StageSection::Ready) => {
|
||||
// Adds a small duration to entering a stance to discourage spam swapping stances for ability activation benefits of matching stance
|
||||
// Adds a small duration to entering a stance to discourage spam swapping
|
||||
// stances for ability activation benefits of matching stance
|
||||
if self.timer < STANCE_ENTER_TIME {
|
||||
if let CharacterState::ComboMelee2(c) = &mut update.character {
|
||||
c.timer = tick_attack_or_default(data, self.timer, None);
|
||||
@ -166,8 +174,10 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
if input_is_pressed(data, ability_input) {
|
||||
if let CharacterState::ComboMelee2(c) = &mut update.character {
|
||||
// Only have the next strike skip the recover period of this strike if not every strike in the combo is complete yet
|
||||
c.start_next_strike = (c.completed_strikes + 1) < c.static_data.strikes.len();
|
||||
// Only have the next strike skip the recover period of this strike if not
|
||||
// every strike in the combo is complete yet
|
||||
c.start_next_strike =
|
||||
(c.completed_strikes + 1) < c.static_data.strikes.len();
|
||||
}
|
||||
}
|
||||
if self.timer.as_secs_f32()
|
||||
@ -248,7 +258,13 @@ impl CharacterBehavior for Data {
|
||||
|
||||
if input_is_pressed(data, ability_input) {
|
||||
next_strike(&mut update)
|
||||
} else if !self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) && !interrupted {
|
||||
} else if !self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& !interrupted
|
||||
{
|
||||
attempt_input(data, output_events, &mut update);
|
||||
}
|
||||
},
|
||||
@ -266,7 +282,8 @@ impl CharacterBehavior for Data {
|
||||
) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
if matches!(data.character, CharacterState::ComboMelee2(data) if data.static_data.ability_info.input == Some(input) && input != InputKind::Primary && data.stage_section.is_none()) {
|
||||
if matches!(data.character, CharacterState::ComboMelee2(data) if data.static_data.ability_info.input == Some(input) && input != InputKind::Primary && data.stage_section.is_none())
|
||||
{
|
||||
end_melee_ability(data, &mut update);
|
||||
} else {
|
||||
update.queued_inputs.insert(input, InputAttr {
|
||||
@ -281,8 +298,9 @@ impl CharacterBehavior for Data {
|
||||
let mut update = StateUpdate::from(data);
|
||||
if let CharacterState::ComboMelee2(c) = data.character {
|
||||
if c.stage_section.is_none() {
|
||||
update.character =
|
||||
CharacterState::Wielding(wielding::Data { is_sneaking: data.character.is_stealthy() });
|
||||
update.character = CharacterState::Wielding(wielding::Data {
|
||||
is_sneaking: data.character.is_stealthy(),
|
||||
});
|
||||
attempt_swap_equipped_weapons(data, &mut update);
|
||||
}
|
||||
}
|
||||
@ -314,7 +332,11 @@ impl CharacterBehavior for Data {
|
||||
let reset_to_idle = match inv_action {
|
||||
InventoryAction::Drop(slot)
|
||||
| InventoryAction::Swap(slot, _)
|
||||
| InventoryAction::Swap(_, Slot::Equip(slot)) if matches!(slot, EquipSlot::ActiveMainhand | EquipSlot::ActiveOffhand) => true,
|
||||
| InventoryAction::Swap(_, Slot::Equip(slot))
|
||||
if matches!(slot, EquipSlot::ActiveMainhand | EquipSlot::ActiveOffhand) =>
|
||||
{
|
||||
true
|
||||
},
|
||||
InventoryAction::Use(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
@ -363,7 +385,10 @@ impl CharacterBehavior for Data {
|
||||
fn sneak(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
if let CharacterState::ComboMelee2(c) = data.character {
|
||||
if c.stage_section.is_none() && data.physics.on_ground.is_some() && data.body.is_humanoid() {
|
||||
if c.stage_section.is_none()
|
||||
&& data.physics.on_ground.is_some()
|
||||
&& data.body.is_humanoid()
|
||||
{
|
||||
update.character = CharacterState::Wielding(wielding::Data { is_sneaking: true });
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,11 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
// Transitions to charge section of stage
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
auto_charge: !self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)),
|
||||
auto_charge: !self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input)),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Charge,
|
||||
..*self
|
||||
@ -90,7 +94,11 @@ impl CharacterBehavior for Data {
|
||||
},
|
||||
StageSection::Charge => {
|
||||
if self.timer < self.charge_end_timer
|
||||
&& (self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& (self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
|| (self.auto_charge && self.timer < self.static_data.charge_duration))
|
||||
&& update.energy.current() > 0.0
|
||||
{
|
||||
|
@ -88,9 +88,9 @@ impl CharacterBehavior for Data {
|
||||
self.static_data.combo_on_use as f32
|
||||
/ self.static_data.minimum_combo as f32
|
||||
},
|
||||
ScalingKind::Sqrt => {
|
||||
(self.static_data.combo_on_use as f32 / self.static_data.minimum_combo as f32).sqrt()
|
||||
},
|
||||
ScalingKind::Sqrt => (self.static_data.combo_on_use as f32
|
||||
/ self.static_data.minimum_combo as f32)
|
||||
.sqrt(),
|
||||
};
|
||||
match scaling.target {
|
||||
ScalingTarget::Attack => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
comp::{character_state::OutputEvents, CharacterState, MeleeConstructor, StateUpdate},
|
||||
combat::CombatEffect,
|
||||
comp::{character_state::OutputEvents, CharacterState, MeleeConstructor, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::{StageSection, *},
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement, Damage, DamageKind,
|
||||
DamageSource, GroupTarget, Knockback,
|
||||
},
|
||||
comp::{character_state::OutputEvents, CharacterState, shockwave, StateUpdate},
|
||||
comp::{character_state::OutputEvents, shockwave, CharacterState, StateUpdate},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
outcome::Outcome,
|
||||
states::{
|
||||
@ -88,7 +88,6 @@ impl CharacterBehavior for Data {
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
||||
// Transitions to leap portion of state after buildup delay
|
||||
update.character = CharacterState::LeapShockwave(Data {
|
||||
timer: Duration::default(),
|
||||
@ -102,7 +101,7 @@ impl CharacterBehavior for Data {
|
||||
// Apply jumping force
|
||||
let progress = 1.0
|
||||
- self.timer.as_secs_f32()
|
||||
/ self.static_data.movement_duration.as_secs_f32();
|
||||
/ self.static_data.movement_duration.as_secs_f32();
|
||||
handle_forced_movement(data, &mut update, ForcedMovement::Leap {
|
||||
vertical: self.static_data.vertical_leap_strength,
|
||||
forward: self.static_data.forward_leap_strength,
|
||||
@ -142,12 +141,12 @@ impl CharacterBehavior for Data {
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
CombatEffect::Poise(self.static_data.poise_damage),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
let knockback = AttackEffect::new(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
CombatEffect::Knockback(self.static_data.knockback),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
let mut damage = AttackDamage::new(
|
||||
Damage {
|
||||
source: DamageSource::Shockwave,
|
||||
@ -185,9 +184,7 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
// Send local event used for frontend shenanigans
|
||||
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::IceSpikes {
|
||||
pos: data.pos.0
|
||||
+ *data.ori.look_dir()
|
||||
* (data.body.max_radius()),
|
||||
pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
|
||||
}));
|
||||
} else {
|
||||
// Transitions to recover
|
||||
|
@ -56,7 +56,12 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
} else {
|
||||
// Done
|
||||
if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) {
|
||||
if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
reset_state(self, data, output_events, &mut update);
|
||||
} else {
|
||||
end_ability(data, &mut update);
|
||||
@ -70,7 +75,12 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
|
||||
// At end of state logic so an interrupt isn't overwritten
|
||||
if !self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input)) {
|
||||
if !self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
{
|
||||
handle_dodge_input(data, &mut update);
|
||||
}
|
||||
|
||||
@ -85,11 +95,6 @@ fn reset_state(
|
||||
update: &mut StateUpdate,
|
||||
) {
|
||||
if let Some(input) = data.static_data.ability_info.input {
|
||||
handle_input(
|
||||
join,
|
||||
output_events,
|
||||
update,
|
||||
input,
|
||||
);
|
||||
handle_input(join, output_events, update, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
combat::CombatEffect,
|
||||
comp::{
|
||||
character_state::OutputEvents, Body, CharacterState, LightEmitter, Pos,
|
||||
ProjectileConstructor, StateUpdate,
|
||||
},
|
||||
combat::CombatEffect,
|
||||
event::ServerEvent,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
@ -87,7 +87,11 @@ impl CharacterBehavior for Data {
|
||||
.unwrap_or_default(),
|
||||
..*self
|
||||
});
|
||||
} else if self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input))
|
||||
} else if self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))
|
||||
&& update.energy.current() >= self.static_data.energy_cost
|
||||
{
|
||||
// Fire if input is pressed still
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
buff::{BuffChange, BuffKind},
|
||||
character_state::{OutputEvents, AttackImmunities},
|
||||
character_state::{AttackImmunities, OutputEvents},
|
||||
CharacterState, InputKind, StateUpdate,
|
||||
},
|
||||
event::ServerEvent,
|
||||
|
@ -145,9 +145,7 @@ impl CharacterBehavior for Data {
|
||||
// Send local event used for frontend shenanigans
|
||||
if self.static_data.specifier == shockwave::FrontendSpecifier::IceSpikes {
|
||||
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::FlashFreeze {
|
||||
pos: data.pos.0
|
||||
+ *data.ori.look_dir()
|
||||
* (data.body.max_radius()),
|
||||
pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
|
@ -57,8 +57,7 @@ impl CharacterBehavior for Data {
|
||||
data.sidewalk = 0.0;
|
||||
}
|
||||
// forward, max at 8u/s
|
||||
(data.dt.0 * 3.0)
|
||||
.clamp(0.0, 8.0 - current_planar_velocity)
|
||||
(data.dt.0 * 3.0).clamp(0.0, 8.0 - current_planar_velocity)
|
||||
} else {
|
||||
if let CharacterState::Skate(data) = &mut update.character {
|
||||
data.accelerate = -1.0;
|
||||
|
@ -121,7 +121,11 @@ impl CharacterBehavior for Data {
|
||||
} else if update.energy.current() >= self.static_data.energy_cost
|
||||
&& (self.consecutive_spins < self.static_data.num_spins
|
||||
|| (self.static_data.is_infinite
|
||||
&& self.static_data.ability_info.input.map_or(false, |input| input_is_pressed(data, input))))
|
||||
&& self
|
||||
.static_data
|
||||
.ability_info
|
||||
.input
|
||||
.map_or(false, |input| input_is_pressed(data, input))))
|
||||
{
|
||||
update.character = CharacterState::SpinMelee(Data {
|
||||
timer: Duration::default(),
|
||||
|
@ -1,11 +1,13 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{character_state::OutputEvents, CharacterState, InventoryManip, StateUpdate, item::{Item, ItemDefinitionIdOwned}},
|
||||
event::{ServerEvent, LocalEvent},
|
||||
outcome::Outcome,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
comp::{
|
||||
character_state::OutputEvents,
|
||||
item::{Item, ItemDefinitionIdOwned},
|
||||
CharacterState, InventoryManip, StateUpdate,
|
||||
},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
outcome::Outcome,
|
||||
states::behavior::{CharacterBehavior, JoinData},
|
||||
terrain::SpriteKind,
|
||||
util::Dir,
|
||||
};
|
||||
@ -95,20 +97,43 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
} else {
|
||||
// Create inventory manipulation event
|
||||
let required_item = self.static_data.required_item
|
||||
.as_ref()
|
||||
.and_then(|(i, consume)| Some((
|
||||
Item::new_from_item_definition_id(i.as_ref(), data.ability_map, data.msm).ok()?,
|
||||
*consume,
|
||||
)));
|
||||
let has_required_item = required_item.as_ref().map_or(true, |(item, _consume)| data.inventory.map_or(false, |inv| inv.contains(item)));
|
||||
let required_item =
|
||||
self.static_data
|
||||
.required_item
|
||||
.as_ref()
|
||||
.and_then(|(i, consume)| {
|
||||
Some((
|
||||
Item::new_from_item_definition_id(
|
||||
i.as_ref(),
|
||||
data.ability_map,
|
||||
data.msm,
|
||||
)
|
||||
.ok()?,
|
||||
*consume,
|
||||
))
|
||||
});
|
||||
let has_required_item =
|
||||
required_item.as_ref().map_or(true, |(item, _consume)| {
|
||||
data.inventory.map_or(false, |inv| inv.contains(item))
|
||||
});
|
||||
if has_required_item {
|
||||
let inv_slot = required_item.and_then(|(item, consume)| Some((data.inventory.and_then(|inv| inv.get_slot_of_item(&item))?, consume)));
|
||||
let inv_manip = InventoryManip::Collect { sprite_pos: self.static_data.sprite_pos, required_item: inv_slot };
|
||||
output_events.emit_server(ServerEvent::InventoryManip(data.entity, inv_manip));
|
||||
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::SpriteUnlocked {
|
||||
pos: self.static_data.sprite_pos,
|
||||
}));
|
||||
let inv_slot = required_item.and_then(|(item, consume)| {
|
||||
Some((
|
||||
data.inventory.and_then(|inv| inv.get_slot_of_item(&item))?,
|
||||
consume,
|
||||
))
|
||||
});
|
||||
let inv_manip = InventoryManip::Collect {
|
||||
sprite_pos: self.static_data.sprite_pos,
|
||||
required_item: inv_slot,
|
||||
};
|
||||
output_events
|
||||
.emit_server(ServerEvent::InventoryManip(data.entity, inv_manip));
|
||||
output_events.emit_local(LocalEvent::CreateOutcome(
|
||||
Outcome::SpriteUnlocked {
|
||||
pos: self.static_data.sprite_pos,
|
||||
},
|
||||
));
|
||||
}
|
||||
// Done
|
||||
end_ability(data, &mut update);
|
||||
|
@ -26,7 +26,8 @@ pub struct StaticData {
|
||||
pub recover_duration: Duration,
|
||||
/// What kind of sprite is created by this state
|
||||
pub sprite: SpriteKind,
|
||||
/// Duration until sprite-delete begins (in sec), randomization-range of sprite-delete-time (in sec)
|
||||
/// Duration until sprite-delete begins (in sec), randomization-range of
|
||||
/// sprite-delete-time (in sec)
|
||||
pub del_timeout: Option<(f32, f32)>,
|
||||
/// Range that sprites are created relative to the summonner
|
||||
pub summon_distance: (f32, f32),
|
||||
@ -92,7 +93,15 @@ impl CharacterBehavior for Data {
|
||||
let spiral = Spiral2d::with_edge_radius(radius);
|
||||
for point in spiral {
|
||||
// If square is in the angle and is not sparse, generate sprite
|
||||
if data.ori.look_vec().xy().angle_between(point.as_()).to_degrees() <= (self.static_data.angle / 2.0) && !thread_rng().gen_bool(self.static_data.sparseness) {
|
||||
if data
|
||||
.ori
|
||||
.look_vec()
|
||||
.xy()
|
||||
.angle_between(point.as_())
|
||||
.to_degrees()
|
||||
<= (self.static_data.angle / 2.0)
|
||||
&& !thread_rng().gen_bool(self.static_data.sparseness)
|
||||
{
|
||||
// The coordinates of where the sprite is created
|
||||
let sprite_pos = Vec3::new(
|
||||
data.pos.0.x.floor() as i32 + point.x,
|
||||
@ -120,8 +129,7 @@ impl CharacterBehavior for Data {
|
||||
let z = sprite_pos.z + (10.5 - obstacle_z).ceil() as i32;
|
||||
|
||||
// Location sprite will be created
|
||||
let sprite_pos =
|
||||
Vec3::new(sprite_pos.x, sprite_pos.y, z);
|
||||
let sprite_pos = Vec3::new(sprite_pos.x, sprite_pos.y, z);
|
||||
// Layers of sprites
|
||||
let layers = match self.static_data.sprite {
|
||||
SpriteKind::SeaUrchin => 2,
|
||||
@ -132,7 +140,7 @@ impl CharacterBehavior for Data {
|
||||
output_events.emit_server(ServerEvent::CreateSprite {
|
||||
pos: Vec3::new(sprite_pos.x, sprite_pos.y, z + i),
|
||||
sprite: self.static_data.sprite,
|
||||
del_timeout: self.static_data.del_timeout,
|
||||
del_timeout: self.static_data.del_timeout,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -147,9 +155,7 @@ impl CharacterBehavior for Data {
|
||||
// Send local event used for frontend shenanigans
|
||||
if self.static_data.sprite == SpriteKind::IceSpike {
|
||||
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::IceCrack {
|
||||
pos: data.pos.0
|
||||
+ *data.ori.look_dir()
|
||||
* (data.body.max_radius()),
|
||||
pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
|
@ -1,9 +1,7 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{character_state::OutputEvents, CharacterState, PoiseState, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
},
|
||||
states::behavior::{CharacterBehavior, JoinData},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
@ -10,9 +10,7 @@ use crate::{
|
||||
CharacterState, InventoryManip, StateUpdate,
|
||||
},
|
||||
event::ServerEvent,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
},
|
||||
states::behavior::{CharacterBehavior, JoinData},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
character_state::OutputEvents,
|
||||
controller::InventoryManip,
|
||||
inventory::slot::{ArmorSlot, EquipSlot, Slot},
|
||||
item::{armor::Friction, tool::AbilityContext, Hands, ItemKind, ToolKind, Item},
|
||||
item::{armor::Friction, tool::AbilityContext, Hands, Item, ItemKind, ToolKind},
|
||||
quadruped_low, quadruped_medium, quadruped_small,
|
||||
skills::{Skill, SwimSkill, SKILL_MODIFIERS},
|
||||
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
||||
@ -17,9 +17,9 @@ use crate::{
|
||||
event::{LocalEvent, ServerEvent},
|
||||
outcome::Outcome,
|
||||
states::{behavior::JoinData, utils::CharacterState::Idle, *},
|
||||
terrain::{TerrainChunkSize, UnlockKind},
|
||||
util::Dir,
|
||||
vol::{ReadVol, RectVolSize},
|
||||
terrain::{TerrainChunkSize, UnlockKind},
|
||||
};
|
||||
use core::hash::BuildHasherDefault;
|
||||
use fxhash::FxHasher64;
|
||||
@ -826,8 +826,7 @@ pub fn handle_manipulate_loadout(
|
||||
} else {
|
||||
// Else emit inventory action instantaneously
|
||||
let inv_manip = InventoryManip::Use(slot);
|
||||
output_events
|
||||
.emit_server(ServerEvent::InventoryManip(data.entity, inv_manip));
|
||||
output_events.emit_server(ServerEvent::InventoryManip(data.entity, inv_manip));
|
||||
}
|
||||
},
|
||||
InventoryAction::Collect(sprite_pos) => {
|
||||
@ -913,15 +912,25 @@ pub fn handle_manipulate_loadout(
|
||||
.into_path()
|
||||
.is_some();
|
||||
|
||||
let required_item = sprite_at_pos.and_then(|s| match s.unlock_condition(sprite_cfg.cloned()) {
|
||||
UnlockKind::Free => None,
|
||||
UnlockKind::Requires(item) => Some((item, false)),
|
||||
UnlockKind::Consumes(item) => Some((item, true)),
|
||||
});
|
||||
let required_item =
|
||||
sprite_at_pos.and_then(|s| match s.unlock_condition(sprite_cfg.cloned()) {
|
||||
UnlockKind::Free => None,
|
||||
UnlockKind::Requires(item) => Some((item, false)),
|
||||
UnlockKind::Consumes(item) => Some((item, true)),
|
||||
});
|
||||
let has_required_items = required_item
|
||||
.as_ref()
|
||||
.and_then(|(i, _consume)| Item::new_from_item_definition_id(i.as_ref(), data.ability_map, data.msm).ok())
|
||||
.map_or(true, |i| data.inventory.map_or(false, |inv| inv.contains(&i)));
|
||||
.and_then(|(i, _consume)| {
|
||||
Item::new_from_item_definition_id(
|
||||
i.as_ref(),
|
||||
data.ability_map,
|
||||
data.msm,
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.map_or(true, |i| {
|
||||
data.inventory.map_or(false, |inv| inv.contains(&i))
|
||||
});
|
||||
|
||||
// If path can be found between entity interacting with sprite and entity, start
|
||||
// interaction with sprite
|
||||
@ -934,25 +943,28 @@ pub fn handle_manipulate_loadout(
|
||||
let (buildup_duration, use_duration, recover_duration) =
|
||||
sprite_interact.durations();
|
||||
|
||||
update.character = CharacterState::SpriteInteract(sprite_interact::Data {
|
||||
static_data: sprite_interact::StaticData {
|
||||
buildup_duration,
|
||||
use_duration,
|
||||
recover_duration,
|
||||
sprite_pos,
|
||||
sprite_kind: sprite_interact,
|
||||
was_wielded: data.character.is_wield(),
|
||||
was_sneak: data.character.is_stealthy(),
|
||||
required_item,
|
||||
ability_info: AbilityInfo::from_forced_state_change(data.character),
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
})
|
||||
update.character =
|
||||
CharacterState::SpriteInteract(sprite_interact::Data {
|
||||
static_data: sprite_interact::StaticData {
|
||||
buildup_duration,
|
||||
use_duration,
|
||||
recover_duration,
|
||||
sprite_pos,
|
||||
sprite_kind: sprite_interact,
|
||||
was_wielded: data.character.is_wield(),
|
||||
was_sneak: data.character.is_stealthy(),
|
||||
required_item,
|
||||
ability_info: AbilityInfo::from_forced_state_change(
|
||||
data.character,
|
||||
),
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
})
|
||||
} else {
|
||||
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::FailedSpriteUnlock {
|
||||
pos: sprite_pos,
|
||||
}));
|
||||
output_events.emit_local(LocalEvent::CreateOutcome(
|
||||
Outcome::FailedSpriteUnlock { pos: sprite_pos },
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -968,7 +980,10 @@ pub fn handle_manipulate_loadout(
|
||||
output_events.emit_server(ServerEvent::InventoryManip(data.entity, inv_manip));
|
||||
},
|
||||
InventoryAction::Sort => {
|
||||
output_events.emit_server(ServerEvent::InventoryManip(data.entity, InventoryManip::Sort));
|
||||
output_events.emit_server(ServerEvent::InventoryManip(
|
||||
data.entity,
|
||||
InventoryManip::Sort,
|
||||
));
|
||||
},
|
||||
InventoryAction::Use(slot @ Slot::Equip(_)) => {
|
||||
let inv_manip = InventoryManip::Use(slot);
|
||||
|
@ -26,8 +26,7 @@ impl CharacterBehavior for Data {
|
||||
let lift = WALLRUN_ANTIGRAV;
|
||||
update.vel.0.z += data.dt.0
|
||||
* lift
|
||||
* (Vec2::<f32>::from(update.vel.0).magnitude() * 0.075)
|
||||
.clamp(0.2, 1.0);
|
||||
* (Vec2::<f32>::from(update.vel.0).magnitude() * 0.075).clamp(0.2, 1.0);
|
||||
}
|
||||
|
||||
// fall off wall, hit ground, or enter water
|
||||
|
@ -52,7 +52,11 @@ impl CharacterBehavior for Data {
|
||||
let reset_to_idle = match inv_action {
|
||||
InventoryAction::Drop(slot)
|
||||
| InventoryAction::Swap(slot, _)
|
||||
| InventoryAction::Swap(_, Slot::Equip(slot)) if matches!(slot, EquipSlot::ActiveMainhand | EquipSlot::ActiveOffhand) => true,
|
||||
| InventoryAction::Swap(_, Slot::Equip(slot))
|
||||
if matches!(slot, EquipSlot::ActiveMainhand | EquipSlot::ActiveOffhand) =>
|
||||
{
|
||||
true
|
||||
},
|
||||
InventoryAction::Use(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
@ -282,8 +282,7 @@ impl Block {
|
||||
BlockKind::Lava => None,
|
||||
_ => self.get_sprite().and_then(|sprite| match sprite {
|
||||
sprite if sprite.is_container() => None,
|
||||
SpriteKind::Keyhole
|
||||
| SpriteKind::KeyDoor => None,
|
||||
SpriteKind::Keyhole | SpriteKind::KeyDoor => None,
|
||||
SpriteKind::Anvil
|
||||
| SpriteKind::Cauldron
|
||||
| SpriteKind::CookingPot
|
||||
@ -307,9 +306,10 @@ impl Block {
|
||||
| SpriteKind::SeaDecorWindowVer
|
||||
| SpriteKind::Rope
|
||||
| SpriteKind::GlassBarrier => None,
|
||||
SpriteKind::EnsnaringVines | SpriteKind::EnsnaringWeb | SpriteKind::SeaUrchin | SpriteKind::IceSpike => {
|
||||
Some(0.1)
|
||||
},
|
||||
SpriteKind::EnsnaringVines
|
||||
| SpriteKind::EnsnaringWeb
|
||||
| SpriteKind::SeaUrchin
|
||||
| SpriteKind::IceSpike => Some(0.1),
|
||||
_ => Some(0.25),
|
||||
}),
|
||||
}
|
||||
|
@ -198,8 +198,7 @@ impl<V, S: RectVolSize, M: Clone> ReadVol for Chonk<V, S, M> {
|
||||
let rpos = pos
|
||||
- Vec3::unit_z()
|
||||
* (self.z_offset + sub_chunk_idx * SubChunkSize::<S>::SIZE.z as i32);
|
||||
self.sub_chunks[sub_chunk_idx as usize]
|
||||
.get_unchecked(rpos)
|
||||
self.sub_chunks[sub_chunk_idx as usize].get_unchecked(rpos)
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,12 +207,16 @@ impl<V, S: RectVolSize, M: Clone> ReadVol for Chonk<V, S, M> {
|
||||
Self::Vox: Copy,
|
||||
{
|
||||
let idx = self.sub_chunk_idx(aabb.min.z);
|
||||
// Special-case for the AABB being entirely within a single sub-chunk as this is very common.
|
||||
// Special-case for the AABB being entirely within a single sub-chunk as this is
|
||||
// very common.
|
||||
if idx == self.sub_chunk_idx(aabb.max.z) && idx >= 0 && idx < self.sub_chunks.len() as i32 {
|
||||
let sub_chunk = &self.sub_chunks[idx as usize];
|
||||
let z_off = self.z_offset + idx * SubChunkSize::<S>::SIZE.z as i32;
|
||||
sub_chunk.for_each_in(
|
||||
Aabb { min: aabb.min.with_z(aabb.min.z - z_off), max: aabb.max.with_z(aabb.max.z - z_off) },
|
||||
Aabb {
|
||||
min: aabb.min.with_z(aabb.min.z - z_off),
|
||||
max: aabb.max.with_z(aabb.max.z - z_off),
|
||||
},
|
||||
|pos, vox| f(pos.with_z(pos.z + z_off), vox),
|
||||
);
|
||||
} else {
|
||||
|
@ -202,9 +202,10 @@ impl MapSizeLg {
|
||||
/// Determine whether a chunk position is in bounds.
|
||||
pub const fn contains_chunk(&self, chunk_key: Vec2<i32>) -> bool {
|
||||
let map_size = self.chunks();
|
||||
chunk_key.x >= 0 && chunk_key.y >= 0 &&
|
||||
chunk_key.x == chunk_key.x & ((map_size.x as i32) - 1) &&
|
||||
chunk_key.y == chunk_key.y & ((map_size.y as i32) - 1)
|
||||
chunk_key.x >= 0
|
||||
&& chunk_key.y >= 0
|
||||
&& chunk_key.x == chunk_key.x & ((map_size.x as i32) - 1)
|
||||
&& chunk_key.y == chunk_key.y & ((map_size.y as i32) - 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,12 +12,12 @@ pub use self::{
|
||||
block::{Block, BlockKind},
|
||||
map::MapSizeLg,
|
||||
site::SiteKindMeta,
|
||||
sprite::{SpriteKind, SpriteCfg, UnlockKind},
|
||||
sprite::{SpriteCfg, SpriteKind, UnlockKind},
|
||||
structure::{Structure, StructuresGroup},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use roots::find_roots_cubic;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use crate::{
|
||||
vol::{ReadVol, RectVolSize},
|
||||
@ -100,9 +100,10 @@ impl CoordinateConversions for Vec2<f32> {
|
||||
|
||||
impl CoordinateConversions for Vec2<f64> {
|
||||
#[inline]
|
||||
fn wpos_to_cpos(&self) -> Self { self.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f64)}
|
||||
fn wpos_to_cpos(&self) -> Self { self.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f64) }
|
||||
|
||||
#[inline]
|
||||
fn cpos_to_wpos(&self) -> Self { self.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e * sz as f64)}
|
||||
fn cpos_to_wpos(&self) -> Self { self.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e * sz as f64) }
|
||||
}
|
||||
|
||||
// TerrainChunkMeta
|
||||
@ -205,9 +206,7 @@ impl TerrainChunkMeta {
|
||||
|
||||
pub fn debug_lines(&self) -> &[LineSegment3<f32>] { &self.debug_lines }
|
||||
|
||||
pub fn add_debug_line(&mut self, line: LineSegment3<f32>) {
|
||||
self.debug_lines.push(line);
|
||||
}
|
||||
pub fn add_debug_line(&mut self, line: LineSegment3<f32>) { self.debug_lines.push(line); }
|
||||
|
||||
pub fn sprite_cfg_at(&self, rpos: Vec3<i32>) -> Option<&SpriteCfg> {
|
||||
self.sprite_cfgs.get(&rpos)
|
||||
|
@ -1,28 +1,22 @@
|
||||
use crate::{
|
||||
comp::{item::{ItemDefinitionId, ItemDefinitionIdOwned}, tool::ToolKind},
|
||||
comp::{
|
||||
item::{ItemDefinitionId, ItemDefinitionIdOwned},
|
||||
tool::ToolKind,
|
||||
},
|
||||
lottery::LootSpec,
|
||||
make_case_elim,
|
||||
};
|
||||
use strum::EnumIter;
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use num_derive::FromPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{convert::TryFrom, fmt};
|
||||
use strum::EnumIter;
|
||||
|
||||
make_case_elim!(
|
||||
sprite_kind,
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Hash,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
EnumIter,
|
||||
FromPrimitive,
|
||||
Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, EnumIter, FromPrimitive,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum SpriteKind {
|
||||
@ -230,9 +224,9 @@ make_case_elim!(
|
||||
SeaDecorPillar = 0xC7,
|
||||
SeashellLantern = 0xC8,
|
||||
Rope = 0xC9,
|
||||
IceSpike = 0xCA,
|
||||
Bedroll = 0xCB,
|
||||
BedrollSnow = 0xCC,
|
||||
IceSpike = 0xCA,
|
||||
Bedroll = 0xCB,
|
||||
BedrollSnow = 0xCC,
|
||||
BedrollPirate = 0xCD,
|
||||
Tent = 0xCE,
|
||||
Grave = 0xCF,
|
||||
@ -242,10 +236,10 @@ make_case_elim!(
|
||||
MagicalBarrier = 0xD3,
|
||||
MagicalSeal = 0xD4,
|
||||
WallLampWizard = 0xD5,
|
||||
Candle = 0xD6,
|
||||
Candle = 0xD6,
|
||||
Keyhole = 0xD7,
|
||||
KeyDoor = 0xD8,
|
||||
CommonLockedChest = 0xD9,
|
||||
KeyDoor = 0xD8,
|
||||
CommonLockedChest = 0xD9,
|
||||
}
|
||||
);
|
||||
|
||||
@ -511,13 +505,17 @@ impl SpriteKind {
|
||||
}
|
||||
|
||||
/// Requires this item in the inventory to harvest, uses item_definition_id
|
||||
// TODO: Do we want to consolidate this with mine_tool at all? Main differences are that mine tool requires item to be an equippable tool, be equipped, and does not consume item while required_item requires that the item be in the inventory and will consume the item on collecting the sprite.
|
||||
// TODO: Do we want to consolidate this with mine_tool at all? Main differences
|
||||
// are that mine tool requires item to be an equippable tool, be equipped, and
|
||||
// does not consume item while required_item requires that the item be in the
|
||||
// inventory and will consume the item on collecting the sprite.
|
||||
pub fn unlock_condition(&self, cfg: Option<SpriteCfg>) -> UnlockKind {
|
||||
cfg
|
||||
.and_then(|cfg| cfg.unlock)
|
||||
cfg.and_then(|cfg| cfg.unlock)
|
||||
.unwrap_or_else(|| match self {
|
||||
// Example, do not let this merge with twigs requiring cheese to pick up
|
||||
SpriteKind::CommonLockedChest => UnlockKind::Consumes(ItemDefinitionId::Simple("common.items.utility.lockpick_0").to_owned()),
|
||||
SpriteKind::CommonLockedChest => UnlockKind::Consumes(
|
||||
ItemDefinitionId::Simple("common.items.utility.lockpick_0").to_owned(),
|
||||
),
|
||||
_ => UnlockKind::Free,
|
||||
})
|
||||
}
|
||||
@ -613,9 +611,8 @@ impl fmt::Display for SpriteKind {
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SPRITE_KINDS: HashMap<String, SpriteKind> = SpriteKind::iter()
|
||||
.map(|sk| (sk.to_string(), sk))
|
||||
.collect();
|
||||
pub static ref SPRITE_KINDS: HashMap<String, SpriteKind> =
|
||||
SpriteKind::iter().map(|sk| (sk.to_string(), sk)).collect();
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for SpriteKind {
|
||||
@ -629,9 +626,11 @@ impl<'a> TryFrom<&'a str> for SpriteKind {
|
||||
pub enum UnlockKind {
|
||||
/// The sprite can be freely unlocked without any conditions
|
||||
Free,
|
||||
/// The sprite requires that the opening character has a given item in their inventory
|
||||
/// The sprite requires that the opening character has a given item in their
|
||||
/// inventory
|
||||
Requires(ItemDefinitionIdOwned),
|
||||
/// The sprite will consume the given item from the opening character's inventory
|
||||
/// The sprite will consume the given item from the opening character's
|
||||
/// inventory
|
||||
Consumes(ItemDefinitionIdOwned),
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ use serde::Deserialize;
|
||||
use std::{num::NonZeroU8, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
|
||||
make_case_elim!(
|
||||
structure_block,
|
||||
#[derive(Clone, PartialEq, Debug, Deserialize)]
|
||||
|
@ -119,7 +119,7 @@ impl<Context, Target> SynthTyped<Context, Target> for WeakHead<Pure<Target>, Tar
|
||||
/// # #[allow(non_snake_case)]
|
||||
/// # #[allow(dead_code)]
|
||||
/// mod my_type_module {
|
||||
/// use ::serde::{Deserialize, Serialize};
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
///
|
||||
/// /// The number of variants in this enum.
|
||||
/// pub const NUM_VARIANTS: usize = 2;
|
||||
|
@ -1,15 +1,20 @@
|
||||
use std::hash::{Hasher, BuildHasher};
|
||||
use std::hash::{BuildHasher, Hasher};
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct GridHasher(u64);
|
||||
|
||||
// It's extremely unlikely that the spatial grid can be used to viably DOS the server given that clients only have
|
||||
// control over their player and a handful of entities in their near vicinity. For this reason, we just use an xor
|
||||
// hash, which should keep collisions relatively low since the spatial coherence of the grid is distributed fairly
|
||||
// evenly with the output of the hash function.
|
||||
// It's extremely unlikely that the spatial grid can be used to viably DOS the
|
||||
// server given that clients only have control over their player and a handful
|
||||
// of entities in their near vicinity. For this reason, we just use an xor hash,
|
||||
// which should keep collisions relatively low since the spatial coherence of
|
||||
// the grid is distributed fairly evenly with the output of the hash function.
|
||||
impl Hasher for GridHasher {
|
||||
fn finish(&self) -> u64 { self.0 }
|
||||
fn write(&mut self, _: &[u8]) { panic!("Hashing arbitrary bytes is unimplemented"); }
|
||||
|
||||
fn write(&mut self, _: &[u8]) {
|
||||
panic!("Hashing arbitrary bytes is unimplemented");
|
||||
}
|
||||
|
||||
fn write_i32(&mut self, x: i32) { self.0 = self.0.wrapping_mul(113989) ^ self.0 ^ x as u64; }
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
mod color;
|
||||
pub mod dir;
|
||||
pub mod find_dist;
|
||||
mod grid_hasher;
|
||||
mod option;
|
||||
pub mod plane;
|
||||
pub mod projection;
|
||||
/// Contains [`SpatialGrid`] which is useful for accelerating queries of nearby
|
||||
/// entities
|
||||
mod spatial_grid;
|
||||
mod grid_hasher;
|
||||
|
||||
pub const GIT_VERSION_BUILD: &str = include_str!(concat!(env!("OUT_DIR"), "/githash"));
|
||||
pub const GIT_TAG_BUILD: &str = include_str!(concat!(env!("OUT_DIR"), "/gittag"));
|
||||
@ -36,8 +36,8 @@ lazy_static::lazy_static! {
|
||||
|
||||
pub use color::*;
|
||||
pub use dir::*;
|
||||
pub use grid_hasher::GridHasher;
|
||||
pub use option::either_with;
|
||||
pub use plane::Plane;
|
||||
pub use projection::Projection;
|
||||
pub use spatial_grid::SpatialGrid;
|
||||
pub use grid_hasher::GridHasher;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use vek::*;
|
||||
use super::GridHasher;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SpatialGrid {
|
||||
|
@ -16,10 +16,10 @@ impl ViewDistances {
|
||||
///
|
||||
/// Also ensures both are at a minimum of 1 (unless the provided max is 0).
|
||||
pub fn clamp(self, max: Option<u32>) -> Self {
|
||||
let terrain = self.terrain.clamp(1,max.unwrap_or(u32::MAX));
|
||||
let terrain = self.terrain.clamp(1, max.unwrap_or(u32::MAX));
|
||||
Self {
|
||||
terrain,
|
||||
entity: self.entity.clamp(1,terrain),
|
||||
entity: self.entity.clamp(1, terrain),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,8 +98,9 @@ pub trait ReadVol: BaseVol {
|
||||
/// Get a reference to the voxel at the provided position in the volume.
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Error>;
|
||||
|
||||
/// Get a reference to the voxel at the provided position in the volume. Many volumes provide a fast path,
|
||||
/// provided the position is always in-bounds. Note that this function is still safe.
|
||||
/// Get a reference to the voxel at the provided position in the volume.
|
||||
/// Many volumes provide a fast path, provided the position is always
|
||||
/// in-bounds. Note that this function is still safe.
|
||||
fn get_unchecked(&self, pos: Vec3<i32>) -> &Self::Vox { self.get(pos).unwrap() }
|
||||
|
||||
/// NOTE: By default, this ray will simply run from `from` to `to` without
|
||||
|
@ -309,9 +309,7 @@ impl<V, S: VolSize, M> ReadVol for Chunk<V, S, M> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_unchecked(&self, pos: Vec3<i32>) -> &Self::Vox {
|
||||
self.get_unchecked(pos)
|
||||
}
|
||||
fn get_unchecked(&self, pos: Vec3<i32>) -> &Self::Vox { self.get_unchecked(pos) }
|
||||
|
||||
fn for_each_in(&self, mut aabb: Aabb<i32>, mut f: impl FnMut(Vec3<i32>, Self::Vox))
|
||||
where
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
terrain::MapSizeLg,
|
||||
util::GridHasher,
|
||||
vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol, WriteVol},
|
||||
volumes::dyna::DynaError,
|
||||
util::GridHasher,
|
||||
};
|
||||
use hashbrown::{hash_map, HashMap};
|
||||
use std::{fmt::Debug, ops::Deref, sync::Arc};
|
||||
@ -42,7 +42,8 @@ impl<V: RectRasterableVol> VolGrid2d<V> {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn par_keys(&self) -> hashbrown::hash_map::rayon::ParKeys<Vec2<i32>, Arc<V>>
|
||||
where V: Send + Sync,
|
||||
where
|
||||
V: Send + Sync,
|
||||
{
|
||||
self.chunks.par_keys()
|
||||
}
|
||||
@ -185,7 +186,8 @@ impl<V: RectRasterableVol> VolGrid2d<V> {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_key_real(&self, key: Vec2<i32>) -> Option<&V> {
|
||||
self.get_key_arc_real(key).map(|arc_chunk| arc_chunk.as_ref())
|
||||
self.get_key_arc_real(key)
|
||||
.map(|arc_chunk| arc_chunk.as_ref())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -197,20 +199,21 @@ impl<V: RectRasterableVol> VolGrid2d<V> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn contains_key_real(&self, key: Vec2<i32>) -> bool {
|
||||
self.chunks.contains_key(&key)
|
||||
}
|
||||
pub fn contains_key_real(&self, key: Vec2<i32>) -> bool { self.chunks.contains_key(&key) }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_key_arc(&self, key: Vec2<i32>) -> Option<&Arc<V>> {
|
||||
self.get_key_arc_real(key)
|
||||
.or_else(|| if !self.map_size_lg.contains_chunk(key) { Some(&self.default) } else { None })
|
||||
self.get_key_arc_real(key).or_else(|| {
|
||||
if !self.map_size_lg.contains_chunk(key) {
|
||||
Some(&self.default)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_key_arc_real(&self, key: Vec2<i32>) -> Option<&Arc<V>> {
|
||||
self.chunks.get(&key)
|
||||
}
|
||||
pub fn get_key_arc_real(&self, key: Vec2<i32>) -> Option<&Arc<V>> { self.chunks.get(&key) }
|
||||
|
||||
pub fn clear(&mut self) { self.chunks.clear(); }
|
||||
|
||||
@ -225,9 +228,7 @@ impl<V: RectRasterableVol> VolGrid2d<V> {
|
||||
pub fn pos_key(&self, pos: Vec3<i32>) -> Vec2<i32> { Self::chunk_key(pos) }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn pos_chunk(&self, pos: Vec3<i32>) -> Option<&V> {
|
||||
self.get_key(self.pos_key(pos))
|
||||
}
|
||||
pub fn pos_chunk(&self, pos: Vec3<i32>) -> Option<&V> { self.get_key(self.pos_key(pos)) }
|
||||
|
||||
pub fn iter(&self) -> ChunkIter<V> {
|
||||
ChunkIter {
|
||||
|
@ -47,9 +47,7 @@ impl Weather {
|
||||
}
|
||||
|
||||
// Get the wind velocity for this weather
|
||||
pub fn wind_vel(&self) -> Vec2<f32> {
|
||||
self.wind
|
||||
}
|
||||
pub fn wind_vel(&self) -> Vec2<f32> { self.wind }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
|
Loading…
Reference in New Issue
Block a user