Merge branch 'sam/sceptre-overhaul' into 'master'

Sceptre Rework

Closes #760

See merge request veloren/veloren!1345
This commit is contained in:
Samuel Keiffer 2020-09-30 03:05:14 +00:00
commit a2daad8c76
85 changed files with 1543 additions and 784 deletions

View File

@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Overhauled persistence layer including no longer storing serialized JSON items in the database
- Overhauled representation of blocks to permit fluid and sprite coexistence
- Overhauled sword
- Reworked healing sceptre
### Removed

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Heals your allies with the mystical Velorite aura.",
kind: Tool(
(
kind: Staff("SceptreVelorite"),
kind: Sceptre("SceptreVelorite"),
stats: (
equip_time_millis: 400,
power: 2.0,

View File

@ -3,7 +3,7 @@ ItemDef(
description: "Heals your allies with the power of nature.",
kind: Tool(
(
kind: Staff("Sceptre"),
kind: Sceptre("Sceptre"),
stats: (
equip_time_millis: 400,
power: 1.00,

View File

@ -0,0 +1,13 @@
ItemDef(
name: "Naturalist Walking Stick",
description: "Heals your allies with the power of nature.",
kind: Tool(
(
kind: Sceptre("StarterSceptre"),
stats: (
equip_time_millis: 400,
power: 0.50,
),
)
),
)

View File

@ -31,11 +31,11 @@
(0.04, "common.items.weapons.axe.steel_axe-5"),
(0.04, "common.items.weapons.axe.steel_axe-6"),
// healing staff
(0.5, "common.items.weapons.staff.staff_nature"),
(0.5, "common.items.weapons.sceptre.staff_nature"),
// staves
(1.00, "common.items.weapons.staff.bone_staff"),
(1.00, "common.items.weapons.staff.amethyst_staff"),
(0.1, "common.items.weapons.staff.sceptre_velorite_0"),
(0.1, "common.items.weapons.sceptre.sceptre_velorite_0"),
// hammers
(0.30, "common.items.weapons.hammer.cobalt_hammer-0"),
(0.30, "common.items.weapons.hammer.cobalt_hammer-1"),

View File

@ -78,7 +78,7 @@
(0.10, "common.items.weapons.axe.worn_iron_axe-3"),
(0.10, "common.items.weapons.axe.worn_iron_axe-4"),
// healing staff
(0.25, "common.items.weapons.staff.staff_nature"),
(0.25, "common.items.weapons.sceptre.staff_nature"),
// hammers
(0.15, "common.items.weapons.hammer.flimsy_hammer"),
(0.10, "common.items.weapons.hammer.wood_hammer-0"),
@ -134,7 +134,7 @@
(0.04, "common.items.weapons.axe.steel_axe-5"),
(0.04, "common.items.weapons.axe.steel_axe-6"),
// healing staff
(0.5, "common.items.weapons.staff.staff_nature"),
(0.5, "common.items.weapons.sceptre.staff_nature"),
// staves
(1.00, "common.items.weapons.staff.bone_staff"),
// hammers
@ -179,7 +179,7 @@
(0.30, "common.items.weapons.axe.cobalt_axe-0"),
(0.10, "common.items.weapons.axe.malachite_axe-0"),
// healing staff
(0.25, "common.items.weapons.staff.staff_nature"),
(0.25, "common.items.weapons.sceptre.staff_nature"),
// staves
(1.00, "common.items.weapons.staff.amethyst_staff"),
// hammers

View File

@ -18,7 +18,7 @@
(0.10, "common.items.weapons.axe.worn_iron_axe-2"),
(0.10, "common.items.weapons.axe.worn_iron_axe-3"),
(0.10, "common.items.weapons.axe.worn_iron_axe-4"),
(0.25, "common.items.weapons.staff.staff_nature"),
(0.25, "common.items.weapons.sceptre.staff_nature"),
(0.15, "common.items.weapons.hammer.flimsy_hammer"),
(0.10, "common.items.weapons.hammer.wood_hammer-0"),
(0.25, "common.items.weapons.bow.wood_shortbow-0"),

View File

@ -21,7 +21,7 @@
(0.10, "common.items.weapons.axe.worn_iron_axe-3"),
(0.10, "common.items.weapons.axe.worn_iron_axe-4"),
// healing staff
(0.25, "common.items.weapons.staff.staff_nature"),
(0.25, "common.items.weapons.sceptre.staff_nature"),
// staves
(1.00, "common.items.weapons.staff.starter_staff"),
// hammers

View File

@ -39,7 +39,7 @@
(0.04, "common.items.weapons.axe.steel_axe-5"),
(0.04, "common.items.weapons.axe.steel_axe-6"),
// healing staff
(0.5, "common.items.weapons.staff.staff_nature"),
(0.5, "common.items.weapons.sceptre.staff_nature"),
// staves
(1.00, "common.items.weapons.staff.bone_staff"),
// hammers

View File

@ -20,7 +20,7 @@
"apples_stick": (("common.items.food.apple_stick", 1),[("common.items.crafting_ing.twigs", 2), ("common.items.food.apple", 2)]),
"mushroom_stick": (("common.items.food.mushroom_stick", 1),[("common.items.crafting_ing.twigs", 2), ("common.items.food.mushroom", 3)]),
// Weapons
"velorite_sceptre": (("common.items.weapons.staff.sceptre_velorite_0", 1),[("common.items.crafting_ing.twigs", 20), ("common.items.ore.veloritefrag", 10), ("common.items.crafting_ing.shiny_gem", 4), ("common.items.crafting_tools.craftsman_hammer", 0)]),
"velorite_sceptre": (("common.items.weapons.sceptre.sceptre_velorite_0", 1),[("common.items.crafting_ing.twigs", 20), ("common.items.ore.veloritefrag", 10), ("common.items.crafting_ing.shiny_gem", 4), ("common.items.crafting_tools.craftsman_hammer", 0)]),
// Enhanced starting weapons
"better bow": (("common.items.weapons.bow.wood_shortbow-0", 1), [("common.items.crafting_ing.leather_scraps", 8),("common.items.crafting_ing.twigs", 6), ("common.items.crafting_ing.stones", 0)]),
"better sword": (("common.items.weapons.sword.wood_sword", 1), [("common.items.crafting_ing.leather_scraps", 4),("common.items.crafting_ing.twigs", 10), ("common.items.ore.veloritefrag", 1), ("common.items.crafting_ing.stones", 0)]),

BIN
assets/voxygen/element/icons/heal_bomb.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -182,6 +182,7 @@ https://account.veloren.net."#,
"hud.chat.pvp_melee_kill_msg": "[{attacker}] defeated [{victim}]",
"hud.chat.pvp_ranged_kill_msg": "[{attacker}] shot [{victim}]",
"hud.chat.pvp_explosion_kill_msg": "[{attacker}] blew up [{victim}]",
"hud.chat.pvp_energy_kill_msg": "[{attacker}] used magic to kill [{victim}]",
"hud.chat.npc_melee_kill_msg": "{attacker} killed [{victim}]",
"hud.chat.npc_ranged_kill_msg": "{attacker} shot [{victim}]",

View File

@ -506,12 +506,16 @@
(1.0, 0.0, 0.0), (-310., 90.0, 0.0), 1.2,
),
// Healing staff
Tool(Staff("Sceptre")): VoxTrans(
"voxel.weapon.staff.wood-nature",
Tool(Sceptre("Sceptre")): VoxTrans(
"voxel.weapon.sceptre.wood-nature",
(1.0, -1.0, 0.0), (-310., 90.0, 0.0), 1.2,
),
Tool(Staff("SceptreVelorite")): VoxTrans(
"voxel.weapon.staff.ore-nature",
Tool(Sceptre("StarterSceptre")): VoxTrans(
"voxel.weapon.sceptre.wood-simple",
(0.0, -0.0, 0.0), (-310., 90.0, 0.0), 1.25,
),
Tool(Sceptre("SceptreVelorite")): VoxTrans(
"voxel.weapon.sceptre.ore-nature",
(1.0, -1.0, 0.0), (-310., 90.0, 0.0), 1.15,
),
// Shields

View File

@ -23,6 +23,7 @@ in vec3 inst_pos;
in float inst_time;
in float inst_lifespan;
in float inst_entropy;
in vec3 inst_dir;
in int inst_mode;
out vec3 f_pos;
@ -48,6 +49,8 @@ const int LEAF = 9;
const int FIREFLY = 10;
const int BEE = 11;
const int GROUND_SHOCKWAVE = 12;
const int HEALING_BEAM = 13;
const int ENERGY_NATURE = 14;
// meters per second squared (acceleration)
const float earth_gravity = 9.807;
@ -103,6 +106,24 @@ mat4 identity() {
);
}
vec3 perp_axis1(vec3 axis) {
return normalize(vec3(axis.y + axis.z, -axis.x + axis.z, -axis.x - axis.y));
}
vec3 perp_axis2(vec3 axis1, vec3 axis2) {
return normalize(vec3(axis1.y * axis2.z - axis1.z * axis2.y, axis1.z * axis2.x - axis1.x * axis2.z, axis1.x * axis2.y - axis1.y * axis2.x));
}
vec3 spiral_motion(vec3 line, float radius, float time_function) {
vec3 axis2 = perp_axis1(line);
vec3 axis3 = perp_axis2(line, axis2);
return line * time_function + vec3(
radius * cos(10 * time_function - inst_time) * axis2.x + radius * sin(10 * time_function - inst_time) * axis3.x,
radius * cos(10 * time_function - inst_time) * axis2.y + radius * sin(10 * time_function - inst_time) * axis3.y,
radius * cos(10 * time_function - inst_time) * axis2.z + radius * sin(10 * time_function - inst_time) * axis3.z);
}
void main() {
float rand0 = hash(vec4(inst_entropy + 0));
float rand1 = hash(vec4(inst_entropy + 1));
@ -248,6 +269,23 @@ void main() {
vec4(vec3(0.32 + (rand0 * 0.04), 0.22 + (rand1 * 0.03), 0.05 + (rand2 * 0.01)), 1),
spin_in_axis(vec3(1,0,0),0)
);
} else if (inst_mode == HEALING_BEAM) {
attr = Attr(
spiral_motion(inst_dir, 0.3 * (floor(2 * rand0 + 0.5) - 0.5) * min(linear_scale(10), 1), lifetime / inst_lifespan),
vec3((1.7 - 0.7 * abs(floor(2 * rand0 - 0.5) + 0.5)) * (1.5 + 0.5 * sin(tick.x * 10 - lifetime * 4))),
vec4(vec3(0.3, 0.7 + 0.4 * sin(tick.x * 8 - lifetime * 3), 0.3 + 0.1 * sin (tick.x * 2)), 0.3),
spin_in_axis(inst_dir, tick.z)
);
} else if (inst_mode == ENERGY_NATURE) {
attr = Attr(
linear_motion(
vec3(rand0 * 1, rand1 * 1, rand2 * 1),
vec3(rand3 * 2, rand4 * 2, rand5 * 2)
),
vec3(0.8),
vec4(vec3(0, 1, 0), 1),
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3)
);
} else {
attr = Attr(
linear_motion(

View File

@ -547,12 +547,16 @@
color: None
),
// Healing staff
Staff("Sceptre"): (
vox_spec: ("weapon.staff.wood-nature", (-1.0, -6.0, -5.0)),
Sceptre("StarterSceptre"): (
vox_spec: ("weapon.sceptre.wood-simple", (-1.0, -6.0, -6.0)),
color: None
),
Staff("SceptreVelorite"): (
vox_spec: ("weapon.staff.ore-nature", (-2.0, -6.0, -5.0)),
Sceptre("Sceptre"): (
vox_spec: ("weapon.sceptre.wood-nature", (-1.0, -6.0, -5.0)),
color: None
),
Sceptre("SceptreVelorite"): (
vox_spec: ("weapon.sceptre.ore-nature", (-2.0, -6.0, -5.0)),
color: None
),
// Misc

BIN
assets/voxygen/voxel/weapon/sceptre/wood-simple.vox (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1673,6 +1673,11 @@ impl Client {
alias_of_uid(attacker_uid),
alias_of_uid(victim)
),
KillSource::Player(attacker_uid, KillType::Energy) => format!(
"[{}] used magic to kill [{}]",
alias_of_uid(attacker_uid),
alias_of_uid(victim)
),
KillSource::NonPlayer(attacker_name, KillType::Melee) => {
format!("{} killed [{}]", attacker_name, alias_of_uid(victim))
},
@ -1682,6 +1687,11 @@ impl Client {
KillSource::NonPlayer(attacker_name, KillType::Explosion) => {
format!("{} blew up [{}]", attacker_name, alias_of_uid(victim))
},
KillSource::NonPlayer(attacker_name, KillType::Energy) => format!(
"{} used magic to kill [{}]",
attacker_name,
alias_of_uid(victim)
),
KillSource::Environment(environment) => {
format!("[{}] died in {}", alias_of_uid(victim), environment)
},
@ -1704,6 +1714,9 @@ impl Client {
KillSource::Player(attacker_uid, KillType::Explosion) => message
.replace("{attacker}", &alias_of_uid(attacker_uid))
.replace("{victim}", &alias_of_uid(victim)),
KillSource::Player(attacker_uid, KillType::Energy) => message
.replace("{attacker}", &alias_of_uid(attacker_uid))
.replace("{victim}", &alias_of_uid(victim)),
KillSource::NonPlayer(attacker_name, KillType::Melee) => message
.replace("{attacker}", attacker_name)
.replace("{victim}", &alias_of_uid(victim)),
@ -1713,6 +1726,9 @@ impl Client {
KillSource::NonPlayer(attacker_name, KillType::Explosion) => message
.replace("{attacker}", attacker_name)
.replace("{victim}", &alias_of_uid(victim)),
KillSource::NonPlayer(attacker_name, KillType::Energy) => message
.replace("{attacker}", attacker_name)
.replace("{victim}", &alias_of_uid(victim)),
KillSource::Environment(environment) => message
.replace("{name}", &alias_of_uid(victim))
.replace("{environment}", environment),

View File

@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
use specs::{Component, FlaggedStorage};
use specs_idvs::IdvStorage;
use std::time::Duration;
use vek::Vec3;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub enum CharacterAbilityType {
@ -24,6 +25,7 @@ pub enum CharacterAbilityType {
LeapMelee,
SpinMelee,
GroundShockwave,
BasicBeam,
}
impl From<&CharacterState> for CharacterAbilityType {
@ -39,6 +41,7 @@ impl From<&CharacterState> for CharacterAbilityType {
CharacterState::SpinMelee(_) => Self::SpinMelee,
CharacterState::ChargedRanged(_) => Self::ChargedRanged,
CharacterState::GroundShockwave(_) => Self::ChargedRanged,
CharacterState::BasicBeam(_) => Self::BasicBeam,
_ => Self::BasicMelee,
}
}
@ -146,6 +149,20 @@ pub enum CharacterAbility {
shockwave_duration: Duration,
requires_ground: bool,
},
BasicBeam {
energy_cost: u32,
buildup_duration: Duration,
recover_duration: Duration,
beam_duration: Duration,
base_hps: u32,
base_dps: u32,
tick_rate: f32,
range: f32,
max_angle: f32,
lifesteal_eff: f32,
energy_regen: u32,
energy_drain: u32,
},
}
impl CharacterAbility {
@ -190,6 +207,10 @@ impl CharacterAbility {
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
CharacterAbility::BasicBeam { energy_cost, .. } => update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(),
_ => true,
}
}
@ -497,6 +518,38 @@ impl From<&CharacterAbility> for CharacterState {
shockwave_duration: *shockwave_duration,
requires_ground: *requires_ground,
}),
CharacterAbility::BasicBeam {
energy_cost: _,
buildup_duration,
recover_duration,
beam_duration,
base_hps,
base_dps,
tick_rate,
range,
max_angle,
lifesteal_eff,
energy_regen,
energy_drain,
} => CharacterState::BasicBeam(basic_beam::Data {
static_data: basic_beam::StaticData {
buildup_duration: *buildup_duration,
recover_duration: *recover_duration,
beam_duration: *beam_duration,
base_hps: *base_hps,
base_dps: *base_dps,
tick_rate: *tick_rate,
range: *range,
max_angle: *max_angle,
lifesteal_eff: *lifesteal_eff,
energy_regen: *energy_regen,
energy_drain: *energy_drain,
},
timer: Duration::default(),
stage_section: StageSection::Buildup,
particle_ori: None::<Vec3<f32>>,
offset: 0.0,
}),
}
}
}

49
common/src/comp/beam.rs Normal file
View File

@ -0,0 +1,49 @@
use crate::sync::Uid;
use serde::{Deserialize, Serialize};
use specs::{Component, FlaggedStorage};
use specs_idvs::IdvStorage;
use std::time::Duration;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Properties {
pub angle: f32,
pub speed: f32,
pub damage: u32,
pub heal: u32,
pub lifesteal_eff: f32,
pub energy_regen: u32,
pub energy_drain: u32,
pub duration: Duration,
pub owner: Option<Uid>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct BeamSegment {
pub properties: Properties,
#[serde(skip)]
/// Time that the beam segment was created at
/// Used to calculate beam propagation
/// Deserialized from the network as `None`
pub creation: Option<f64>,
}
impl Component for BeamSegment {
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
}
impl std::ops::Deref for BeamSegment {
type Target = Properties;
fn deref(&self) -> &Properties { &self.properties }
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Beam {
pub hit_entities: Vec<Uid>,
pub tick_dur: Duration,
pub timer: Duration,
}
impl Component for Beam {
type Storage = IdvStorage<Self>;
}

View File

@ -67,6 +67,7 @@ make_case_elim!(
FireworkRed = 57,
FireworkYellow = 58,
MultiArrow = 59,
BoltNature = 60,
}
);
@ -77,7 +78,7 @@ impl Body {
}
}
pub const ALL_OBJECTS: [Body; 60] = [
pub const ALL_OBJECTS: [Body; 61] = [
Body::Arrow,
Body::Bomb,
Body::Scarecrow,
@ -138,6 +139,7 @@ pub const ALL_OBJECTS: [Body; 60] = [
Body::FireworkRed,
Body::FireworkYellow,
Body::MultiArrow,
Body::BoltNature,
];
impl From<Body> for super::Body {
@ -207,6 +209,7 @@ impl Body {
Body::FireworkRed => "firework_red",
Body::FireworkYellow => "firework_yellow",
Body::MultiArrow => "multi_arrow",
Body::BoltNature => "bolt_nature",
}
}
}

View File

@ -71,6 +71,9 @@ pub enum CharacterState {
ChargedRanged(charged_ranged::Data),
/// A ground shockwave attack
GroundShockwave(ground_shockwave::Data),
/// A continuous attack that affects all creatures in a cone originating
/// from the source
BasicBeam(basic_beam::Data),
}
impl CharacterState {
@ -86,6 +89,7 @@ impl CharacterState {
| CharacterState::SpinMelee(_)
| CharacterState::ChargedRanged(_)
| CharacterState::GroundShockwave(_)
| CharacterState::BasicBeam(_)
)
}
@ -99,6 +103,7 @@ impl CharacterState {
| CharacterState::SpinMelee(_)
| CharacterState::ChargedRanged(_)
| CharacterState::GroundShockwave(_)
| CharacterState::BasicBeam(_)
)
}
@ -112,6 +117,7 @@ impl CharacterState {
| CharacterState::LeapMelee(_)
| CharacterState::ChargedRanged(_)
| CharacterState::GroundShockwave(_)
| CharacterState::BasicBeam(_)
)
}
@ -136,7 +142,8 @@ impl Component for CharacterState {
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Attacking {
pub base_healthchange: i32,
pub base_damage: u32,
pub base_heal: u32,
pub range: f32,
pub max_angle: f32,
pub applied: bool,

View File

@ -50,6 +50,7 @@ pub enum KillType {
Melee,
Projectile,
Explosion,
Energy,
// Projectile(String), TODO: add projectile name when available
}

View File

@ -16,6 +16,7 @@ pub enum DamageSource {
Explosion,
Falling,
Shockwave,
Energy,
}
impl Damage {
@ -39,11 +40,6 @@ impl Damage {
if (damage_reduction - 1.0).abs() > f32::EPSILON {
self.healthchange += critdamage;
}
// Min damage
if (damage_reduction - 1.0).abs() > f32::EPSILON && self.healthchange > -10.0 {
self.healthchange = -10.0;
}
},
DamageSource::Projectile => {
// Critical hit
@ -57,11 +53,6 @@ impl Damage {
// Armor
let damage_reduction = loadout.get_damage_reduction();
self.healthchange *= 1.0 - damage_reduction;
// Min damage
if (damage_reduction - 1.0).abs() > f32::EPSILON && self.healthchange > -10.0 {
self.healthchange = -10.0;
}
},
DamageSource::Explosion => {
// Block
@ -71,21 +62,16 @@ impl Damage {
// Armor
let damage_reduction = loadout.get_damage_reduction();
self.healthchange *= 1.0 - damage_reduction;
// Min damage
if (damage_reduction - 1.0).abs() > f32::EPSILON && self.healthchange > -10.0 {
self.healthchange = -10.0;
}
},
DamageSource::Shockwave => {
// Armor
let damage_reduction = loadout.get_damage_reduction();
self.healthchange *= 1.0 - damage_reduction;
// Min damage
if (damage_reduction - 1.0).abs() > f32::EPSILON && self.healthchange > -10.0 {
self.healthchange = -10.0;
}
},
DamageSource::Energy => {
// Armor
let damage_reduction = loadout.get_damage_reduction();
self.healthchange *= 1.0 - damage_reduction;
},
_ => {},
}

View File

@ -16,6 +16,7 @@ pub enum ToolKind {
Bow(String),
Dagger(String),
Staff(String),
Sceptre(String),
Shield(String),
NpcWeapon(String),
Debug(String),
@ -33,6 +34,7 @@ impl ToolKind {
ToolKind::Bow(_) => Hands::TwoHand,
ToolKind::Dagger(_) => Hands::OneHand,
ToolKind::Staff(_) => Hands::TwoHand,
ToolKind::Sceptre(_) => Hands::TwoHand,
ToolKind::Shield(_) => Hands::OneHand,
ToolKind::NpcWeapon(_) => Hands::TwoHand,
ToolKind::Debug(_) => Hands::TwoHand,
@ -55,6 +57,7 @@ pub enum ToolCategory {
Bow,
Dagger,
Staff,
Sceptre,
Shield,
NpcWeapon,
Debug,
@ -71,6 +74,7 @@ impl From<&ToolKind> for ToolCategory {
ToolKind::Bow(_) => ToolCategory::Bow,
ToolKind::Dagger(_) => ToolCategory::Dagger,
ToolKind::Staff(_) => ToolCategory::Staff,
ToolKind::Sceptre(_) => ToolCategory::Sceptre,
ToolKind::Shield(_) => ToolCategory::Shield,
ToolKind::NpcWeapon(_) => ToolCategory::NpcWeapon,
ToolKind::Debug(_) => ToolCategory::Debug,
@ -299,119 +303,121 @@ impl Tool {
range: 3.5,
max_angle: 20.0,
}],
Staff(kind) => {
if kind == "Sceptre" {
vec![
BasicMelee {
energy_cost: 0,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(300),
base_healthchange: (-10.0 * self.base_power()) as i32,
knockback: 0.0,
range: 5.0,
max_angle: 20.0,
},
BasicMelee {
energy_cost: 350,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(1000),
base_healthchange: (150.0 * self.base_power()) as i32,
knockback: 0.0,
range: 100.0,
max_angle: 90.0,
},
]
} else if kind == "SceptreVelorite" {
vec![
BasicMelee {
energy_cost: 0,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(300),
base_healthchange: (-10.0 * self.base_power()) as i32,
knockback: 0.0,
range: 5.0,
max_angle: 20.0,
},
BasicMelee {
energy_cost: 350,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(1000),
base_healthchange: (350.0 * self.base_power()) as i32,
knockback: 0.0,
range: 100.0,
max_angle: 90.0,
},
]
} else {
vec![
BasicMelee {
energy_cost: 0,
buildup_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(300),
base_healthchange: (-40.0 * self.base_power()) as i32,
knockback: 0.0,
range: 3.5,
max_angle: 20.0,
},
BasicRanged {
energy_cost: 0,
holdable: false,
prepare_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(600),
projectile: Projectile {
hit_solid: vec![projectile::Effect::Vanish],
hit_entity: vec![
projectile::Effect::Damage((-40.0 * self.base_power()) as i32),
projectile::Effect::RewardEnergy(150),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
ignore_group: true,
Sceptre(_) => vec![
BasicBeam {
energy_cost: 0,
buildup_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(250),
beam_duration: Duration::from_secs(1),
base_hps: (60.0 * self.base_power()) as u32,
base_dps: (40.0 * self.base_power()) as u32,
tick_rate: 2.0,
range: 25.0,
max_angle: 1.0,
lifesteal_eff: 0.25,
energy_regen: 50,
energy_drain: 100,
},
BasicRanged {
energy_cost: 800,
holdable: true,
prepare_duration: Duration::from_millis(800),
recover_duration: Duration::from_millis(50),
projectile: Projectile {
hit_solid: vec![
projectile::Effect::Explode {
power: 1.4 * self.base_power(),
percent_damage: 0.2,
},
projectile_body: Body::Object(object::Body::BoltFire),
projectile_light: Some(LightEmitter {
col: (0.85, 0.5, 0.11).into(),
..Default::default()
}),
projectile_gravity: None,
projectile_speed: 100.0,
},
BasicRanged {
energy_cost: 400,
holdable: true,
prepare_duration: Duration::from_millis(800),
recover_duration: Duration::from_millis(50),
projectile: Projectile {
hit_solid: vec![
projectile::Effect::Explode {
power: 1.4 * self.base_power(),
},
projectile::Effect::Vanish,
],
hit_entity: vec![
projectile::Effect::Explode {
power: 1.4 * self.base_power(),
},
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
ignore_group: true,
projectile::Effect::Vanish,
],
hit_entity: vec![
projectile::Effect::Explode {
power: 1.4 * self.base_power(),
percent_damage: 0.2,
},
projectile_body: Body::Object(object::Body::BoltFireBig),
projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),
projectile_gravity: None,
projectile_speed: 100.0,
},
]
}
},
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
ignore_group: true,
},
projectile_body: Body::Object(object::Body::BoltNature),
projectile_light: Some(LightEmitter {
col: (0.0, 1.0, 0.0).into(),
..Default::default()
}),
projectile_gravity: Some(Gravity(0.5)),
projectile_speed: 40.0,
},
],
Staff(_) => vec![
BasicMelee {
energy_cost: 0,
buildup_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(300),
base_healthchange: (-40.0 * self.base_power()) as i32,
knockback: 0.0,
range: 3.5,
max_angle: 20.0,
},
BasicRanged {
energy_cost: 0,
holdable: false,
prepare_duration: Duration::from_millis(250),
recover_duration: Duration::from_millis(600),
projectile: Projectile {
hit_solid: vec![projectile::Effect::Vanish],
hit_entity: vec![
projectile::Effect::Damage((-40.0 * self.base_power()) as i32),
projectile::Effect::RewardEnergy(150),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
ignore_group: true,
},
projectile_body: Body::Object(object::Body::BoltFire),
projectile_light: Some(LightEmitter {
col: (0.85, 0.5, 0.11).into(),
..Default::default()
}),
projectile_gravity: None,
projectile_speed: 100.0,
},
BasicRanged {
energy_cost: 400,
holdable: true,
prepare_duration: Duration::from_millis(800),
recover_duration: Duration::from_millis(50),
projectile: Projectile {
hit_solid: vec![
projectile::Effect::Explode {
power: 1.4 * self.base_power(),
percent_damage: 1.0,
},
projectile::Effect::Vanish,
],
hit_entity: vec![
projectile::Effect::Explode {
power: 1.4 * self.base_power(),
percent_damage: 1.0,
},
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
ignore_group: true,
},
projectile_body: Body::Object(object::Body::BoltFireBig),
projectile_light: Some(LightEmitter {
col: (1.0, 0.75, 0.11).into(),
..Default::default()
}),
projectile_gravity: None,
projectile_speed: 100.0,
},
],
Shield(_) => vec![
BasicMelee {
energy_cost: 0,

View File

@ -1,6 +1,7 @@
mod ability;
mod admin;
pub mod agent;
pub mod beam;
mod body;
mod character_state;
pub mod chat;
@ -25,6 +26,7 @@ pub mod visual;
pub use ability::{CharacterAbility, CharacterAbilityType, ItemConfig, Loadout};
pub use admin::{Admin, AdminList};
pub use agent::{Agent, Alignment};
pub use beam::{Beam, BeamSegment};
pub use body::{
biped_large, bird_medium, bird_small, dragon, fish_medium, fish_small, golem, humanoid, object,
quadruped_low, quadruped_medium, quadruped_small, theropod, AllBodies, Body, BodyData,

View File

@ -9,7 +9,7 @@ pub enum Effect {
Damage(i32),
Knockback(f32),
RewardEnergy(u32),
Explode { power: f32 },
Explode { power: f32, percent_damage: f32 },
Vanish,
Stick,
Possess,

View File

@ -19,6 +19,7 @@ pub enum HealthSource {
Attack { by: Uid }, // TODO: Implement weapon
Projectile { owner: Option<Uid> },
Explosion { owner: Option<Uid> },
Energy { owner: Option<Uid> },
Suicide,
World,
Revive,

View File

@ -33,6 +33,7 @@ pub enum ServerEvent {
owner: Option<Uid>,
friendly_damage: bool,
reagent: Option<Reagent>,
percent_damage: f32,
},
Damage {
uid: Uid,
@ -63,6 +64,11 @@ pub enum ServerEvent {
entity: EcsEntity,
impulse: Vec3<f32>,
},
BeamSegment {
properties: comp::beam::Properties,
pos: Pos,
ori: Ori,
},
LandOnGround {
entity: EcsEntity,
vel: Vec3<f32>,

View File

@ -30,6 +30,7 @@ sum_type! {
Vel(comp::Vel),
Ori(comp::Ori),
Shockwave(comp::Shockwave),
BeamSegment(comp::BeamSegment),
}
}
// Automatically derive From<T> for EcsCompPhantom
@ -58,6 +59,7 @@ sum_type! {
Vel(PhantomData<comp::Vel>),
Ori(PhantomData<comp::Ori>),
Shockwave(PhantomData<comp::Shockwave>),
BeamSegment(PhantomData<comp::BeamSegment>),
}
}
impl sync::CompPacket for EcsCompPacket {
@ -86,6 +88,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::Vel(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Ori(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Shockwave(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::BeamSegment(comp) => sync::handle_insert(comp, entity, world),
}
}
@ -112,6 +115,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::Vel(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Ori(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Shockwave(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::BeamSegment(comp) => sync::handle_modify(comp, entity, world),
}
}
@ -142,6 +146,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPhantom::Vel(_) => sync::handle_remove::<comp::Vel>(entity, world),
EcsCompPhantom::Ori(_) => sync::handle_remove::<comp::Ori>(entity, world),
EcsCompPhantom::Shockwave(_) => sync::handle_remove::<comp::Shockwave>(entity, world),
EcsCompPhantom::BeamSegment(_) => sync::handle_remove::<comp::Ori>(entity, world),
}
}
}

View File

@ -14,6 +14,7 @@ pub enum Outcome {
pos: Vec3<f32>,
power: f32,
reagent: Option<Reagent>, // How can we better define this?
percent_damage: f32,
},
ProjectileShot {
pos: Vec3<f32>,

View File

@ -127,6 +127,7 @@ impl State {
ecs.register::<comp::Object>();
ecs.register::<comp::Group>();
ecs.register::<comp::Shockwave>();
ecs.register::<comp::BeamSegment>();
// Register components send from clients -> server
ecs.register::<comp::Controller>();
@ -163,6 +164,7 @@ impl State {
ecs.register::<comp::Faction>();
ecs.register::<comp::group::Invite>();
ecs.register::<comp::group::PendingInvites>();
ecs.register::<comp::Beam>();
// Register synced resources used by the ECS.
ecs.insert(TimeOfDay(0.0));

View File

@ -0,0 +1,179 @@
use crate::{
comp::{beam, humanoid, Body, CharacterState, Ori, Pos, StateUpdate},
event::ServerEvent,
states::utils::{StageSection, *},
sync::Uid,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use vek::Vec3;
/// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
/// How long until state should deal damage or heal
pub buildup_duration: Duration,
/// How long the state has until exiting
pub recover_duration: Duration,
/// How long each beam segment persists for
pub beam_duration: Duration,
/// Base healing per second
pub base_hps: u32,
/// Base damage per second
pub base_dps: u32,
/// Ticks of damage/healing per second
pub tick_rate: f32,
/// Max range
pub range: f32,
/// Max angle (45.0 will give you a 90.0 angle window)
pub max_angle: f32,
/// Lifesteal efficiency (0 gives 0% conversion of damage to health, 1 gives
/// 100% conversion of damage to health)
pub lifesteal_eff: f32,
/// Energy regened per second for damage ticks
pub energy_regen: u32,
/// Energy consumed per second for heal ticks
pub energy_drain: u32,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data {
/// Struct containing data that does not change over the course of the
/// character state
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
/// What section the character stage is in
pub stage_section: StageSection,
/// Used for particle stuffs
pub particle_ori: Option<Vec3<f32>>,
/// Used to offset beam and particles
pub offset: f32,
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_move(data, &mut update, 0.4);
handle_jump(data, &mut update);
if unwrap_tool_data(data).is_none() {
update.character = CharacterState::Idle;
return update;
}
match self.stage_section {
StageSection::Buildup => {
if self.timer < self.static_data.buildup_duration {
// Build up
update.character = CharacterState::BasicBeam(Data {
static_data: self.static_data,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
particle_ori: Some(*data.inputs.look_dir),
offset: self.offset,
});
} else {
// Creates beam
data.updater.insert(data.entity, beam::Beam {
hit_entities: Vec::<Uid>::new(),
tick_dur: Duration::from_secs_f32(1.0 / self.static_data.tick_rate),
timer: Duration::default(),
});
// Gets offset
let eye_height = match data.body {
Body::Humanoid(body) => body.eye_height(),
_ => humanoid::DEFAULT_HUMANOID_EYE_HEIGHT,
};
// Build up
update.character = CharacterState::BasicBeam(Data {
static_data: self.static_data,
timer: Duration::default(),
stage_section: StageSection::Cast,
particle_ori: Some(*data.inputs.look_dir),
offset: eye_height * 0.9,
});
}
},
StageSection::Cast => {
if data.inputs.primary.is_pressed() {
let damage =
(self.static_data.base_dps as f32 / self.static_data.tick_rate) as u32;
let heal =
(self.static_data.base_hps as f32 / self.static_data.tick_rate) as u32;
let energy_regen =
(self.static_data.energy_regen as f32 / self.static_data.tick_rate) as u32;
let energy_drain =
(self.static_data.energy_drain as f32 / self.static_data.tick_rate) as u32;
let speed =
self.static_data.range / self.static_data.beam_duration.as_secs_f32();
let properties = beam::Properties {
angle: self.static_data.max_angle.to_radians(),
speed,
damage,
heal,
lifesteal_eff: self.static_data.lifesteal_eff,
energy_regen,
energy_drain,
duration: self.static_data.beam_duration,
owner: Some(*data.uid),
};
let pos = Pos(data.pos.0 + Vec3::new(0.0, 0.0, self.offset));
// Create beam segment
update.server_events.push_front(ServerEvent::BeamSegment {
properties,
pos,
ori: Ori(data.inputs.look_dir),
});
update.character = CharacterState::BasicBeam(Data {
static_data: self.static_data,
timer: self.timer,
stage_section: self.stage_section,
particle_ori: Some(*data.inputs.look_dir),
offset: self.offset,
});
} else {
update.character = CharacterState::BasicBeam(Data {
static_data: self.static_data,
timer: Duration::default(),
stage_section: StageSection::Recover,
particle_ori: Some(*data.inputs.look_dir),
offset: self.offset,
});
}
},
StageSection::Recover => {
if self.timer < self.static_data.recover_duration {
update.character = CharacterState::BasicBeam(Data {
static_data: self.static_data,
timer: self
.timer
.checked_add(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(),
stage_section: self.stage_section,
particle_ori: Some(*data.inputs.look_dir),
offset: self.offset,
});
} else {
// Done
update.character = CharacterState::Wielding;
// Make sure attack component is removed
data.updater.remove::<beam::Beam>(data.entity);
}
},
_ => {
// If it somehow ends up in an incorrect stage section
update.character = CharacterState::Wielding;
// Make sure attack component is removed
data.updater.remove::<beam::Beam>(data.entity);
},
}
update
}
}

View File

@ -1,7 +1,7 @@
use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::*,
sys::character_behavior::*,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
@ -46,9 +46,15 @@ impl CharacterBehavior for Data {
exhausted: false,
});
} else if !self.exhausted {
let (damage, heal) = if self.base_healthchange > 0 {
(0, self.base_healthchange as u32)
} else {
((-self.base_healthchange) as u32, 0)
};
// Hit attempt
data.updater.insert(data.entity, Attacking {
base_healthchange: self.base_healthchange,
base_damage: damage,
base_heal: heal,
range: self.range,
max_angle: self.max_angle.to_radians(),
applied: false,

View File

@ -2,7 +2,7 @@ use crate::{
comp::{Body, CharacterState, Gravity, LightEmitter, Projectile, StateUpdate},
event::ServerEvent,
states::utils::*,
sys::character_behavior::*,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;

View File

@ -1,7 +1,7 @@
use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::*,
sys::character_behavior::*,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;

View File

@ -5,7 +5,7 @@ use crate::{
},
event::ServerEvent,
states::utils::*,
sys::character_behavior::*,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;

View File

@ -126,13 +126,12 @@ impl CharacterBehavior for Data {
// Hit attempt
data.updater.insert(data.entity, Attacking {
base_healthchange: -((self.static_data.stage_data[stage_index]
.max_damage
.min(
self.static_data.stage_data[stage_index].base_damage
+ self.combo / self.static_data.num_stages
* self.static_data.stage_data[stage_index].damage_increase,
)) as i32),
base_damage: self.static_data.stage_data[stage_index].max_damage.min(
self.static_data.stage_data[stage_index].base_damage
+ self.combo / self.static_data.num_stages
* self.static_data.stage_data[stage_index].damage_increase,
),
base_heal: 0,
range: self.static_data.stage_data[stage_index].range,
max_angle: self.static_data.stage_data[stage_index].angle.to_radians(),
applied: false,

View File

@ -1,7 +1,7 @@
use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::{StageSection, *},
sys::character_behavior::*,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
@ -121,7 +121,8 @@ impl CharacterBehavior for Data {
* charge_frac
+ self.static_data.base_knockback;
data.updater.insert(data.entity, Attacking {
base_healthchange: -damage as i32,
base_damage: damage as u32,
base_heal: 0,
range: self.static_data.range,
max_angle: self.static_data.angle.to_radians(),
applied: false,
@ -251,6 +252,12 @@ impl CharacterBehavior for Data {
data.updater.remove::<Attacking>(data.entity);
}
},
_ => {
// If it somehow ends up in an incorrect stage section
update.character = CharacterState::Wielding;
// Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity);
},
}
update

View File

@ -2,7 +2,7 @@ use crate::{
comp::{shockwave, Attacking, CharacterState, StateUpdate},
event::ServerEvent,
states::utils::*,
sys::character_behavior::*,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;

View File

@ -1,7 +1,7 @@
use crate::{
comp::{Attacking, CharacterState, StateUpdate},
states::utils::*,
sys::character_behavior::*,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
@ -73,7 +73,8 @@ impl CharacterBehavior for Data {
} else if !self.exhausted {
// Hit attempt
data.updater.insert(data.entity, Attacking {
base_healthchange: -(self.base_damage as i32),
base_damage: self.base_damage,
base_heal: 0,
range: 4.5,
max_angle: 360_f32.to_radians(),
applied: false,

View File

@ -1,3 +1,4 @@
pub mod basic_beam;
pub mod basic_block;
pub mod basic_melee;
pub mod basic_ranged;

View File

@ -1,7 +1,7 @@
use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::utils::{StageSection, *},
sys::character_behavior::*,
sys::character_behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
@ -106,7 +106,8 @@ impl CharacterBehavior for Data {
});
// Hit attempt
data.updater.insert(data.entity, Attacking {
base_healthchange: -(self.static_data.base_damage as i32),
base_damage: self.static_data.base_damage,
base_heal: 0,
range: self.static_data.range,
max_angle: 180_f32.to_radians(),
applied: false,

View File

@ -363,4 +363,5 @@ pub enum StageSection {
Swing,
Recover,
Charge,
Cast,
}

View File

@ -498,7 +498,9 @@ impl<'a> System<'a> for Sys {
// Only if the attack was recent
if my_stats.health.last_change.0 < 3.0 {
if let comp::HealthSource::Attack { by }
| comp::HealthSource::Projectile { owner: Some(by) } =
| comp::HealthSource::Projectile { owner: Some(by) }
| comp::HealthSource::Energy { owner: Some(by) }
| comp::HealthSource::Explosion { owner: Some(by) } =
my_stats.health.last_change.1.cause
{
if !agent.activity.is_attack() {

387
common/src/sys/beam.rs Normal file
View File

@ -0,0 +1,387 @@
use crate::{
comp::{
group, Beam, BeamSegment, Body, CharacterState, Damage, DamageSource, Energy, EnergySource,
HealthChange, HealthSource, Last, Loadout, Ori, Pos, Scale, Stats,
},
event::{EventBus, ServerEvent},
state::{DeltaTime, Time},
sync::{Uid, UidAllocator},
};
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
use std::time::Duration;
use vek::*;
pub const BLOCK_ANGLE: f32 = 180.0;
/// This system is responsible for handling beams that heal or do damage
pub struct Sys;
impl<'a> System<'a> for Sys {
#[allow(clippy::type_complexity)]
type SystemData = (
Entities<'a>,
Read<'a, EventBus<ServerEvent>>,
Read<'a, Time>,
Read<'a, DeltaTime>,
Read<'a, UidAllocator>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Pos>,
ReadStorage<'a, Last<Pos>>,
ReadStorage<'a, Ori>,
ReadStorage<'a, Scale>,
ReadStorage<'a, Body>,
ReadStorage<'a, Stats>,
ReadStorage<'a, Loadout>,
ReadStorage<'a, group::Group>,
ReadStorage<'a, CharacterState>,
WriteStorage<'a, Energy>,
WriteStorage<'a, BeamSegment>,
WriteStorage<'a, Beam>,
);
fn run(
&mut self,
(
entities,
server_bus,
time,
dt,
uid_allocator,
uids,
positions,
last_positions,
orientations,
scales,
bodies,
stats,
loadouts,
groups,
character_states,
mut energies,
mut beam_segments,
mut beams,
): Self::SystemData,
) {
let mut server_emitter = server_bus.emitter();
let time = time.0;
let dt = dt.0;
// Beams
for (entity, uid, pos, ori, beam_segment) in
(&entities, &uids, &positions, &orientations, &beam_segments).join()
{
let creation_time = match beam_segment.creation {
Some(time) => time,
// Skip newly created beam segments
None => continue,
};
let end_time = creation_time + beam_segment.duration.as_secs_f64();
// If beam segment is out of time emit destroy event but still continue since it
// may have traveled and produced effects a bit before reaching it's
// end point
if end_time < time {
server_emitter.emit(ServerEvent::Destroy {
entity,
cause: HealthSource::World,
});
}
// Determine area that was covered by the beam in the last tick
let frame_time = dt.min((end_time - time) as f32);
if frame_time <= 0.0 {
continue;
}
// Note: min() probably uneeded
let time_since_creation = (time - creation_time) as f32;
let frame_start_dist =
(beam_segment.speed * (time_since_creation - frame_time)).max(0.0);
let frame_end_dist = (beam_segment.speed * time_since_creation).max(frame_start_dist);
let beam_owner = beam_segment
.owner
.and_then(|uid| uid_allocator.retrieve_entity_internal(uid.into()));
// Group to ignore collisions with
// Might make this more nuanced if beams are used for non damage effects
let group = beam_owner.and_then(|e| groups.get(e));
let hit_entities = if let Some(beam) = beam_owner.and_then(|e| beams.get_mut(e)) {
&mut beam.hit_entities
} else {
continue;
};
// Go through all other effectable entities
for (
b,
uid_b,
pos_b,
last_pos_b_maybe,
ori_b,
scale_b_maybe,
character_b,
stats_b,
body_b,
) in (
&entities,
&uids,
&positions,
// TODO: make sure that these are maintained on the client and remove `.maybe()`
last_positions.maybe(),
&orientations,
scales.maybe(),
character_states.maybe(),
&stats,
&bodies,
)
.join()
{
// Check to see if entity has already been hit recently
if hit_entities.iter().any(|&uid| uid == *uid_b) {
continue;
}
// Scales
let scale_b = scale_b_maybe.map_or(1.0, |s| s.0);
let rad_b = body_b.radius() * scale_b;
let height_b = body_b.height() * scale_b;
// Check if it is a hit
let hit = entity != b
&& !stats_b.is_dead
// Collision shapes
&& (sphere_wedge_cylinder_collision(pos.0, frame_start_dist, frame_end_dist, *ori.0, beam_segment.angle, pos_b.0, rad_b, height_b)
|| last_pos_b_maybe.map_or(false, |pos_maybe| {sphere_wedge_cylinder_collision(pos.0, frame_start_dist, frame_end_dist, *ori.0, beam_segment.angle, (pos_maybe.0).0, rad_b, height_b)}));
if hit {
// See if entities are in the same group
let same_group = group
.map(|group_a| Some(group_a) == groups.get(b))
.unwrap_or(Some(*uid_b) == beam_segment.owner);
// If owner, shouldn't heal or damage
if Some(*uid_b) == beam_segment.owner {
continue;
}
// Don't heal if outside group
// Don't damage in the same group
let is_damage = !same_group && (beam_segment.damage > 0);
let is_heal = same_group && (beam_segment.heal > 0);
if !is_heal && !is_damage {
continue;
}
// Weapon gives base damage
let source = if is_heal {
DamageSource::Healing
} else {
DamageSource::Energy
};
let healthchange = if is_heal {
beam_segment.heal as f32
} else {
-(beam_segment.damage as f32)
};
let mut damage = Damage {
healthchange,
source,
};
let block = character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
// TODO: investigate whether this calculation is proper for beams
&& ori_b.0.angle_between(pos.0 - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0;
if let Some(loadout) = loadouts.get(b) {
damage.modify_damage(block, loadout);
}
if is_damage {
server_emitter.emit(ServerEvent::Damage {
uid: *uid_b,
change: HealthChange {
amount: damage.healthchange as i32,
cause: HealthSource::Energy {
owner: beam_segment.owner,
},
},
});
if beam_segment.lifesteal_eff > 0.0 {
server_emitter.emit(ServerEvent::Damage {
uid: beam_segment.owner.unwrap_or(*uid),
change: HealthChange {
amount: (-damage.healthchange * beam_segment.lifesteal_eff)
as i32,
cause: HealthSource::Healing {
by: beam_segment.owner,
},
},
});
}
if let Some(energy_mut) = beam_owner.and_then(|o| energies.get_mut(o)) {
energy_mut.change_by(
beam_segment.energy_regen as i32,
EnergySource::HitEnemy,
);
}
}
if is_heal {
if let Some(energy_mut) = beam_owner.and_then(|o| energies.get_mut(o)) {
if energy_mut
.try_change_by(
-(beam_segment.energy_drain as i32), // Stamina use
EnergySource::Ability,
)
.is_ok()
{
server_emitter.emit(ServerEvent::Damage {
uid: *uid_b,
change: HealthChange {
amount: damage.healthchange as i32,
cause: HealthSource::Healing {
by: beam_segment.owner,
},
},
});
}
}
}
// Adds entities that were hit to the hit_entities list on the beam, sees if it
// needs to purge the hit_entities list
hit_entities.push(*uid_b);
}
}
}
for beam in (&mut beams).join() {
beam.timer = beam
.timer
.checked_add(Duration::from_secs_f32(dt))
.unwrap_or(beam.tick_dur);
if beam.timer >= beam.tick_dur {
beam.hit_entities.clear();
beam.timer = beam.timer.checked_sub(beam.tick_dur).unwrap_or_default();
}
}
// Set start time on new beams
// This change doesn't need to be recorded as it is not sent to the client
beam_segments.set_event_emission(false);
(&mut beam_segments).join().for_each(|beam_segment| {
if beam_segment.creation.is_none() {
beam_segment.creation = Some(time);
}
});
beam_segments.set_event_emission(true);
}
}
/// Assumes upright cylinder
/// See page 12 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.396.7952&rep=rep1&type=pdf
#[allow(clippy::too_many_arguments)]
fn sphere_wedge_cylinder_collision(
// Values for spherical wedge
real_pos: Vec3<f32>,
min_rad: f32, // Distance from beam origin to inner section of beam
max_rad: f32, //Distance from beam origin to outer section of beam
ori: Vec3<f32>,
angle: f32,
// Values for cylinder
bottom_pos_b: Vec3<f32>, // Position of bottom of cylinder
rad_b: f32,
length_b: f32,
) -> bool {
// Converts all coordinates so that the new origin is in the center of the
// cylinder
let center_pos_b = Vec3::new(
bottom_pos_b.x,
bottom_pos_b.y,
bottom_pos_b.z + length_b / 2.0,
);
let pos = real_pos - center_pos_b;
let pos_b = Vec3::zero();
if pos.distance_squared(pos_b) > (max_rad + rad_b + length_b).powi(2) {
// Does quick check if entity is too far (I'm not sure if necessary, but
// probably makes detection more efficient)
false
} else if pos.z.abs() <= length_b / 2.0 {
// Checks case 1: center of sphere is on same z-height as cylinder
let pos2 = Vec2::<f32>::from(pos);
let ori2 = Vec2::from(ori);
let distance = pos2.distance(Vec2::zero());
let in_range = distance < max_rad && distance > min_rad;
// Done so that if distance = 0, atan() can still be calculated https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6d2221bb9454debdfca8f9c52d1edb29
let tangent_value1: f32 = rad_b / distance;
let tangent_value2: f32 = length_b / 2.0 / distance;
let in_angle = pos2.angle_between(-ori2) < angle + (tangent_value1).atan().abs()
&& pos.angle_between(-ori) < angle + (tangent_value2).atan().abs();
in_range && in_angle
} else {
// Checks case 2: if sphere collides with top/bottom of cylinder, doesn't use
// paper. Logic used here is it checks if line between centers passes through
// either cap, then if the cap is within range, then if withing angle of beam.
// If line
let sign = if pos.z > 0.0 { 1.0 } else { -1.0 };
let height = sign * length_b / 2.0;
let (in_range, in_angle): (bool, bool);
// Gets relatively how far along the line (between sphere and cylinder centers)
// the endcap of the cylinder is, is between 0 and 1 when sphere center is not
// in cylinder
let intersect_frac = (length_b / 2.0 / pos.z).abs();
// Gets the position of the cylinder edge closest to the sphere center
let edge_pos = if let Some(vec) = Vec3::new(pos.x, pos.y, 0.0).try_normalized() {
vec * rad_b
} else {
// Returns an arbitrary location that is still guaranteed to be on the cylinder
// edge. This case should only happen when the sphere is directly above the
// cylinder, in which case all positions on edge are equally close.
Vec3::new(rad_b, 0.0, 0.0)
};
// Gets position on opposite edge of same endcap
let opp_end_edge_pos = Vec3::new(-edge_pos.x, -edge_pos.y, height);
// Gets position on same edge of opposite endcap
let bot_end_edge_pos = Vec3::new(edge_pos.x, edge_pos.y, -height);
// Gets point on line between sphere and cylinder centers that the z value is
// equal to the endcap z location
let intersect_point = Vec2::new(pos.x * intersect_frac, pos.y * intersect_frac);
// Checks if line between sphere and cylinder center passes through cap of
// cylinder
if intersect_point.distance_squared(Vec2::zero()) <= rad_b.powi(2) {
let distance_squared =
Vec3::new(intersect_point.x, intersect_point.y, height).distance_squared(pos);
in_range = distance_squared < max_rad.powi(2) && distance_squared > min_rad.powi(2);
// Angle between (line between centers of cylinder and sphere) and either (line
// between opposite edge of endcap and sphere center) or (line between close
// edge of endcap on bottom of cylinder and sphere center). Whichever angle is
// largest is used.
let angle2 = (pos_b - pos)
.angle_between(opp_end_edge_pos - pos)
.max((pos_b - pos).angle_between(bot_end_edge_pos - pos));
in_angle = pos.angle_between(-ori) < angle + angle2;
} else {
// TODO: Handle collision for this case more accurately
// For this case, the nearest point will be the edge of the endcap
let endcap_edge_pos = Vec3::new(edge_pos.x, edge_pos.y, height);
let distance_squared = endcap_edge_pos.distance_squared(pos);
in_range = distance_squared > min_rad.powi(2) && distance_squared < max_rad.powi(2);
// Gets side positions on same endcap
let side_end_edge_pos_1 = Vec3::new(edge_pos.y, -edge_pos.x, height);
let side_end_edge_pos_2 = Vec3::new(-edge_pos.y, edge_pos.x, height);
// Gets whichever angle is bigger, between sphere center and opposite edge,
// sphere center and bottom edge, or half of sphere center and both the side
// edges
let angle2 = (pos_b - pos).angle_between(opp_end_edge_pos - pos).max(
(pos_b - pos).angle_between(bot_end_edge_pos - pos).max(
(side_end_edge_pos_1 - pos).angle_between(side_end_edge_pos_2 - pos) / 2.0,
),
);
// Will be somewhat inaccurate, tends towards hitting when it shouldn't
// Checks angle between orientation and line between sphere and cylinder centers
in_angle = pos.angle_between(-ori) < angle + angle2;
}
in_range && in_angle
}
}

View File

@ -1,6 +1,6 @@
use crate::{
comp::{
Attacking, Body, CharacterState, ControlAction, Controller, ControllerInputs, Energy,
Attacking, Beam, Body, CharacterState, ControlAction, Controller, ControllerInputs, Energy,
Loadout, Mounting, Ori, PhysicsState, Pos, StateUpdate, Stats, Vel,
},
event::{EventBus, LocalEvent, ServerEvent},
@ -89,6 +89,7 @@ pub type JoinTuple<'a> = (
&'a Body,
&'a PhysicsState,
Option<&'a Attacking>,
Option<&'a Beam>,
);
fn incorporate_update(tuple: &mut JoinTuple, state_update: StateUpdate) {
@ -158,6 +159,7 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Body>,
ReadStorage<'a, PhysicsState>,
ReadStorage<'a, Attacking>,
ReadStorage<'a, Beam>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Mounting>,
);
@ -184,6 +186,7 @@ impl<'a> System<'a> for Sys {
bodies,
physics_states,
attacking_storage,
beam_storage,
uids,
mountings,
): Self::SystemData,
@ -207,6 +210,7 @@ impl<'a> System<'a> for Sys {
&bodies,
&physics_states,
attacking_storage.maybe(),
beam_storage.maybe(),
)
.join()
{
@ -259,6 +263,7 @@ impl<'a> System<'a> for Sys {
CharacterState::SpinMelee(data) => data.handle_event(&j, action),
CharacterState::ChargedRanged(data) => data.handle_event(&j, action),
CharacterState::GroundShockwave(data) => data.handle_event(&j, action),
CharacterState::BasicBeam(data) => data.handle_event(&j, action),
};
local_emitter.append(&mut state_update.local_events);
server_emitter.append(&mut state_update.server_events);
@ -288,6 +293,7 @@ impl<'a> System<'a> for Sys {
CharacterState::SpinMelee(data) => data.behavior(&j),
CharacterState::ChargedRanged(data) => data.behavior(&j),
CharacterState::GroundShockwave(data) => data.behavior(&j),
CharacterState::BasicBeam(data) => data.behavior(&j),
};
local_emitter.append(&mut state_update.local_events);

View File

@ -113,18 +113,20 @@ impl<'a> System<'a> for Sys {
.unwrap_or(false);
// Don't heal if outside group
// Don't damage in the same group
if same_group != (attack.base_healthchange > 0) {
let is_damage = !same_group && (attack.base_damage > 0);
let is_heal = same_group && (attack.base_heal > 0);
if !is_heal && !is_damage {
continue;
}
// Weapon gives base damage
let source = if attack.base_healthchange > 0 {
DamageSource::Healing
let (source, healthchange) = if is_heal {
(DamageSource::Healing, attack.base_heal as f32)
} else {
DamageSource::Melee
(DamageSource::Melee, -(attack.base_damage as f32))
};
let mut damage = Damage {
healthchange: attack.base_healthchange as f32,
healthchange,
source,
};
@ -135,22 +137,20 @@ impl<'a> System<'a> for Sys {
damage.modify_damage(block, loadout);
}
if damage.healthchange < 0.0 {
if damage.healthchange != 0.0 {
let cause = if is_heal {
HealthSource::Healing { by: Some(*uid) }
} else {
HealthSource::Attack { by: *uid }
};
server_emitter.emit(ServerEvent::Damage {
uid: *uid_b,
change: HealthChange {
amount: damage.healthchange as i32,
cause: HealthSource::Attack { by: *uid },
},
});
} else if damage.healthchange > 0.0 {
server_emitter.emit(ServerEvent::Damage {
uid: *uid_b,
change: HealthChange {
amount: damage.healthchange as i32,
cause: HealthSource::Healing { by: Some(*uid) },
cause,
},
});
attack.hit_count += 1;
}
if attack.knockback != 0.0 && damage.healthchange != 0.0 {
let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
@ -160,7 +160,6 @@ impl<'a> System<'a> for Sys {
* *Dir::slerp(kb_dir, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5),
});
}
attack.hit_count += 1;
}
}
}

View File

@ -1,4 +1,5 @@
pub mod agent;
mod beam;
pub mod character_behavior;
pub mod combat;
pub mod controller;
@ -15,6 +16,7 @@ use specs::DispatcherBuilder;
pub const CHARACTER_BEHAVIOR_SYS: &str = "character_behavior_sys";
pub const COMBAT_SYS: &str = "combat_sys";
pub const AGENT_SYS: &str = "agent_sys";
pub const BEAM_SYS: &str = "beam_sys";
pub const CONTROLLER_SYS: &str = "controller_sys";
pub const MOUNT_SYS: &str = "mount_sys";
pub const PHYS_SYS: &str = "phys_sys";
@ -33,5 +35,6 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS, MOUNT_SYS, STATS_SYS]);
dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]);
dispatch_builder.add(shockwave::Sys, SHOCKWAVE_SYS, &[PHYS_SYS]);
dispatch_builder.add(beam::Sys, BEAM_SYS, &[PHYS_SYS]);
dispatch_builder.add(combat::Sys, COMBAT_SYS, &[PROJECTILE_SYS]);
}

View File

@ -1,7 +1,7 @@
use crate::{
comp::{
Collider, Gravity, Group, Mass, Mounting, Ori, PhysicsState, Pos, Projectile, Scale,
Sticky, Vel,
BeamSegment, Collider, Gravity, Group, Mass, Mounting, Ori, PhysicsState, Pos, Projectile,
Scale, Sticky, Vel,
},
event::{EventBus, ServerEvent},
metrics::SysMetrics,
@ -70,6 +70,7 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Mounting>,
ReadStorage<'a, Group>,
ReadStorage<'a, Projectile>,
ReadStorage<'a, BeamSegment>,
);
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
@ -96,6 +97,7 @@ impl<'a> System<'a> for Sys {
mountings,
groups,
projectiles,
beams,
): Self::SystemData,
) {
let start_time = std::time::Instant::now();
@ -177,6 +179,7 @@ impl<'a> System<'a> for Sys {
collider_other,
_,
group_b,
_,
) in (
&entities,
&uids,
@ -186,6 +189,7 @@ impl<'a> System<'a> for Sys {
colliders.maybe(),
!&mountings,
groups.maybe(),
!&beams,
)
.join()
{

View File

@ -75,7 +75,7 @@ impl<'a> System<'a> for Sys {
continue;
}
for effect in projectile.hit_entity.iter().cloned() {
for effect in projectile.hit_entity.drain(..) {
match effect {
projectile::Effect::Damage(healthchange) => {
let owner_uid = projectile.owner.unwrap();
@ -133,15 +133,17 @@ impl<'a> System<'a> for Sys {
energy_mut.change_by(energy as i32, EnergySource::HitEnemy);
}
},
projectile::Effect::Explode { power } => {
server_emitter.emit(ServerEvent::Explosion {
pos: pos.0,
power,
owner: projectile.owner,
friendly_damage: false,
reagent: None,
})
},
projectile::Effect::Explode {
power,
percent_damage,
} => server_emitter.emit(ServerEvent::Explosion {
pos: pos.0,
power,
owner: projectile.owner,
friendly_damage: false,
reagent: None,
percent_damage,
}),
projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy {
entity,
cause: HealthSource::World,
@ -162,15 +164,17 @@ impl<'a> System<'a> for Sys {
if physics.on_wall.is_some() || physics.on_ground || physics.on_ceiling {
for effect in projectile.hit_solid.drain(..) {
match effect {
projectile::Effect::Explode { power } => {
server_emitter.emit(ServerEvent::Explosion {
pos: pos.0,
power,
owner: projectile.owner,
friendly_damage: false,
reagent: None,
})
},
projectile::Effect::Explode {
power,
percent_damage,
} => server_emitter.emit(ServerEvent::Explosion {
pos: pos.0,
power,
owner: projectile.owner,
friendly_damage: false,
reagent: None,
percent_damage,
}),
projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy {
entity,
cause: HealthSource::World,

View File

@ -113,7 +113,8 @@ impl<'a> System<'a> for Sys {
| CharacterState::ComboMelee { .. }
| CharacterState::BasicRanged { .. }
| CharacterState::ChargedRanged { .. }
| CharacterState::GroundShockwave { .. } => {
| CharacterState::GroundShockwave { .. }
| CharacterState::BasicBeam { .. } => {
if energy.get_unchecked().regen_rate != 0.0 {
energy.get_mut_unchecked().regen_rate = 0.0
}

370
items.csv
View File

@ -1,370 +0,0 @@
Path,Name,Kind
common.items.armor.back.admin,Admin's Cape,Admin
common.items.armor.back.dungeon_purple-0,Purple Cultist Cape,DungPurp0
common.items.armor.back.leather_adventurer,Agile Cape,Short2
common.items.armor.back.short_0,Short leather Cape,Short0
common.items.armor.back.short_1,Green Blanket,Short1
common.items.armor.belt.assassin,Assassin Belt,Assassin
common.items.armor.belt.bonerattler,Bonerattler Belt,Bonerattler
common.items.armor.belt.cloth_blue_0,Blue Linen Belt,ClothBlue0
common.items.armor.belt.cloth_green_0,Green Linen Belt,ClothGreen0
common.items.armor.belt.cloth_purple_0,Purple Linen Belt,ClothPurple0
common.items.armor.belt.cultist_belt,Cultist Belt,Cultist
common.items.armor.belt.druid,Druid's Belt,Druid
common.items.armor.belt.leather_0,Swift Belt,Leather0
common.items.armor.belt.leather_2,Leather Belt,Leather2
common.items.armor.belt.leather_adventurer,Agile Belt,Leather2
common.items.armor.belt.plate_0,Iron Belt,Plate0
common.items.armor.belt.steel_0,Steel Belt,Steel0
common.items.armor.belt.tarasque,Tarasque Belt,Tarasque
common.items.armor.belt.twig,Twig Belt,Twig
common.items.armor.belt.twigsflowers,Flowery Belt,Twigsflowers
common.items.armor.belt.twigsleaves,Leafy Belt,Twigsleaves
common.items.armor.chest.assassin,Assassin Chest,Assassin
common.items.armor.chest.bonerattler,Bonerattler Cuirass,Bonerattler
common.items.armor.chest.cloth_blue_0,Blue Linen Chest,ClothBlue0
common.items.armor.chest.cloth_green_0,Green Linen Chest,ClothGreen0
common.items.armor.chest.cloth_purple_0,Purple Linen Chest,ClothPurple0
common.items.armor.chest.cultist_chest_blue,Blue Cultist Chest,CultistBlue
common.items.armor.chest.cultist_chest_purple,Purple Cultist Chest,CultistPurple
common.items.armor.chest.druid,Druid's Vest,Druid
common.items.armor.chest.leather_0,Swift Chest,Leather0
common.items.armor.chest.leather_2,Leather Cuirass,Leather2
common.items.armor.chest.leather_adventurer,Agile Chest,Leather2
common.items.armor.chest.plate_green_0,Iron Chestplate,PlateGreen0
common.items.armor.chest.steel_0,Steel Cuirass,Steel0
common.items.armor.chest.tarasque,Tarasque Cuirass,Tarasque
common.items.armor.chest.twig,Twig Shirt,Twig
common.items.armor.chest.twigsflowers,Flowery Shirt,Twigsflowers
common.items.armor.chest.twigsleaves,Leafy Shirt,Twigsleaves
common.items.armor.chest.worker_green_0,Green Worker Shirt,WorkerGreen0
common.items.armor.chest.worker_green_1,Green Worker Shirt,WorkerGreen1
common.items.armor.chest.worker_orange_0,Orange Worker Shirt,WorkerOrange0
common.items.armor.chest.worker_orange_1,Orange Worker Shirt,WorkerOrange1
common.items.armor.chest.worker_purple_0,Purple Worker Shirt,WorkerPurple0
common.items.armor.chest.worker_purple_1,Purple Worker Shirt,WorkerPurple1
common.items.armor.chest.worker_red_0,Red Worker Shirt,WorkerRed0
common.items.armor.chest.worker_red_1,Red Worker Shirt,WorkerRed1
common.items.armor.chest.worker_yellow_0,Yellow Worker Shirt,WorkerYellow0
common.items.armor.chest.worker_yellow_1,Yellow Worker Shirt,WorkerYellow1
common.items.armor.foot.assassin,Assassin Boots,Assassin
common.items.armor.foot.bonerattler,Bonerattler Boots,Bonerattler
common.items.armor.foot.cloth_blue_0,Blue Linen Boots,ClothBlue0
common.items.armor.foot.cloth_green_0,Green Linen Boots,ClothGreen0
common.items.armor.foot.cloth_purple_0,Purple Linen Boots,ClothPurple0
common.items.armor.foot.cultist_boots,Cultist Boots,Cultist
common.items.armor.foot.druid,Druid's Slippers,Druid
common.items.armor.foot.jackalope_slippers,Fluffy Jackalope Slippers,JackalopeSlips
common.items.armor.foot.leather_0,Swift Boots,Leather0
common.items.armor.foot.leather_2,Leather Boots,Leather2
common.items.armor.foot.leather_adventurer,Agile Kickers,Leather2
common.items.armor.foot.plate_0,Iron Feet,Plate0
common.items.armor.foot.steel_0,Steel Boots,Steel0
common.items.armor.foot.tarasque,Tarasque Boots,Tarasque
common.items.armor.foot.twig,Twig Boots,Twig
common.items.armor.foot.twigsflowers,Flowery Boots,Twigsflowers
common.items.armor.foot.twigsleaves,Leafy Boots,Twigsleaves
common.items.armor.hand.assassin,Assassin Gloves,Assassin
common.items.armor.hand.bonerattler,Bonerattler Gauntlets,Bonerattler
common.items.armor.hand.cloth_blue_0,Blue Linen Wrists,ClothBlue0
common.items.armor.hand.cloth_green_0,Green Linen Wrists,ClothGreen0
common.items.armor.hand.cloth_purple_0,Purple Silk Wrists,ClothPurple0
common.items.armor.hand.cultist_hands_blue,Blue Cultist Gloves,CultistBlue
common.items.armor.hand.cultist_hands_purple,Purple Cultist Gloves,CultistPurple
common.items.armor.hand.druid,Druid's Gloves,Druid
common.items.armor.hand.leather_0,Swift Gloves,Leather0
common.items.armor.hand.leather_2,Leather Gloves,Leather2
common.items.armor.hand.leather_adventurer,Agile Gauntlets,Leather2
common.items.armor.hand.plate_0,Iron Handguards,Plate0
common.items.armor.hand.steel_0,Steel Gauntlets,Steel0
common.items.armor.hand.tarasque,Tarasque Gauntlets,Tarasque
common.items.armor.hand.twig,Twig Wraps,Twig
common.items.armor.hand.twigsflowers,Flowery Wraps,Twigsflowers
common.items.armor.hand.twigsleaves,Leafy Wraps,Twigsleaves
common.items.armor.head.assa_mask_0,Dark Assassin Mask,AssaMask0
common.items.armor.head.leather_0,Swift Leather Cap,Leather0
common.items.armor.neck.neck_0,Plain Necklace,Neck0
common.items.armor.neck.neck_1,Gem of lesser Protection,Neck1
common.items.armor.pants.assassin,Assassin Pants,Assassin
common.items.armor.pants.bonerattler,Bonerattler Chausses,Bonerattler
common.items.armor.pants.cloth_blue_0,Blue Linen Skirt,ClothBlue0
common.items.armor.pants.cloth_green_0,Green Linen Skirt,ClothGreen0
common.items.armor.pants.cloth_purple_0,Purple Linen Skirt,ClothPurple0
common.items.armor.pants.cultist_legs_blue,Blue Cultist Skirt,CultistBlue
common.items.armor.pants.cultist_legs_purple,Purple Cultist Skirt,CultistPurple
common.items.armor.pants.druid,Druid's Kilt,Druid
common.items.armor.pants.hunting,Hunting Pants,Hunting
common.items.armor.pants.leather_0,Swift Pants,Leather0
common.items.armor.pants.leather_2,Leather Leg Armour,Leather2
common.items.armor.pants.leather_adventurer,Agile Pantalons,Leather2
common.items.armor.pants.plate_green_0,Iron Legguards,PlateGreen0
common.items.armor.pants.steel_0,Steel Chausses,Steel0
common.items.armor.pants.tarasque,Tarasque Chausses,Tarasque
common.items.armor.pants.twig,Twig Pants,Twig
common.items.armor.pants.twigsflowers,Flowery Pants,Twigsflowers
common.items.armor.pants.twigsleaves,Leafy Pants,Twigsleaves
common.items.armor.pants.worker_blue_0,Blue Worker Pants,WorkerBlue0
common.items.armor.ring.ring_0,Scratched Ring,Ring0
common.items.armor.shoulder.assassin,Assassin Shoulder Guard,Assassin
common.items.armor.shoulder.bonerattler,Bonerattler Shoulder Pad,Bonerattler
common.items.armor.shoulder.cloth_blue_0,Blue Linen Coat,ClothBlue0
common.items.armor.shoulder.cloth_blue_1,Blue Cloth Pads,ClothBlue1
common.items.armor.shoulder.cloth_green_0,Green Linen Coat,ClothGreen0
common.items.armor.shoulder.cloth_purple_0,Purple Linen Coat,ClothPurple0
common.items.armor.shoulder.cultist_shoulder_blue,Blue Cultist Mantle,CultistBlue
common.items.armor.shoulder.cultist_shoulder_purple,Purple Cultist Mantle,CultistPurple
common.items.armor.shoulder.druidshoulder,Druid Shoulders,DruidShoulder
common.items.armor.shoulder.iron_spikes,Iron Spiked Pauldrons,IronSpikes
common.items.armor.shoulder.leather_0,Leather Pauldrons,Leather0
common.items.armor.shoulder.leather_1,Swift Shoulderpads,Leather1
common.items.armor.shoulder.leather_2,Leather Shoulder Pad,Leather2
common.items.armor.shoulder.leather_adventurer,Agile Guards,Leather2
common.items.armor.shoulder.leather_iron_0,Iron and Leather Spaulders,IronLeather0
common.items.armor.shoulder.leather_iron_1,Iron and Leather Spaulders,IronLeather1
common.items.armor.shoulder.leather_iron_2,Iron and Leather Spaulders,IronLeather2
common.items.armor.shoulder.leather_iron_3,Iron and Leather Spaulders,IronLeather3
common.items.armor.shoulder.leather_strips,Leather Strips,LeatherStrips
common.items.armor.shoulder.plate_0,Iron Shoulderguards,Plate0
common.items.armor.shoulder.steel_0,Steel Shoulder Pad,Steel0
common.items.armor.shoulder.tarasque,Tarasque Shoulder Pad,Tarasque
common.items.armor.shoulder.twigs,Twiggy Shoulders,TwiggyShoulder
common.items.armor.shoulder.twigsflowers,Flowery Shoulders,FlowerShoulder
common.items.armor.shoulder.twigsleaves,Leafy Shoulders,LeafyShoulder
common.items.armor.starter.lantern,Black Lantern,Black0
common.items.armor.starter.rugged_chest,Rugged Shirt,Rugged0
common.items.armor.starter.rugged_pants,Rugged Commoner's Pants,Rugged0
common.items.armor.starter.sandals_0,Worn out Sandals,Sandal0
common.items.armor.tabard.admin,Admin's Tabard,Admin
common.items.boss_drops.exp_flask,Flask of Velorite Dusk,
common.items.boss_drops.lantern,Magic Lantern,Blue0
common.items.boss_drops.potions,Potent Potion,
common.items.boss_drops.xp_potion,Potion of Skill,
common.items.consumable.potion_big,Large Potion,
common.items.consumable.potion_med,Medium Potion,
common.items.consumable.potion_minor,Minor Potion,
common.items.crafting_ing.empty_vial,Empty Vial,
common.items.crafting_ing.leather_scraps,Leather Scraps,
common.items.crafting_ing.shiny_gem,Shiny Gem,
common.items.crafting_ing.stones,Stones,
common.items.crafting_ing.twigs,Twigs,
common.items.crafting_tools.craftsman_hammer,Craftsman Hammer,
common.items.crafting_tools.mortar_pestle,Mortar and Pestle,
common.items.debug.admin,Admin's Tabard,Admin
common.items.debug.admin_back,Admin's Cape,Admin
common.items.debug.boost,Belzeshrub the Broom-God,Boost
common.items.debug.cultist_belt,Cultist Belt,Cultist
common.items.debug.cultist_boots,Cultist Boots,Cultist
common.items.debug.cultist_chest_blue,Blue Cultist Chest,CultistBlue
common.items.debug.cultist_hands_blue,Blue Cultist Gloves,CultistBlue
common.items.debug.cultist_legs_blue,Blue Cultist Skirt,CultistBlue
common.items.debug.cultist_purp_2h_boss-0,Admin Greatsword,CultPurp0
common.items.debug.cultist_shoulder_blue,Blue Cultist Mantle,CultistBlue
common.items.debug.dungeon_purple-0,Purple Admin Cape,DungPurp0
common.items.debug.possess,Belzeshrub the Broom-God,Boost
common.items.flowers.blue,Blue Flower,
common.items.flowers.pink,Pink Flower,
common.items.flowers.red,Red Flower,
common.items.flowers.sun,Sunflower,
common.items.flowers.white,White flower,
common.items.flowers.yellow,Yellow Flower,
common.items.food.apple,Apple,
common.items.food.apple_mushroom_curry,Mushroom Curry,
common.items.food.apple_stick,Apple Stick,
common.items.food.cheese,Dwarven Cheese,
common.items.food.coconut,Coconut,
common.items.food.mushroom,Mushroom,
common.items.food.mushroom_stick,Mushroom Stick,
common.items.grasses.long,Long Grass,
common.items.grasses.medium,Medium Grass,
common.items.grasses.short,Short Grass,
common.items.lantern.black_0,Black Lantern,Black0
common.items.lantern.blue_0,Cool Blue Lantern,Blue0
common.items.lantern.green_0,Lime Zest Lantern,Green0
common.items.lantern.red_0,Red Lantern,Red0
common.items.npc_armor.back.dungeon_purple-0,Purple Cultist Cape,DungPurp0
common.items.npc_armor.belt.cultist_belt,Cultist Belt,Cultist
common.items.npc_armor.chest.cultist_chest_purple,Purple Cultist Chest,CultistPurple
common.items.npc_armor.chest.worker_green_0,Green Worker Shirt,WorkerGreen0
common.items.npc_armor.chest.worker_green_1,Green Worker Shirt,WorkerGreen1
common.items.npc_armor.chest.worker_orange_0,Orange Worker Shirt,WorkerOrange0
common.items.npc_armor.chest.worker_orange_1,Orange Worker Shirt,WorkerOrange1
common.items.npc_armor.chest.worker_purple_0,Purple Worker Shirt,WorkerPurple0
common.items.npc_armor.chest.worker_purple_1,Purple Worker Shirt,WorkerPurple1
common.items.npc_armor.chest.worker_red_0,Red Worker Shirt,WorkerRed0
common.items.npc_armor.chest.worker_red_1,Red Worker Shirt,WorkerRed1
common.items.npc_armor.chest.worker_yellow_0,Yellow Worker Shirt,WorkerYellow0
common.items.npc_armor.chest.worker_yellow_1,Yellow Worker Shirt,WorkerYellow1
common.items.npc_armor.foot.cultist_boots,Cultist Boots,Cultist
common.items.npc_armor.hand.cultist_hands_purple,Purple Cultist Gloves,CultistPurple
common.items.npc_armor.pants.cultist_legs_purple,Purple Cultist Skirt,CultistPurple
common.items.npc_armor.shoulder.cultist_shoulder_purple,Purple Cultist Mantle,CultistPurple
common.items.npc_weapons.axe.malachite_axe-0,Malachite Axe,MalachiteAxe0
common.items.npc_weapons.axe.starter_axe,Notched Axe,BasicAxe
common.items.npc_weapons.bow.horn_longbow-0,Horn Bow,HornLongbow0
common.items.npc_weapons.dagger.starter_dagger,Rusty Dagger,BasicDagger
common.items.npc_weapons.empty.empty,Empty,
common.items.npc_weapons.hammer.cultist_purp_2h-0,Magical Cultist Warhammer,CultPurp0
common.items.npc_weapons.hammer.starter_hammer,Sturdy Old Hammer,BasicHammer
common.items.npc_weapons.shield.shield_1,A Tattered Targe,BasicShield
common.items.npc_weapons.staff.bone_staff,Bone Staff,BoneStaff
common.items.npc_weapons.staff.cultist_staff,Cultist Staff,CultistStaff
common.items.npc_weapons.sword.cultist_purp_2h-0,Magical Cultist Greatsword,CultPurp0
common.items.npc_weapons.sword.cultist_purp_2h_boss-0,Magical Cultist Greatsword,CultPurp0
common.items.npc_weapons.sword.starter_sword,Battered Sword,BasicSword
common.items.npc_weapons.sword.zweihander_sword_0,Sturdy Zweihander,Zweihander0
common.items.npc_weapons.tool.broom,Broom,Broom
common.items.npc_weapons.tool.fishing_rod,Fishing Rod,FishingRod0
common.items.npc_weapons.tool.hoe,Hoe,Hoe0
common.items.npc_weapons.tool.pickaxe,Pickaxe,Pickaxe0
common.items.npc_weapons.tool.pitchfork,Pitchfork,Pitchfork
common.items.npc_weapons.tool.rake,Rake,Rake
common.items.npc_weapons.tool.shovel-0,Shovel,Shovel0
common.items.npc_weapons.tool.shovel-1,Shovel,Shovel1
common.items.ore.velorite,Velorite,
common.items.ore.veloritefrag,Velorite Fragment,
common.items.testing.test_boots,Testing Boots,Dark
common.items.utility.bomb,Bomb,
common.items.utility.bomb_pile,Bomb,
common.items.utility.collar,Collar,
common.items.utility.firework_blue,Firework Blue,
common.items.utility.firework_green,Firework Green,
common.items.utility.firework_purple,Firework Purple,
common.items.utility.firework_red,Firework Red,
common.items.utility.firework_yellow,Firework Yellow,
common.items.utility.training_dummy,Training Dummy,
common.items.weapons.axe.bloodsteel_axe-0,Bloodsteel Axe,BloodsteelAxe0
common.items.weapons.axe.bloodsteel_axe-1,Executioner's Axe,BloodsteelAxe1
common.items.weapons.axe.bloodsteel_axe-2,Tribal Axe,BloodsteelAxe2
common.items.weapons.axe.bronze_axe-0,Bronze Axe,BronzeAxe0
common.items.weapons.axe.bronze_axe-1,Discus Axe,BronzeAxe1
common.items.weapons.axe.cobalt_axe-0,Cobalt Axe,CobaltAxe0
common.items.weapons.axe.iron_axe-0,Iron Greataxe,IronAxe0
common.items.weapons.axe.iron_axe-1,Ceremonial Axe,IronAxe1
common.items.weapons.axe.iron_axe-2,Cyclone Axe,IronAxe2
common.items.weapons.axe.iron_axe-3,Iron Battleaxe,IronAxe3
common.items.weapons.axe.iron_axe-4,Butcher's Axe,IronAxe4
common.items.weapons.axe.iron_axe-5,Barbarian's Axe,IronAxe5
common.items.weapons.axe.iron_axe-6,Iron Axe,IronAxe6
common.items.weapons.axe.iron_axe-7,Iron Labrys,IronAxe7
common.items.weapons.axe.iron_axe-8,Fanged Axe,IronAxe8
common.items.weapons.axe.iron_axe-9,Wolfen Axe,IronAxe9
common.items.weapons.axe.malachite_axe-0,Malachite Axe,MalachiteAxe0
common.items.weapons.axe.orc_axe-0,Beast Cleaver,OrcAxe0
common.items.weapons.axe.starter_axe,Notched Axe,BasicAxe
common.items.weapons.axe.steel_axe-0,Steel Battleaxe,SteelAxe0
common.items.weapons.axe.steel_axe-1,Steel Labrys,SteelAxe1
common.items.weapons.axe.steel_axe-2,Steel Axe,SteelAxe2
common.items.weapons.axe.steel_axe-3,Crescent Axe,SteelAxe3
common.items.weapons.axe.steel_axe-4,Moon Axe,SteelAxe4
common.items.weapons.axe.steel_axe-5,Owl Axe,SteelAxe5
common.items.weapons.axe.steel_axe-6,Spade Axe,SteelAxe6
common.items.weapons.axe.worn_iron_axe-0,Worn Dwarven Axe,WornIronAxe0
common.items.weapons.axe.worn_iron_axe-1,Worn Elven Axe,WornIronAxe1
common.items.weapons.axe.worn_iron_axe-2,Worn Human Axe,WornIronAxe2
common.items.weapons.axe.worn_iron_axe-3,Worn Orcish Axe,WornIronAxe3
common.items.weapons.axe.worn_iron_axe-4,Beetle Axe,WornIronAxe4
common.items.weapons.bow.horn_longbow-0,Horn Bow,HornLongbow0
common.items.weapons.bow.iron_longbow-0,Soldier's Bow,IronLongbow0
common.items.weapons.bow.leafy_longbow-0,Elven Longbow,LeafyLongbow0
common.items.weapons.bow.leafy_shortbow-0,Elven Shortbow,LeafyShortbow0
common.items.weapons.bow.nature_ore_longbow-0,Velorite Bow,NatureOreLongbow
common.items.weapons.bow.rare_longbow,Enchanted Longbow,RareLongbow
common.items.weapons.bow.starter_bow,Uneven Bow,ShortBow0
common.items.weapons.bow.wood_longbow-0,Longbow,WoodLongbow0
common.items.weapons.bow.wood_longbow-1,Recurve Bow,WoodLongbow1
common.items.weapons.bow.wood_shortbow-0,Hunting Bow,WoodShortbow0
common.items.weapons.bow.wood_shortbow-1,Horse Bow,WoodShortbow1
common.items.weapons.dagger.starter_dagger,Rusty Dagger,BasicDagger
common.items.weapons.empty.empty,Empty,
common.items.weapons.hammer.bronze_hammer-0,Bronze Hammer,BronzeHammer0
common.items.weapons.hammer.bronze_hammer-1,Bronze Club,BronzeHammer1
common.items.weapons.hammer.cobalt_hammer-0,Cobalt Hammer,CobaltHammer0
common.items.weapons.hammer.cobalt_hammer-1,Cobalt Mace,CobaltHammer1
common.items.weapons.hammer.cultist_purp_2h-0,Magical Cultist Warhammer,CultPurp0
common.items.weapons.hammer.flimsy_hammer,Flimsy Hammer,FlimsyHammer
common.items.weapons.hammer.hammer_1,Crude Mallet,BasicHammer
common.items.weapons.hammer.iron_hammer-0,Iron Hammer,IronHammer0
common.items.weapons.hammer.iron_hammer-1,Iron Battlehammer,IronHammer1
common.items.weapons.hammer.iron_hammer-2,Iron Mace,IronHammer2
common.items.weapons.hammer.iron_hammer-3,Crowned Mace,IronHammer3
common.items.weapons.hammer.iron_hammer-4,Forge Hammer,IronHammer4
common.items.weapons.hammer.iron_hammer-5,Pike Hammer,IronHammer5
common.items.weapons.hammer.iron_hammer-6,Spiked Maul,IronHammer6
common.items.weapons.hammer.iron_hammer-7,Giant's Fist,IronHammer7
common.items.weapons.hammer.iron_hammer-8,Lucerne Hammer,IronHammer8
common.items.weapons.hammer.mjolnir,Mjolnir,Mjolnir
common.items.weapons.hammer.ramshead_hammer,Ram's Head Mace,RamsheadHammer
common.items.weapons.hammer.runic_hammer,Runic Hammer,RunicHammer
common.items.weapons.hammer.starter_hammer,Sturdy Old Hammer,BasicHammer
common.items.weapons.hammer.steel_hammer-0,Steel Hammer,SteelHammer0
common.items.weapons.hammer.steel_hammer-1,Steel Greathammer,SteelHammer1
common.items.weapons.hammer.steel_hammer-2,Steel Club,SteelHammer2
common.items.weapons.hammer.steel_hammer-3,Battle Mace,SteelHammer3
common.items.weapons.hammer.steel_hammer-4,Brute's Hammer,SteelHammer4
common.items.weapons.hammer.steel_hammer-5,Morning Star,SteelHammer5
common.items.weapons.hammer.stone_hammer-0,Basalt Sledgehammer,StoneHammer0
common.items.weapons.hammer.stone_hammer-1,Granite Sledgehammer,StoneHammer1
common.items.weapons.hammer.stone_hammer-2,Rocky Maul,StoneHammer2
common.items.weapons.hammer.stone_hammer-3,Stone Sledgehammer,StoneHammer3
common.items.weapons.hammer.wood_hammer-0,Hardwood Mallet,WoodHammer0
common.items.weapons.hammer.worn_iron_hammer-0,Worn Dwarven Hammer,WornIronHammer0
common.items.weapons.hammer.worn_iron_hammer-1,Worn Elven Hammer,WornIronHammer1
common.items.weapons.hammer.worn_iron_hammer-2,Worn Human Mace,WornIronHammer2
common.items.weapons.hammer.worn_iron_hammer-3,Worn Orcish Hammer,WornIronHammer3
common.items.weapons.shield.shield_1,A Tattered Targe,BasicShield
common.items.weapons.staff.amethyst_staff,Amethyst Staff,AmethystStaff
common.items.weapons.staff.bone_staff,Bone Staff,BoneStaff
common.items.weapons.staff.cultist_staff,Cultist Staff,CultistStaff
common.items.weapons.staff.sceptre_velorite_0,Velorite Sceptre,SceptreVelorite
common.items.weapons.staff.staff_1,Humble Stick,BasicStaff
common.items.weapons.staff.staff_nature,Sceptre of Regeneration,Sceptre
common.items.weapons.staff.starter_staff,Gnarled Rod,BasicStaff
common.items.weapons.sword.cultist_purp_2h-0,Magical Cultist Greatsword,CultPurp0
common.items.weapons.sword.greatsword_2h_dam-0,Damaged Greatsword,GreatswordDam0
common.items.weapons.sword.greatsword_2h_dam-1,Damaged Greatsword,GreatswordDam1
common.items.weapons.sword.greatsword_2h_dam-2,Damaged Greatsword,GreatswordDam2
common.items.weapons.sword.greatsword_2h_fine-0,Fine Greatsword,GreatswordFine0
common.items.weapons.sword.greatsword_2h_fine-1,Fine Greatsword,GreatswordFine1
common.items.weapons.sword.greatsword_2h_fine-2,Fine Greatsword,GreatswordFine2
common.items.weapons.sword.greatsword_2h_orn-0,Ornamented Greatsword,GreatswordOrn0
common.items.weapons.sword.greatsword_2h_orn-1,Ornamented Greatsword,GreatswordOrn1
common.items.weapons.sword.greatsword_2h_orn-2,Ornamented Greatsword,GreatswordOrn2
common.items.weapons.sword.greatsword_2h_simple-0,Simple Greatsword,GreatswordSimple0
common.items.weapons.sword.greatsword_2h_simple-1,Simple Greatsword,GreatswordSimple1
common.items.weapons.sword.greatsword_2h_simple-2,Simple Greatsword,GreatswordSimple2
common.items.weapons.sword.long_2h_dam-0,Damaged Longsword,LongDam0
common.items.weapons.sword.long_2h_dam-1,Damaged Longsword,LongDam1
common.items.weapons.sword.long_2h_dam-2,Damaged Longsword,LongDam2
common.items.weapons.sword.long_2h_dam-3,Damaged Longsword,LongDam3
common.items.weapons.sword.long_2h_dam-4,Damaged Longsword,LongDam4
common.items.weapons.sword.long_2h_dam-5,Damaged Longsword,LongDam5
common.items.weapons.sword.long_2h_fine-0,Fine Longsword,LongFine0
common.items.weapons.sword.long_2h_fine-1,Fine Longsword,LongFine1
common.items.weapons.sword.long_2h_fine-2,Fine Longsword,LongFine2
common.items.weapons.sword.long_2h_fine-3,Fine Longsword,LongFine3
common.items.weapons.sword.long_2h_fine-4,Fine Longsword,LongFine4
common.items.weapons.sword.long_2h_fine-5,Fine Longsword,LongFine5
common.items.weapons.sword.long_2h_orn-0,Ornamented Longsword,LongOrn0
common.items.weapons.sword.long_2h_orn-1,Ornamented Longsword,LongOrn1
common.items.weapons.sword.long_2h_orn-2,Ornamented Longsword,LongOrn2
common.items.weapons.sword.long_2h_orn-3,Ornamented Longsword,LongOrn3
common.items.weapons.sword.long_2h_orn-4,Ornamented Longsword,LongOrn4
common.items.weapons.sword.long_2h_orn-5,Ornamented Longsword,LongOrn5
common.items.weapons.sword.long_2h_simple-0,Simple Longsword,LongSimple0
common.items.weapons.sword.long_2h_simple-1,Simple Longsword,LongSimple1
common.items.weapons.sword.long_2h_simple-2,Simple Longsword,LongSimple2
common.items.weapons.sword.long_2h_simple-3,Simple Longsword,LongSimple3
common.items.weapons.sword.long_2h_simple-4,Simple Longsword,LongSimple4
common.items.weapons.sword.long_2h_simple-5,Simple Longsword,LongSimple5
common.items.weapons.sword.short_sword_0,Vicious Gladius,Short0
common.items.weapons.sword.starter_sword,Battered Sword,BasicSword
common.items.weapons.sword.wood_sword,Forest Spirit,WoodTraining
common.items.weapons.sword.zweihander_sword_0,Sturdy Zweihander,Zweihander0
common.items.weapons.tool.broom,Broom,Broom
common.items.weapons.tool.fishing_rod,Fishing Rod,FishingRod0
common.items.weapons.tool.hoe,Hoe,Hoe0
common.items.weapons.tool.pickaxe,Pickaxe,Pickaxe0
common.items.weapons.tool.pitchfork,Pitchfork,Pitchfork
common.items.weapons.tool.rake,Rake,Rake
common.items.weapons.tool.shovel-0,Shovel,Shovel0
common.items.weapons.tool.shovel-1,Shovel,Shovel1
1 Path Name Kind
2 common.items.armor.back.admin Admin's Cape Admin
3 common.items.armor.back.dungeon_purple-0 Purple Cultist Cape DungPurp0
4 common.items.armor.back.leather_adventurer Agile Cape Short2
5 common.items.armor.back.short_0 Short leather Cape Short0
6 common.items.armor.back.short_1 Green Blanket Short1
7 common.items.armor.belt.assassin Assassin Belt Assassin
8 common.items.armor.belt.bonerattler Bonerattler Belt Bonerattler
9 common.items.armor.belt.cloth_blue_0 Blue Linen Belt ClothBlue0
10 common.items.armor.belt.cloth_green_0 Green Linen Belt ClothGreen0
11 common.items.armor.belt.cloth_purple_0 Purple Linen Belt ClothPurple0
12 common.items.armor.belt.cultist_belt Cultist Belt Cultist
13 common.items.armor.belt.druid Druid's Belt Druid
14 common.items.armor.belt.leather_0 Swift Belt Leather0
15 common.items.armor.belt.leather_2 Leather Belt Leather2
16 common.items.armor.belt.leather_adventurer Agile Belt Leather2
17 common.items.armor.belt.plate_0 Iron Belt Plate0
18 common.items.armor.belt.steel_0 Steel Belt Steel0
19 common.items.armor.belt.tarasque Tarasque Belt Tarasque
20 common.items.armor.belt.twig Twig Belt Twig
21 common.items.armor.belt.twigsflowers Flowery Belt Twigsflowers
22 common.items.armor.belt.twigsleaves Leafy Belt Twigsleaves
23 common.items.armor.chest.assassin Assassin Chest Assassin
24 common.items.armor.chest.bonerattler Bonerattler Cuirass Bonerattler
25 common.items.armor.chest.cloth_blue_0 Blue Linen Chest ClothBlue0
26 common.items.armor.chest.cloth_green_0 Green Linen Chest ClothGreen0
27 common.items.armor.chest.cloth_purple_0 Purple Linen Chest ClothPurple0
28 common.items.armor.chest.cultist_chest_blue Blue Cultist Chest CultistBlue
29 common.items.armor.chest.cultist_chest_purple Purple Cultist Chest CultistPurple
30 common.items.armor.chest.druid Druid's Vest Druid
31 common.items.armor.chest.leather_0 Swift Chest Leather0
32 common.items.armor.chest.leather_2 Leather Cuirass Leather2
33 common.items.armor.chest.leather_adventurer Agile Chest Leather2
34 common.items.armor.chest.plate_green_0 Iron Chestplate PlateGreen0
35 common.items.armor.chest.steel_0 Steel Cuirass Steel0
36 common.items.armor.chest.tarasque Tarasque Cuirass Tarasque
37 common.items.armor.chest.twig Twig Shirt Twig
38 common.items.armor.chest.twigsflowers Flowery Shirt Twigsflowers
39 common.items.armor.chest.twigsleaves Leafy Shirt Twigsleaves
40 common.items.armor.chest.worker_green_0 Green Worker Shirt WorkerGreen0
41 common.items.armor.chest.worker_green_1 Green Worker Shirt WorkerGreen1
42 common.items.armor.chest.worker_orange_0 Orange Worker Shirt WorkerOrange0
43 common.items.armor.chest.worker_orange_1 Orange Worker Shirt WorkerOrange1
44 common.items.armor.chest.worker_purple_0 Purple Worker Shirt WorkerPurple0
45 common.items.armor.chest.worker_purple_1 Purple Worker Shirt WorkerPurple1
46 common.items.armor.chest.worker_red_0 Red Worker Shirt WorkerRed0
47 common.items.armor.chest.worker_red_1 Red Worker Shirt WorkerRed1
48 common.items.armor.chest.worker_yellow_0 Yellow Worker Shirt WorkerYellow0
49 common.items.armor.chest.worker_yellow_1 Yellow Worker Shirt WorkerYellow1
50 common.items.armor.foot.assassin Assassin Boots Assassin
51 common.items.armor.foot.bonerattler Bonerattler Boots Bonerattler
52 common.items.armor.foot.cloth_blue_0 Blue Linen Boots ClothBlue0
53 common.items.armor.foot.cloth_green_0 Green Linen Boots ClothGreen0
54 common.items.armor.foot.cloth_purple_0 Purple Linen Boots ClothPurple0
55 common.items.armor.foot.cultist_boots Cultist Boots Cultist
56 common.items.armor.foot.druid Druid's Slippers Druid
57 common.items.armor.foot.jackalope_slippers Fluffy Jackalope Slippers JackalopeSlips
58 common.items.armor.foot.leather_0 Swift Boots Leather0
59 common.items.armor.foot.leather_2 Leather Boots Leather2
60 common.items.armor.foot.leather_adventurer Agile Kickers Leather2
61 common.items.armor.foot.plate_0 Iron Feet Plate0
62 common.items.armor.foot.steel_0 Steel Boots Steel0
63 common.items.armor.foot.tarasque Tarasque Boots Tarasque
64 common.items.armor.foot.twig Twig Boots Twig
65 common.items.armor.foot.twigsflowers Flowery Boots Twigsflowers
66 common.items.armor.foot.twigsleaves Leafy Boots Twigsleaves
67 common.items.armor.hand.assassin Assassin Gloves Assassin
68 common.items.armor.hand.bonerattler Bonerattler Gauntlets Bonerattler
69 common.items.armor.hand.cloth_blue_0 Blue Linen Wrists ClothBlue0
70 common.items.armor.hand.cloth_green_0 Green Linen Wrists ClothGreen0
71 common.items.armor.hand.cloth_purple_0 Purple Silk Wrists ClothPurple0
72 common.items.armor.hand.cultist_hands_blue Blue Cultist Gloves CultistBlue
73 common.items.armor.hand.cultist_hands_purple Purple Cultist Gloves CultistPurple
74 common.items.armor.hand.druid Druid's Gloves Druid
75 common.items.armor.hand.leather_0 Swift Gloves Leather0
76 common.items.armor.hand.leather_2 Leather Gloves Leather2
77 common.items.armor.hand.leather_adventurer Agile Gauntlets Leather2
78 common.items.armor.hand.plate_0 Iron Handguards Plate0
79 common.items.armor.hand.steel_0 Steel Gauntlets Steel0
80 common.items.armor.hand.tarasque Tarasque Gauntlets Tarasque
81 common.items.armor.hand.twig Twig Wraps Twig
82 common.items.armor.hand.twigsflowers Flowery Wraps Twigsflowers
83 common.items.armor.hand.twigsleaves Leafy Wraps Twigsleaves
84 common.items.armor.head.assa_mask_0 Dark Assassin Mask AssaMask0
85 common.items.armor.head.leather_0 Swift Leather Cap Leather0
86 common.items.armor.neck.neck_0 Plain Necklace Neck0
87 common.items.armor.neck.neck_1 Gem of lesser Protection Neck1
88 common.items.armor.pants.assassin Assassin Pants Assassin
89 common.items.armor.pants.bonerattler Bonerattler Chausses Bonerattler
90 common.items.armor.pants.cloth_blue_0 Blue Linen Skirt ClothBlue0
91 common.items.armor.pants.cloth_green_0 Green Linen Skirt ClothGreen0
92 common.items.armor.pants.cloth_purple_0 Purple Linen Skirt ClothPurple0
93 common.items.armor.pants.cultist_legs_blue Blue Cultist Skirt CultistBlue
94 common.items.armor.pants.cultist_legs_purple Purple Cultist Skirt CultistPurple
95 common.items.armor.pants.druid Druid's Kilt Druid
96 common.items.armor.pants.hunting Hunting Pants Hunting
97 common.items.armor.pants.leather_0 Swift Pants Leather0
98 common.items.armor.pants.leather_2 Leather Leg Armour Leather2
99 common.items.armor.pants.leather_adventurer Agile Pantalons Leather2
100 common.items.armor.pants.plate_green_0 Iron Legguards PlateGreen0
101 common.items.armor.pants.steel_0 Steel Chausses Steel0
102 common.items.armor.pants.tarasque Tarasque Chausses Tarasque
103 common.items.armor.pants.twig Twig Pants Twig
104 common.items.armor.pants.twigsflowers Flowery Pants Twigsflowers
105 common.items.armor.pants.twigsleaves Leafy Pants Twigsleaves
106 common.items.armor.pants.worker_blue_0 Blue Worker Pants WorkerBlue0
107 common.items.armor.ring.ring_0 Scratched Ring Ring0
108 common.items.armor.shoulder.assassin Assassin Shoulder Guard Assassin
109 common.items.armor.shoulder.bonerattler Bonerattler Shoulder Pad Bonerattler
110 common.items.armor.shoulder.cloth_blue_0 Blue Linen Coat ClothBlue0
111 common.items.armor.shoulder.cloth_blue_1 Blue Cloth Pads ClothBlue1
112 common.items.armor.shoulder.cloth_green_0 Green Linen Coat ClothGreen0
113 common.items.armor.shoulder.cloth_purple_0 Purple Linen Coat ClothPurple0
114 common.items.armor.shoulder.cultist_shoulder_blue Blue Cultist Mantle CultistBlue
115 common.items.armor.shoulder.cultist_shoulder_purple Purple Cultist Mantle CultistPurple
116 common.items.armor.shoulder.druidshoulder Druid Shoulders DruidShoulder
117 common.items.armor.shoulder.iron_spikes Iron Spiked Pauldrons IronSpikes
118 common.items.armor.shoulder.leather_0 Leather Pauldrons Leather0
119 common.items.armor.shoulder.leather_1 Swift Shoulderpads Leather1
120 common.items.armor.shoulder.leather_2 Leather Shoulder Pad Leather2
121 common.items.armor.shoulder.leather_adventurer Agile Guards Leather2
122 common.items.armor.shoulder.leather_iron_0 Iron and Leather Spaulders IronLeather0
123 common.items.armor.shoulder.leather_iron_1 Iron and Leather Spaulders IronLeather1
124 common.items.armor.shoulder.leather_iron_2 Iron and Leather Spaulders IronLeather2
125 common.items.armor.shoulder.leather_iron_3 Iron and Leather Spaulders IronLeather3
126 common.items.armor.shoulder.leather_strips Leather Strips LeatherStrips
127 common.items.armor.shoulder.plate_0 Iron Shoulderguards Plate0
128 common.items.armor.shoulder.steel_0 Steel Shoulder Pad Steel0
129 common.items.armor.shoulder.tarasque Tarasque Shoulder Pad Tarasque
130 common.items.armor.shoulder.twigs Twiggy Shoulders TwiggyShoulder
131 common.items.armor.shoulder.twigsflowers Flowery Shoulders FlowerShoulder
132 common.items.armor.shoulder.twigsleaves Leafy Shoulders LeafyShoulder
133 common.items.armor.starter.lantern Black Lantern Black0
134 common.items.armor.starter.rugged_chest Rugged Shirt Rugged0
135 common.items.armor.starter.rugged_pants Rugged Commoner's Pants Rugged0
136 common.items.armor.starter.sandals_0 Worn out Sandals Sandal0
137 common.items.armor.tabard.admin Admin's Tabard Admin
138 common.items.boss_drops.exp_flask Flask of Velorite Dusk
139 common.items.boss_drops.lantern Magic Lantern Blue0
140 common.items.boss_drops.potions Potent Potion
141 common.items.boss_drops.xp_potion Potion of Skill
142 common.items.consumable.potion_big Large Potion
143 common.items.consumable.potion_med Medium Potion
144 common.items.consumable.potion_minor Minor Potion
145 common.items.crafting_ing.empty_vial Empty Vial
146 common.items.crafting_ing.leather_scraps Leather Scraps
147 common.items.crafting_ing.shiny_gem Shiny Gem
148 common.items.crafting_ing.stones Stones
149 common.items.crafting_ing.twigs Twigs
150 common.items.crafting_tools.craftsman_hammer Craftsman Hammer
151 common.items.crafting_tools.mortar_pestle Mortar and Pestle
152 common.items.debug.admin Admin's Tabard Admin
153 common.items.debug.admin_back Admin's Cape Admin
154 common.items.debug.boost Belzeshrub the Broom-God Boost
155 common.items.debug.cultist_belt Cultist Belt Cultist
156 common.items.debug.cultist_boots Cultist Boots Cultist
157 common.items.debug.cultist_chest_blue Blue Cultist Chest CultistBlue
158 common.items.debug.cultist_hands_blue Blue Cultist Gloves CultistBlue
159 common.items.debug.cultist_legs_blue Blue Cultist Skirt CultistBlue
160 common.items.debug.cultist_purp_2h_boss-0 Admin Greatsword CultPurp0
161 common.items.debug.cultist_shoulder_blue Blue Cultist Mantle CultistBlue
162 common.items.debug.dungeon_purple-0 Purple Admin Cape DungPurp0
163 common.items.debug.possess Belzeshrub the Broom-God Boost
164 common.items.flowers.blue Blue Flower
165 common.items.flowers.pink Pink Flower
166 common.items.flowers.red Red Flower
167 common.items.flowers.sun Sunflower
168 common.items.flowers.white White flower
169 common.items.flowers.yellow Yellow Flower
170 common.items.food.apple Apple
171 common.items.food.apple_mushroom_curry Mushroom Curry
172 common.items.food.apple_stick Apple Stick
173 common.items.food.cheese Dwarven Cheese
174 common.items.food.coconut Coconut
175 common.items.food.mushroom Mushroom
176 common.items.food.mushroom_stick Mushroom Stick
177 common.items.grasses.long Long Grass
178 common.items.grasses.medium Medium Grass
179 common.items.grasses.short Short Grass
180 common.items.lantern.black_0 Black Lantern Black0
181 common.items.lantern.blue_0 Cool Blue Lantern Blue0
182 common.items.lantern.green_0 Lime Zest Lantern Green0
183 common.items.lantern.red_0 Red Lantern Red0
184 common.items.npc_armor.back.dungeon_purple-0 Purple Cultist Cape DungPurp0
185 common.items.npc_armor.belt.cultist_belt Cultist Belt Cultist
186 common.items.npc_armor.chest.cultist_chest_purple Purple Cultist Chest CultistPurple
187 common.items.npc_armor.chest.worker_green_0 Green Worker Shirt WorkerGreen0
188 common.items.npc_armor.chest.worker_green_1 Green Worker Shirt WorkerGreen1
189 common.items.npc_armor.chest.worker_orange_0 Orange Worker Shirt WorkerOrange0
190 common.items.npc_armor.chest.worker_orange_1 Orange Worker Shirt WorkerOrange1
191 common.items.npc_armor.chest.worker_purple_0 Purple Worker Shirt WorkerPurple0
192 common.items.npc_armor.chest.worker_purple_1 Purple Worker Shirt WorkerPurple1
193 common.items.npc_armor.chest.worker_red_0 Red Worker Shirt WorkerRed0
194 common.items.npc_armor.chest.worker_red_1 Red Worker Shirt WorkerRed1
195 common.items.npc_armor.chest.worker_yellow_0 Yellow Worker Shirt WorkerYellow0
196 common.items.npc_armor.chest.worker_yellow_1 Yellow Worker Shirt WorkerYellow1
197 common.items.npc_armor.foot.cultist_boots Cultist Boots Cultist
198 common.items.npc_armor.hand.cultist_hands_purple Purple Cultist Gloves CultistPurple
199 common.items.npc_armor.pants.cultist_legs_purple Purple Cultist Skirt CultistPurple
200 common.items.npc_armor.shoulder.cultist_shoulder_purple Purple Cultist Mantle CultistPurple
201 common.items.npc_weapons.axe.malachite_axe-0 Malachite Axe MalachiteAxe0
202 common.items.npc_weapons.axe.starter_axe Notched Axe BasicAxe
203 common.items.npc_weapons.bow.horn_longbow-0 Horn Bow HornLongbow0
204 common.items.npc_weapons.dagger.starter_dagger Rusty Dagger BasicDagger
205 common.items.npc_weapons.empty.empty Empty
206 common.items.npc_weapons.hammer.cultist_purp_2h-0 Magical Cultist Warhammer CultPurp0
207 common.items.npc_weapons.hammer.starter_hammer Sturdy Old Hammer BasicHammer
208 common.items.npc_weapons.shield.shield_1 A Tattered Targe BasicShield
209 common.items.npc_weapons.staff.bone_staff Bone Staff BoneStaff
210 common.items.npc_weapons.staff.cultist_staff Cultist Staff CultistStaff
211 common.items.npc_weapons.sword.cultist_purp_2h-0 Magical Cultist Greatsword CultPurp0
212 common.items.npc_weapons.sword.cultist_purp_2h_boss-0 Magical Cultist Greatsword CultPurp0
213 common.items.npc_weapons.sword.starter_sword Battered Sword BasicSword
214 common.items.npc_weapons.sword.zweihander_sword_0 Sturdy Zweihander Zweihander0
215 common.items.npc_weapons.tool.broom Broom Broom
216 common.items.npc_weapons.tool.fishing_rod Fishing Rod FishingRod0
217 common.items.npc_weapons.tool.hoe Hoe Hoe0
218 common.items.npc_weapons.tool.pickaxe Pickaxe Pickaxe0
219 common.items.npc_weapons.tool.pitchfork Pitchfork Pitchfork
220 common.items.npc_weapons.tool.rake Rake Rake
221 common.items.npc_weapons.tool.shovel-0 Shovel Shovel0
222 common.items.npc_weapons.tool.shovel-1 Shovel Shovel1
223 common.items.ore.velorite Velorite
224 common.items.ore.veloritefrag Velorite Fragment
225 common.items.testing.test_boots Testing Boots Dark
226 common.items.utility.bomb Bomb
227 common.items.utility.bomb_pile Bomb
228 common.items.utility.collar Collar
229 common.items.utility.firework_blue Firework Blue
230 common.items.utility.firework_green Firework Green
231 common.items.utility.firework_purple Firework Purple
232 common.items.utility.firework_red Firework Red
233 common.items.utility.firework_yellow Firework Yellow
234 common.items.utility.training_dummy Training Dummy
235 common.items.weapons.axe.bloodsteel_axe-0 Bloodsteel Axe BloodsteelAxe0
236 common.items.weapons.axe.bloodsteel_axe-1 Executioner's Axe BloodsteelAxe1
237 common.items.weapons.axe.bloodsteel_axe-2 Tribal Axe BloodsteelAxe2
238 common.items.weapons.axe.bronze_axe-0 Bronze Axe BronzeAxe0
239 common.items.weapons.axe.bronze_axe-1 Discus Axe BronzeAxe1
240 common.items.weapons.axe.cobalt_axe-0 Cobalt Axe CobaltAxe0
241 common.items.weapons.axe.iron_axe-0 Iron Greataxe IronAxe0
242 common.items.weapons.axe.iron_axe-1 Ceremonial Axe IronAxe1
243 common.items.weapons.axe.iron_axe-2 Cyclone Axe IronAxe2
244 common.items.weapons.axe.iron_axe-3 Iron Battleaxe IronAxe3
245 common.items.weapons.axe.iron_axe-4 Butcher's Axe IronAxe4
246 common.items.weapons.axe.iron_axe-5 Barbarian's Axe IronAxe5
247 common.items.weapons.axe.iron_axe-6 Iron Axe IronAxe6
248 common.items.weapons.axe.iron_axe-7 Iron Labrys IronAxe7
249 common.items.weapons.axe.iron_axe-8 Fanged Axe IronAxe8
250 common.items.weapons.axe.iron_axe-9 Wolfen Axe IronAxe9
251 common.items.weapons.axe.malachite_axe-0 Malachite Axe MalachiteAxe0
252 common.items.weapons.axe.orc_axe-0 Beast Cleaver OrcAxe0
253 common.items.weapons.axe.starter_axe Notched Axe BasicAxe
254 common.items.weapons.axe.steel_axe-0 Steel Battleaxe SteelAxe0
255 common.items.weapons.axe.steel_axe-1 Steel Labrys SteelAxe1
256 common.items.weapons.axe.steel_axe-2 Steel Axe SteelAxe2
257 common.items.weapons.axe.steel_axe-3 Crescent Axe SteelAxe3
258 common.items.weapons.axe.steel_axe-4 Moon Axe SteelAxe4
259 common.items.weapons.axe.steel_axe-5 Owl Axe SteelAxe5
260 common.items.weapons.axe.steel_axe-6 Spade Axe SteelAxe6
261 common.items.weapons.axe.worn_iron_axe-0 Worn Dwarven Axe WornIronAxe0
262 common.items.weapons.axe.worn_iron_axe-1 Worn Elven Axe WornIronAxe1
263 common.items.weapons.axe.worn_iron_axe-2 Worn Human Axe WornIronAxe2
264 common.items.weapons.axe.worn_iron_axe-3 Worn Orcish Axe WornIronAxe3
265 common.items.weapons.axe.worn_iron_axe-4 Beetle Axe WornIronAxe4
266 common.items.weapons.bow.horn_longbow-0 Horn Bow HornLongbow0
267 common.items.weapons.bow.iron_longbow-0 Soldier's Bow IronLongbow0
268 common.items.weapons.bow.leafy_longbow-0 Elven Longbow LeafyLongbow0
269 common.items.weapons.bow.leafy_shortbow-0 Elven Shortbow LeafyShortbow0
270 common.items.weapons.bow.nature_ore_longbow-0 Velorite Bow NatureOreLongbow
271 common.items.weapons.bow.rare_longbow Enchanted Longbow RareLongbow
272 common.items.weapons.bow.starter_bow Uneven Bow ShortBow0
273 common.items.weapons.bow.wood_longbow-0 Longbow WoodLongbow0
274 common.items.weapons.bow.wood_longbow-1 Recurve Bow WoodLongbow1
275 common.items.weapons.bow.wood_shortbow-0 Hunting Bow WoodShortbow0
276 common.items.weapons.bow.wood_shortbow-1 Horse Bow WoodShortbow1
277 common.items.weapons.dagger.starter_dagger Rusty Dagger BasicDagger
278 common.items.weapons.empty.empty Empty
279 common.items.weapons.hammer.bronze_hammer-0 Bronze Hammer BronzeHammer0
280 common.items.weapons.hammer.bronze_hammer-1 Bronze Club BronzeHammer1
281 common.items.weapons.hammer.cobalt_hammer-0 Cobalt Hammer CobaltHammer0
282 common.items.weapons.hammer.cobalt_hammer-1 Cobalt Mace CobaltHammer1
283 common.items.weapons.hammer.cultist_purp_2h-0 Magical Cultist Warhammer CultPurp0
284 common.items.weapons.hammer.flimsy_hammer Flimsy Hammer FlimsyHammer
285 common.items.weapons.hammer.hammer_1 Crude Mallet BasicHammer
286 common.items.weapons.hammer.iron_hammer-0 Iron Hammer IronHammer0
287 common.items.weapons.hammer.iron_hammer-1 Iron Battlehammer IronHammer1
288 common.items.weapons.hammer.iron_hammer-2 Iron Mace IronHammer2
289 common.items.weapons.hammer.iron_hammer-3 Crowned Mace IronHammer3
290 common.items.weapons.hammer.iron_hammer-4 Forge Hammer IronHammer4
291 common.items.weapons.hammer.iron_hammer-5 Pike Hammer IronHammer5
292 common.items.weapons.hammer.iron_hammer-6 Spiked Maul IronHammer6
293 common.items.weapons.hammer.iron_hammer-7 Giant's Fist IronHammer7
294 common.items.weapons.hammer.iron_hammer-8 Lucerne Hammer IronHammer8
295 common.items.weapons.hammer.mjolnir Mjolnir Mjolnir
296 common.items.weapons.hammer.ramshead_hammer Ram's Head Mace RamsheadHammer
297 common.items.weapons.hammer.runic_hammer Runic Hammer RunicHammer
298 common.items.weapons.hammer.starter_hammer Sturdy Old Hammer BasicHammer
299 common.items.weapons.hammer.steel_hammer-0 Steel Hammer SteelHammer0
300 common.items.weapons.hammer.steel_hammer-1 Steel Greathammer SteelHammer1
301 common.items.weapons.hammer.steel_hammer-2 Steel Club SteelHammer2
302 common.items.weapons.hammer.steel_hammer-3 Battle Mace SteelHammer3
303 common.items.weapons.hammer.steel_hammer-4 Brute's Hammer SteelHammer4
304 common.items.weapons.hammer.steel_hammer-5 Morning Star SteelHammer5
305 common.items.weapons.hammer.stone_hammer-0 Basalt Sledgehammer StoneHammer0
306 common.items.weapons.hammer.stone_hammer-1 Granite Sledgehammer StoneHammer1
307 common.items.weapons.hammer.stone_hammer-2 Rocky Maul StoneHammer2
308 common.items.weapons.hammer.stone_hammer-3 Stone Sledgehammer StoneHammer3
309 common.items.weapons.hammer.wood_hammer-0 Hardwood Mallet WoodHammer0
310 common.items.weapons.hammer.worn_iron_hammer-0 Worn Dwarven Hammer WornIronHammer0
311 common.items.weapons.hammer.worn_iron_hammer-1 Worn Elven Hammer WornIronHammer1
312 common.items.weapons.hammer.worn_iron_hammer-2 Worn Human Mace WornIronHammer2
313 common.items.weapons.hammer.worn_iron_hammer-3 Worn Orcish Hammer WornIronHammer3
314 common.items.weapons.shield.shield_1 A Tattered Targe BasicShield
315 common.items.weapons.staff.amethyst_staff Amethyst Staff AmethystStaff
316 common.items.weapons.staff.bone_staff Bone Staff BoneStaff
317 common.items.weapons.staff.cultist_staff Cultist Staff CultistStaff
318 common.items.weapons.staff.sceptre_velorite_0 Velorite Sceptre SceptreVelorite
319 common.items.weapons.staff.staff_1 Humble Stick BasicStaff
320 common.items.weapons.staff.staff_nature Sceptre of Regeneration Sceptre
321 common.items.weapons.staff.starter_staff Gnarled Rod BasicStaff
322 common.items.weapons.sword.cultist_purp_2h-0 Magical Cultist Greatsword CultPurp0
323 common.items.weapons.sword.greatsword_2h_dam-0 Damaged Greatsword GreatswordDam0
324 common.items.weapons.sword.greatsword_2h_dam-1 Damaged Greatsword GreatswordDam1
325 common.items.weapons.sword.greatsword_2h_dam-2 Damaged Greatsword GreatswordDam2
326 common.items.weapons.sword.greatsword_2h_fine-0 Fine Greatsword GreatswordFine0
327 common.items.weapons.sword.greatsword_2h_fine-1 Fine Greatsword GreatswordFine1
328 common.items.weapons.sword.greatsword_2h_fine-2 Fine Greatsword GreatswordFine2
329 common.items.weapons.sword.greatsword_2h_orn-0 Ornamented Greatsword GreatswordOrn0
330 common.items.weapons.sword.greatsword_2h_orn-1 Ornamented Greatsword GreatswordOrn1
331 common.items.weapons.sword.greatsword_2h_orn-2 Ornamented Greatsword GreatswordOrn2
332 common.items.weapons.sword.greatsword_2h_simple-0 Simple Greatsword GreatswordSimple0
333 common.items.weapons.sword.greatsword_2h_simple-1 Simple Greatsword GreatswordSimple1
334 common.items.weapons.sword.greatsword_2h_simple-2 Simple Greatsword GreatswordSimple2
335 common.items.weapons.sword.long_2h_dam-0 Damaged Longsword LongDam0
336 common.items.weapons.sword.long_2h_dam-1 Damaged Longsword LongDam1
337 common.items.weapons.sword.long_2h_dam-2 Damaged Longsword LongDam2
338 common.items.weapons.sword.long_2h_dam-3 Damaged Longsword LongDam3
339 common.items.weapons.sword.long_2h_dam-4 Damaged Longsword LongDam4
340 common.items.weapons.sword.long_2h_dam-5 Damaged Longsword LongDam5
341 common.items.weapons.sword.long_2h_fine-0 Fine Longsword LongFine0
342 common.items.weapons.sword.long_2h_fine-1 Fine Longsword LongFine1
343 common.items.weapons.sword.long_2h_fine-2 Fine Longsword LongFine2
344 common.items.weapons.sword.long_2h_fine-3 Fine Longsword LongFine3
345 common.items.weapons.sword.long_2h_fine-4 Fine Longsword LongFine4
346 common.items.weapons.sword.long_2h_fine-5 Fine Longsword LongFine5
347 common.items.weapons.sword.long_2h_orn-0 Ornamented Longsword LongOrn0
348 common.items.weapons.sword.long_2h_orn-1 Ornamented Longsword LongOrn1
349 common.items.weapons.sword.long_2h_orn-2 Ornamented Longsword LongOrn2
350 common.items.weapons.sword.long_2h_orn-3 Ornamented Longsword LongOrn3
351 common.items.weapons.sword.long_2h_orn-4 Ornamented Longsword LongOrn4
352 common.items.weapons.sword.long_2h_orn-5 Ornamented Longsword LongOrn5
353 common.items.weapons.sword.long_2h_simple-0 Simple Longsword LongSimple0
354 common.items.weapons.sword.long_2h_simple-1 Simple Longsword LongSimple1
355 common.items.weapons.sword.long_2h_simple-2 Simple Longsword LongSimple2
356 common.items.weapons.sword.long_2h_simple-3 Simple Longsword LongSimple3
357 common.items.weapons.sword.long_2h_simple-4 Simple Longsword LongSimple4
358 common.items.weapons.sword.long_2h_simple-5 Simple Longsword LongSimple5
359 common.items.weapons.sword.short_sword_0 Vicious Gladius Short0
360 common.items.weapons.sword.starter_sword Battered Sword BasicSword
361 common.items.weapons.sword.wood_sword Forest Spirit WoodTraining
362 common.items.weapons.sword.zweihander_sword_0 Sturdy Zweihander Zweihander0
363 common.items.weapons.tool.broom Broom Broom
364 common.items.weapons.tool.fishing_rod Fishing Rod FishingRod0
365 common.items.weapons.tool.hoe Hoe Hoe0
366 common.items.weapons.tool.pickaxe Pickaxe Pickaxe0
367 common.items.weapons.tool.pitchfork Pitchfork Pitchfork
368 common.items.weapons.tool.rake Rake Rake
369 common.items.weapons.tool.shovel-0 Shovel Shovel0
370 common.items.weapons.tool.shovel-1 Shovel Shovel1

View File

@ -1120,6 +1120,7 @@ fn handle_explosion(
owner: ecs.read_storage::<Uid>().get(target).copied(),
friendly_damage: true,
reagent: None,
percent_damage: 1.0,
})
},
None => server.notify_client(

View File

@ -2,8 +2,8 @@ use crate::{sys, Server, StateExt};
use common::{
character::CharacterId,
comp::{
self, humanoid::DEFAULT_HUMANOID_EYE_HEIGHT, shockwave, Agent, Alignment, Body, Gravity,
Item, ItemDrop, LightEmitter, Loadout, Ori, Pos, Projectile, Scale, Stats, Vel,
self, beam, humanoid::DEFAULT_HUMANOID_EYE_HEIGHT, shockwave, Agent, Alignment, Body,
Gravity, Item, ItemDrop, LightEmitter, Loadout, Ori, Pos, Projectile, Scale, Stats, Vel,
WaypointArea,
},
outcome::Outcome,
@ -136,6 +136,11 @@ pub fn handle_shockwave(
state.create_shockwave(properties, pos, ori).build();
}
pub fn handle_beam(server: &mut Server, properties: beam::Properties, pos: Pos, ori: Ori) {
let state = server.state_mut();
state.create_beam(properties, pos, ori).build();
}
pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
server
.state

View File

@ -138,10 +138,33 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
KillSource::NonPlayer("<?>".to_string(), KillType::Explosion)
}
},
HealthSource::Energy { owner: Some(by) } => {
// Get energy owner entity
if let Some(char_entity) = state.ecs().entity_from_uid(by.into()) {
// Check if attacker is another player or entity with stats (npc)
if state
.ecs()
.read_storage::<Player>()
.get(char_entity)
.is_some()
{
KillSource::Player(by, KillType::Energy)
} else if let Some(stats) =
state.ecs().read_storage::<Stats>().get(char_entity)
{
KillSource::NonPlayer(stats.name.clone(), KillType::Energy)
} else {
KillSource::NonPlayer("<?>".to_string(), KillType::Energy)
}
} else {
KillSource::NonPlayer("<?>".to_string(), KillType::Energy)
}
},
HealthSource::World => KillSource::FallDamage,
HealthSource::Suicide => KillSource::Suicide,
HealthSource::Projectile { owner: None }
| HealthSource::Explosion { owner: None }
| HealthSource::Energy { owner: None }
| HealthSource::Revive
| HealthSource::Command
| HealthSource::LevelUp
@ -158,8 +181,10 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
// Give EXP to the killer if entity had stats
(|| {
let mut stats = state.ecs().write_storage::<Stats>();
let by = if let HealthSource::Attack { by } | HealthSource::Projectile { owner: Some(by) } =
cause
let by = if let HealthSource::Attack { by }
| HealthSource::Projectile { owner: Some(by) }
| HealthSource::Energy { owner: Some(by) }
| HealthSource::Explosion { owner: Some(by) } = cause
{
by
} else {
@ -450,6 +475,7 @@ pub fn handle_explosion(
owner: Option<Uid>,
friendly_damage: bool,
reagent: Option<Reagent>,
percent_damage: f32,
) {
// Go through all other entities
let hit_range = 3.0 * power;
@ -461,6 +487,7 @@ pub fn handle_explosion(
pos,
power,
reagent,
percent_damage,
});
let owner_entity = owner.and_then(|uid| {
ecs.read_resource::<UidAllocator>()
@ -483,18 +510,40 @@ pub fn handle_explosion(
if !stats_b.is_dead
// RADIUS
&& distance_squared < hit_range.powi(2)
// Skip if they are in the same group and friendly_damage is turned off for the
// explosion
&& (friendly_damage || !owner_entity
.and_then(|e| groups.get(e))
.map_or(false, |group_a| Some(group_a) == groups.get(entity_b)))
{
// See if entities are in the same group
let mut same_group = owner_entity
.and_then(|e| groups.get(e))
.map_or(false, |group_a| Some(group_a) == groups.get(entity_b));
if let Some(entity) = owner_entity {
if entity == entity_b {
same_group = true;
}
}
// Don't heal if outside group
// Don't damage in the same group
let is_damage = (friendly_damage || !same_group) && (percent_damage > 0.0);
let is_heal = same_group && (percent_damage < 1.0);
if !is_heal && !is_damage {
continue;
}
// Weapon gives base damage
let dmg = (1.0 - distance_squared / hit_range.powi(2)) * power * 130.0;
let source = if is_heal {
DamageSource::Healing
} else {
DamageSource::Explosion
};
let strength = (1.0 - distance_squared / hit_range.powi(2)) * power * 130.0;
let healthchange = if is_heal {
strength * (1.0 - percent_damage)
} else {
-strength * percent_damage
};
let mut damage = Damage {
healthchange: -dmg,
source: DamageSource::Explosion,
healthchange,
source,
};
let block = character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
@ -504,15 +553,15 @@ pub fn handle_explosion(
damage.modify_damage(block, loadout);
}
if damage.healthchange < 0.0 {
if damage.healthchange != 0.0 {
let cause = if is_heal {
HealthSource::Healing { by: owner }
} else {
HealthSource::Explosion { owner }
};
stats_b.health.change_by(HealthChange {
amount: damage.healthchange as i32,
cause: HealthSource::Explosion { owner },
});
} else if damage.healthchange > 0.0 {
stats_b.health.change_by(HealthChange {
amount: damage.healthchange as i32,
cause: HealthSource::Healing { by: owner },
cause,
});
}
}
@ -520,64 +569,66 @@ pub fn handle_explosion(
const RAYS: usize = 500;
// Color terrain
let mut touched_blocks = Vec::new();
let color_range = power * 2.7;
for _ in 0..RAYS {
let dir = Vec3::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
)
.normalized();
if percent_damage > 0.9 {
// Color terrain
let mut touched_blocks = Vec::new();
let color_range = power * 2.7;
for _ in 0..RAYS {
let dir = Vec3::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
)
.normalized();
let _ = ecs
.read_resource::<TerrainGrid>()
.ray(pos, pos + dir * color_range)
// TODO: Faster RNG
.until(|_| rand::random::<f32>() < 0.05)
.for_each(|_: &Block, pos| touched_blocks.push(pos))
.cast();
}
let terrain = ecs.read_resource::<TerrainGrid>();
let mut block_change = ecs.write_resource::<BlockChange>();
for block_pos in touched_blocks {
if let Ok(block) = terrain.get(block_pos) {
let diff2 = block_pos.map(|b| b as f32).distance_squared(pos);
let fade = (1.0 - diff2 / color_range.powi(2)).max(0.0);
if let Some(mut color) = block.get_color() {
let r = color[0] as f32 + (fade * (color[0] as f32 * 0.5 - color[0] as f32));
let g = color[1] as f32 + (fade * (color[1] as f32 * 0.3 - color[1] as f32));
let b = color[2] as f32 + (fade * (color[2] as f32 * 0.3 - color[2] as f32));
color[0] = r as u8;
color[1] = g as u8;
color[2] = b as u8;
block_change.set(block_pos, Block::new(block.kind(), color));
}
let _ = ecs
.read_resource::<TerrainGrid>()
.ray(pos, pos + dir * color_range)
// TODO: Faster RNG
.until(|_| rand::random::<f32>() < 0.05)
.for_each(|_: &Block, pos| touched_blocks.push(pos))
.cast();
}
}
// Destroy terrain
for _ in 0..RAYS {
let dir = Vec3::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.15,
)
.normalized();
let terrain = ecs.read_resource::<TerrainGrid>();
let _ = terrain
.ray(pos, pos + dir * power)
// TODO: Faster RNG
.until(|block| block.is_liquid() || rand::random::<f32>() < 0.05)
.for_each(|block: &Block, pos| {
if block.is_explodable() {
block_change.set(pos, block.into_vacant());
let mut block_change = ecs.write_resource::<BlockChange>();
for block_pos in touched_blocks {
if let Ok(block) = terrain.get(block_pos) {
let diff2 = block_pos.map(|b| b as f32).distance_squared(pos);
let fade = (1.0 - diff2 / color_range.powi(2)).max(0.0);
if let Some(mut color) = block.get_color() {
let r = color[0] as f32 + (fade * (color[0] as f32 * 0.5 - color[0] as f32));
let g = color[1] as f32 + (fade * (color[1] as f32 * 0.3 - color[1] as f32));
let b = color[2] as f32 + (fade * (color[2] as f32 * 0.3 - color[2] as f32));
color[0] = r as u8;
color[1] = g as u8;
color[2] = b as u8;
block_change.set(block_pos, Block::new(block.kind(), color));
}
})
.cast();
}
}
// Destroy terrain
for _ in 0..RAYS {
let dir = Vec3::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.15,
)
.normalized();
let terrain = ecs.read_resource::<TerrainGrid>();
let _ = terrain
.ray(pos, pos + dir * power)
// TODO: Faster RNG
.until(|block| block.is_liquid() || rand::random::<f32>() < 0.05)
.for_each(|block: &Block, pos| {
if block.is_explodable() {
block_change.set(pos, block.into_vacant());
}
})
.cast();
}
}
}

View File

@ -4,7 +4,7 @@ use common::{
span,
};
use entity_creation::{
handle_create_npc, handle_create_waypoint, handle_initialize_character,
handle_beam, handle_create_npc, handle_create_waypoint, handle_initialize_character,
handle_loaded_character_data, handle_shockwave, handle_shoot,
};
use entity_manipulation::{
@ -60,7 +60,16 @@ impl Server {
owner,
friendly_damage,
reagent,
} => handle_explosion(&self, pos, power, owner, friendly_damage, reagent),
percent_damage,
} => handle_explosion(
&self,
pos,
power,
owner,
friendly_damage,
reagent,
percent_damage,
),
ServerEvent::Shoot {
entity,
dir,
@ -75,6 +84,11 @@ impl Server {
pos,
ori,
} => handle_shockwave(self, properties, pos, ori),
ServerEvent::BeamSegment {
properties,
pos,
ori,
} => handle_beam(self, properties, pos, ori),
ServerEvent::Knockback { entity, impulse } => {
handle_knockback(&self, entity, impulse)
},

View File

@ -0,0 +1,6 @@
-- This file should undo anything in `up.sql`
UPDATE item
SET item_definition_id = 'common.items.weapons.staff.sceptre_velorite_0' WHERE item_definition_id = 'common.items.weapons.sceptre.sceptre_velorite_0';
UPDATE item
SET item_definition_id = 'common.items.weapons.staff.staff_nature' WHERE item_definition_id = 'common.items.weapons.sceptre.staff_nature';

View File

@ -0,0 +1,6 @@
-- Changes filepaths of sceptres
UPDATE item
SET item_definition_id = 'common.items.weapons.sceptre.sceptre_velorite_0' WHERE item_definition_id = 'common.items.weapons.staff.sceptre_velorite_0';
UPDATE item
SET item_definition_id = 'common.items.weapons.sceptre.staff_nature' WHERE item_definition_id = 'common.items.weapons.staff.staff_nature';

View File

@ -45,6 +45,13 @@ pub trait StateExt {
pos: comp::Pos,
ori: comp::Ori,
) -> EcsEntityBuilder;
/// Build a beam entity
fn create_beam(
&mut self,
properties: comp::beam::Properties,
pos: comp::Pos,
ori: comp::Ori,
) -> EcsEntityBuilder;
/// Insert common/default components for a new character joining the server
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: CharacterId);
/// Update the components associated with the entity's current character.
@ -156,6 +163,22 @@ impl StateExt for State {
})
}
fn create_beam(
&mut self,
properties: comp::beam::Properties,
pos: comp::Pos,
ori: comp::Ori,
) -> EcsEntityBuilder {
self.ecs_mut()
.create_entity_synced()
.with(pos)
.with(ori)
.with(comp::BeamSegment {
properties,
creation: None,
})
}
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: CharacterId) {
let spawn_point = self.ecs().read_resource::<SpawnPoint>().0;

View File

@ -50,6 +50,7 @@ impl<'a> System<'a> for Sys {
owner: *owner,
friendly_damage: true,
reagent: None,
percent_damage: 1.0,
});
}
},
@ -65,6 +66,7 @@ impl<'a> System<'a> for Sys {
owner: *owner,
friendly_damage: true,
reagent: Some(*reagent),
percent_damage: 1.0,
});
}
},

View File

@ -1,9 +1,9 @@
use super::SysTimer;
use common::{
comp::{
Body, CanBuild, CharacterState, Collider, Energy, Gravity, Group, Item, LightEmitter,
Loadout, Mass, MountState, Mounting, Ori, Player, Pos, Scale, Shockwave, Stats, Sticky,
Vel,
BeamSegment, Body, CanBuild, CharacterState, Collider, Energy, Gravity, Group, Item,
LightEmitter, Loadout, Mass, MountState, Mounting, Ori, Player, Pos, Scale, Shockwave,
Stats, Sticky, Vel,
},
msg::EcsCompPacket,
span,
@ -59,6 +59,7 @@ pub struct TrackedComps<'a> {
pub loadout: ReadStorage<'a, Loadout>,
pub character_state: ReadStorage<'a, CharacterState>,
pub shockwave: ReadStorage<'a, Shockwave>,
pub beam_segment: ReadStorage<'a, BeamSegment>,
}
impl<'a> TrackedComps<'a> {
pub fn create_entity_package(
@ -138,7 +139,10 @@ impl<'a> TrackedComps<'a> {
.get(entity)
.cloned()
.map(|c| comps.push(c.into()));
// Add untracked comps
self.beam_segment
.get(entity)
.cloned()
.map(|c| comps.push(c.into()));
// Add untracked comps
pos.map(|c| comps.push(c.into()));
vel.map(|c| comps.push(c.into()));
@ -168,6 +172,7 @@ pub struct ReadTrackers<'a> {
pub loadout: ReadExpect<'a, UpdateTracker<Loadout>>,
pub character_state: ReadExpect<'a, UpdateTracker<CharacterState>>,
pub shockwave: ReadExpect<'a, UpdateTracker<Shockwave>>,
pub beam_segment: ReadExpect<'a, UpdateTracker<BeamSegment>>,
}
impl<'a> ReadTrackers<'a> {
pub fn create_sync_packages(
@ -206,7 +211,8 @@ impl<'a> ReadTrackers<'a> {
&comps.character_state,
filter,
)
.with_component(&comps.uid, &*self.shockwave, &comps.shockwave, filter);
.with_component(&comps.uid, &*self.shockwave, &comps.shockwave, filter)
.with_component(&comps.uid, &*self.beam_segment, &comps.beam_segment, filter);
(entity_sync_package, comp_sync_package)
}
@ -233,6 +239,7 @@ pub struct WriteTrackers<'a> {
loadout: WriteExpect<'a, UpdateTracker<Loadout>>,
character_state: WriteExpect<'a, UpdateTracker<CharacterState>>,
shockwave: WriteExpect<'a, UpdateTracker<Shockwave>>,
beam: WriteExpect<'a, UpdateTracker<BeamSegment>>,
}
fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
@ -258,6 +265,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
.character_state
.record_changes(&comps.character_state);
trackers.shockwave.record_changes(&comps.shockwave);
trackers.beam.record_changes(&comps.beam_segment);
// Debug how many updates are being sent
/*
macro_rules! log_counts {
@ -290,6 +298,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
log_counts!(loadout, "Loadouts");
log_counts!(character_state, "Character States");
log_counts!(shockwave, "Shockwaves");
log_counts!(beam, "Beams");
*/
}
@ -313,6 +322,7 @@ pub fn register_trackers(world: &mut World) {
world.register_tracker::<Loadout>();
world.register_tracker::<CharacterState>();
world.register_tracker::<Shockwave>();
world.register_tracker::<BeamSegment>();
}
/// Deleted entities grouped by region

View File

@ -78,6 +78,7 @@ fn get_tool_kind(kind: &ToolKind) -> String {
ToolKind::Bow(_) => "Bow".to_string(),
ToolKind::Dagger(_) => "Dagger".to_string(),
ToolKind::Staff(_) => "Staff".to_string(),
ToolKind::Sceptre(_) => "Sceptre".to_string(),
ToolKind::Shield(_) => "Shield".to_string(),
ToolKind::Debug(_) => "Debug".to_string(),
ToolKind::Farming(_) => "Farming".to_string(),
@ -94,6 +95,7 @@ fn get_tool_kind_kind(kind: &ToolKind) -> String {
ToolKind::Bow(x) => x.clone(),
ToolKind::Dagger(x) => x.clone(),
ToolKind::Staff(x) => x.clone(),
ToolKind::Sceptre(x) => x.clone(),
ToolKind::Shield(x) => x.clone(),
ToolKind::Debug(x) => x.clone(),
ToolKind::Farming(x) => x.clone(),

View File

@ -373,7 +373,7 @@ impl Animation for AlphaAnimation {
next.torso.orientation = Quaternion::rotation_z(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
},
Some(ToolKind::Staff(_)) => {
Some(ToolKind::Staff(_)) | Some(ToolKind::Sceptre(_)) => {
next.head.orientation =
Quaternion::rotation_x(staff * 0.2) * Quaternion::rotation_z(staff * 0.2);
next.l_hand.position = Vec3::new(11.0, 5.0, -4.0);

View File

@ -127,7 +127,7 @@ impl Animation for BlockAnimation {
* Quaternion::rotation_z(-0.85);
next.main.scale = Vec3::one();
},
Some(ToolKind::Staff(_)) => {
Some(ToolKind::Staff(_)) | Some(ToolKind::Sceptre(_)) => {
next.l_hand.position = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0,
3.5 + wave_ultra_slow_cos * 0.5,

View File

@ -97,7 +97,7 @@ impl Animation for ChargeAnimation {
match active_tool_kind {
//TODO: Inventory
Some(ToolKind::Staff(_)) => {
Some(ToolKind::Staff(_)) | Some(ToolKind::Sceptre(_)) => {
next.l_hand.position = Vec3::new(11.0, 5.0, -4.0);
next.l_hand.orientation = Quaternion::rotation_x(1.27);
next.l_hand.scale = Vec3::one() * 1.05;

View File

@ -180,6 +180,7 @@ impl Animation for DashAnimation {
Quaternion::rotation_x(-1.5) * Quaternion::rotation_y(-1.0);
next.control.scale = Vec3::one();
},
_ => {},
}
}
},

View File

@ -103,7 +103,7 @@ impl Animation for EquipAnimation {
Quaternion::rotation_x(0.0) * Quaternion::rotation_y(1.35 + 2.5);
next.control.scale = Vec3::one();
},
Some(ToolKind::Staff(_)) => {
Some(ToolKind::Staff(_)) | Some(ToolKind::Sceptre(_)) => {
next.l_hand.position = Vec3::new(1.0, -2.0, -5.0);
next.l_hand.orientation =
Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.3);

View File

@ -65,7 +65,7 @@ impl Animation for ShootAnimation {
match active_tool_kind {
//TODO: Inventory
Some(ToolKind::Staff(_)) => {
Some(ToolKind::Staff(_)) | Some(ToolKind::Sceptre(_)) => {
next.l_hand.position = Vec3::new(11.0, 5.0, -4.0);
next.l_hand.orientation =
Quaternion::rotation_x(1.27) * Quaternion::rotation_y(0.0);

View File

@ -277,7 +277,7 @@ impl Animation for SwimWieldAnimation {
* Quaternion::rotation_z(u_slowalt * 0.08);
next.control.scale = Vec3::one();
},
Some(ToolKind::Staff(_)) => {
Some(ToolKind::Staff(_)) | Some(ToolKind::Sceptre(_)) => {
next.l_hand.position = Vec3::new(1.5, 0.5, -4.0);
next.l_hand.orientation =
Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.3);

View File

@ -228,7 +228,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_z(u_slowalt * 0.08);
next.control.scale = Vec3::one();
},
Some(ToolKind::Staff(_)) => {
Some(ToolKind::Staff(_)) | Some(ToolKind::Sceptre(_)) => {
next.l_hand.position = Vec3::new(11.0, 5.0, -4.0);
next.l_hand.orientation =
Quaternion::rotation_x(1.27) * Quaternion::rotation_y(0.0);

View File

@ -72,7 +72,11 @@ impl<'a> System<'a> for Sys {
// (maybe health changes could be sent to the client as a list
// of events)
if match health.last_change.1.cause {
HealthSource::Attack { by } | HealthSource::Projectile { owner: Some(by) } => {
HealthSource::Attack { by }
| HealthSource::Projectile { owner: Some(by) }
| HealthSource::Energy { owner: Some(by) }
| HealthSource::Explosion { owner: Some(by) }
| HealthSource::Healing { by: Some(by) } => {
let by_me = my_uid.map_or(false, |&uid| by == uid);
// If the attack was by me also reset this timer
if by_me {

View File

@ -369,6 +369,10 @@ impl<'a> Widget for Chat<'a> {
.localized_strings
.get("hud.chat.pvp_explosion_kill_msg")
.to_string(),
KillSource::Player(_, KillType::Energy) => self
.localized_strings
.get("hud.chat.pvp_energy_kill_msg")
.to_string(),
KillSource::NonPlayer(_, KillType::Melee) => self
.localized_strings
.get("hud.chat.npc_melee_kill_msg")
@ -381,6 +385,10 @@ impl<'a> Widget for Chat<'a> {
.localized_strings
.get("hud.chat.npc_explosion_kill_msg")
.to_string(),
KillSource::NonPlayer(_, KillType::Energy) => self
.localized_strings
.get("hud.chat.npc_energy_kill_msg")
.to_string(),
KillSource::Environment(_) => self
.localized_strings
.get("hud.chat.environmental_kill_msg")

View File

@ -77,12 +77,11 @@ impl State {
.filter(|kind| {
use common::comp::item::{tool::ToolKind, ItemKind};
if let ItemKind::Tool(kind) = kind {
if let ToolKind::Staff(kind) = &kind.kind {
kind != "Sceptre" && kind != "SceptreVelorite"
} else if let ToolKind::Debug(kind) = &kind.kind {
kind == "Boost"
} else {
matches!(&kind.kind, ToolKind::Sword(_))
match &kind.kind {
ToolKind::Staff(_) => true,
ToolKind::Debug(kind) => kind == "Boost",
ToolKind::Sword(_) => true,
_ => false,
}
} else {
false

View File

@ -268,6 +268,7 @@ image_ids! {
snake_arrow_0: "voxygen.element.icons.snake",
heal_0: "voxygen.element.icons.heal_0",
sword_whirlwind: "voxygen.element.icons.sword_whirlwind",
heal_bomb: "voxygen.element.icons.heal_bomb",
// Buttons
button: "voxygen.element.buttons.button",

View File

@ -914,22 +914,41 @@ impl Hud {
let hp_fade = ((crate::ecs::sys::floater::MY_HP_SHOWTIME - floater.timer)
* 0.25)
+ 0.2;
Text::new(&format!("{}", (floater.hp_change / 10).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, hp_fade))
.x_y(x, y - 3.0)
.set(player_sct_bg_id, ui_widgets);
Text::new(&format!("{}", (floater.hp_change / 10).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.hp_change < 0 {
Color::Rgba(1.0, 0.1, 0.0, hp_fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, hp_fade)
})
.x_y(x, y)
.set(player_sct_id, ui_widgets);
if floater.hp_change.abs() > 10 {
Text::new(&format!("{}", (floater.hp_change / 10).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, hp_fade))
.x_y(x, y - 3.0)
.set(player_sct_bg_id, ui_widgets);
Text::new(&format!("{}", (floater.hp_change / 10).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.hp_change < 0 {
Color::Rgba(1.0, 0.1, 0.0, hp_fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, hp_fade)
})
.x_y(x, y)
.set(player_sct_id, ui_widgets);
} else {
Text::new(&format!("{}", (floater.hp_change as f32 / 10.0).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, hp_fade))
.x_y(x, y - 3.0)
.set(player_sct_bg_id, ui_widgets);
Text::new(&format!("{}", (floater.hp_change as f32 / 10.0).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.hp_change < 0 {
Color::Rgba(1.0, 0.1, 0.0, hp_fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, hp_fade)
})
.x_y(x, y)
.set(player_sct_id, ui_widgets);
}
}
}
// EXP Numbers
@ -1236,25 +1255,48 @@ impl Hud {
+ 100.0;
// Timer sets text transparency
let fade = ((crate::ecs::sys::floater::HP_SHOWTIME - timer) * 0.25) + 0.2;
if hp_damage.abs() < 10 {
// Damage and heal below 10/10 are shown as decimals
Text::new(&format!("{}", hp_damage.abs() as f32 / 10.0))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.x_y(0.0, y - 3.0)
.position_ingame(ingame_pos)
.set(sct_bg_id, ui_widgets);
Text::new(&format!("{}", hp_damage.abs() as f32 / 10.0))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.x_y(0.0, y)
.color(if hp_damage < 0 {
Color::Rgba(font_col.r, font_col.g, font_col.b, fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, fade)
})
.position_ingame(ingame_pos)
.set(sct_id, ui_widgets);
} else {
// Damage and heal above 10/10 are shown rounded
Text::new(&format!("{}", hp_dmg_rounded_abs))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.x_y(0.0, y - 3.0)
.position_ingame(ingame_pos)
.set(sct_bg_id, ui_widgets);
Text::new(&format!("{}", hp_dmg_rounded_abs))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.x_y(0.0, y - 3.0)
.position_ingame(ingame_pos)
.set(sct_bg_id, ui_widgets);
Text::new(&format!("{}", hp_dmg_rounded_abs))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.x_y(0.0, y)
.color(if hp_damage < 0 {
Color::Rgba(font_col.r, font_col.g, font_col.b, fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, fade)
})
.position_ingame(ingame_pos)
.set(sct_id, ui_widgets);
Text::new(&format!("{}", hp_dmg_rounded_abs))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.x_y(0.0, y)
.color(if hp_damage < 0 {
Color::Rgba(font_col.r, font_col.g, font_col.b, fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, fade)
})
.position_ingame(ingame_pos)
.set(sct_id, ui_widgets);
};
} else {
for floater in floaters {
let number_speed = 250.0; // Single Numbers Speed
@ -1284,29 +1326,55 @@ impl Hud {
let fade = ((crate::ecs::sys::floater::HP_SHOWTIME - floater.timer)
* 0.25)
+ 0.2;
Text::new(&format!("{}", (floater.hp_change / 10).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.hp_change < 0 {
Color::Rgba(0.0, 0.0, 0.0, fade)
} else {
Color::Rgba(0.0, 0.0, 0.0, 1.0)
})
.x_y(0.0, y - 3.0)
.position_ingame(ingame_pos)
.set(sct_bg_id, ui_widgets);
Text::new(&format!("{}", (floater.hp_change / 10).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.x_y(0.0, y)
.color(if floater.hp_change < 0 {
Color::Rgba(font_col.r, font_col.g, font_col.b, fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, 1.0)
})
.position_ingame(ingame_pos)
.set(sct_id, ui_widgets);
if floater.hp_change.abs() < 10 {
// Damage and heal below 10/10 are shown as decimals
Text::new(&format!("{}", (floater.hp_change.abs() as f32 / 10.0)))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.hp_change < 0 {
Color::Rgba(0.0, 0.0, 0.0, fade)
} else {
Color::Rgba(0.0, 0.0, 0.0, 1.0)
})
.x_y(0.0, y - 3.0)
.position_ingame(ingame_pos)
.set(sct_bg_id, ui_widgets);
Text::new(&format!("{}", (floater.hp_change.abs() as f32 / 10.0)))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.x_y(0.0, y)
.color(if floater.hp_change < 0 {
Color::Rgba(font_col.r, font_col.g, font_col.b, fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, 1.0)
})
.position_ingame(ingame_pos)
.set(sct_id, ui_widgets);
} else {
// Damage and heal above 10/10 are shown rounded
Text::new(&format!("{}", (floater.hp_change / 10).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.hp_change < 0 {
Color::Rgba(0.0, 0.0, 0.0, fade)
} else {
Color::Rgba(0.0, 0.0, 0.0, 1.0)
})
.x_y(0.0, y - 3.0)
.position_ingame(ingame_pos)
.set(sct_bg_id, ui_widgets);
Text::new(&format!("{}", (floater.hp_change / 10).abs()))
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.x_y(0.0, y)
.color(if floater.hp_change < 0 {
Color::Rgba(font_col.r, font_col.g, font_col.b, fade)
} else {
Color::Rgba(0.1, 1.0, 0.1, 1.0)
})
.position_ingame(ingame_pos)
.set(sct_id, ui_widgets);
}
}
}
}

View File

@ -620,6 +620,7 @@ impl<'a> Widget for Skillbar<'a> {
ToolKind::Hammer(_) => self.imgs.twohhammer_m1,
ToolKind::Axe(_) => self.imgs.twohaxe_m1,
ToolKind::Bow(_) => self.imgs.bow_m1,
ToolKind::Sceptre(_) => self.imgs.heal_0,
ToolKind::Staff(_) => self.imgs.staff_m1,
ToolKind::Debug(kind) => match kind.as_ref() {
"Boost" => self.imgs.flyingrod_m1,
@ -698,11 +699,8 @@ impl<'a> Widget for Skillbar<'a> {
Some(ToolKind::Hammer(_)) => self.imgs.hammerleap,
Some(ToolKind::Axe(_)) => self.imgs.axespin,
Some(ToolKind::Bow(_)) => self.imgs.bow_m2,
Some(ToolKind::Staff(kind)) => match kind.as_ref() {
"Sceptre" => self.imgs.heal_0,
"SceptreVelorite" => self.imgs.heal_0,
_ => self.imgs.staff_m2,
},
Some(ToolKind::Sceptre(_)) => self.imgs.heal_bomb,
Some(ToolKind::Staff(_)) => self.imgs.staff_m2,
Some(ToolKind::Debug(kind)) => match kind.as_ref() {
"Boost" => self.imgs.flyingrod_m2,
_ => self.imgs.nothing,
@ -719,22 +717,12 @@ impl<'a> Widget for Skillbar<'a> {
Color::Rgba(0.3, 0.3, 0.3, 0.8)
}
},
Some(ToolKind::Staff(kind)) => match kind.as_ref() {
"Sceptre" => {
if self.energy.current() as f64 >= 400.0 {
Color::Rgba(1.0, 1.0, 1.0, 1.0)
} else {
Color::Rgba(0.3, 0.3, 0.3, 0.8)
}
},
"SceptreVelorite" => {
if self.energy.current() as f64 >= 400.0 {
Color::Rgba(1.0, 1.0, 1.0, 1.0)
} else {
Color::Rgba(0.3, 0.3, 0.3, 0.8)
}
},
_ => Color::Rgba(1.0, 1.0, 1.0, 1.0),
Some(ToolKind::Sceptre(_)) => {
if self.energy.current() as f64 >= 400.0 {
Color::Rgba(1.0, 1.0, 1.0, 1.0)
} else {
Color::Rgba(0.3, 0.3, 0.3, 0.8)
}
},
_ => Color::Rgba(1.0, 1.0, 1.0, 1.0),
})

View File

@ -75,6 +75,7 @@ fn tool_desc(tool: &Tool, desc: &str) -> String {
ToolKind::Bow(_) => "Bow",
ToolKind::Dagger(_) => "Dagger",
ToolKind::Staff(_) => "Staff",
ToolKind::Sceptre(_) => "Sceptre",
ToolKind::Shield(_) => "Shield",
ToolKind::NpcWeapon(_) => "Npc Weapon",
ToolKind::Debug(_) => "Debug",

View File

@ -35,7 +35,8 @@ const STARTER_AXE: &str = "common.items.weapons.axe.starter_axe";
const STARTER_STAFF: &str = "common.items.weapons.staff.starter_staff";
const STARTER_SWORD: &str = "common.items.weapons.sword.starter_sword";
const STARTER_DAGGER: &str = "common.items.weapons.dagger.starter_dagger";
//const STARTER_SCEPTRE: &str = "common.items.weapons.dagger.starter_dagger";
//const STARTER_SCEPTRE: &str = "common.items.weapons.sceptre.starter_sceptre";
// // Use in future MR to make this a starter weapon
// UI Color-Theme
const UI_MAIN: Color = Color::Rgba(0.61, 0.70, 0.70, 1.0); // Greenish Blue

View File

@ -35,6 +35,9 @@ gfx_defines! {
// can save 32 bits per instance, and have cleaner tailor made code.
inst_mode: i32 = "inst_mode",
// A direction for particles to move in
inst_dir: [f32; 3] = "inst_dir",
// a triangle is: f32 x 3 x 3 x 1 = 288 bits
// a quad is: f32 x 3 x 3 x 2 = 576 bits
// a cube is: f32 x 3 x 3 x 12 = 3456 bits
@ -106,6 +109,8 @@ pub enum ParticleMode {
Firefly = 10,
Bee = 11,
GroundShockwave = 12,
HealingBeam = 13,
EnergyNature = 14,
}
impl ParticleMode {
@ -126,6 +131,25 @@ impl Instance {
inst_entropy: rand::thread_rng().gen(),
inst_mode: inst_mode as i32,
inst_pos: inst_pos.into_array(),
inst_dir: [0.0, 0.0, 0.0],
}
}
pub fn new_beam(
inst_time: f64,
lifespan: f32,
inst_mode: ParticleMode,
inst_pos: Vec3<f32>,
inst_pos2: Vec3<f32>,
) -> Self {
use rand::Rng;
Self {
inst_time: inst_time as f32,
inst_lifespan: lifespan,
inst_entropy: rand::thread_rng().gen(),
inst_mode: inst_mode as i32,
inst_pos: inst_pos.into_array(),
inst_dir: (inst_pos2 - inst_pos).into_array(),
}
}
}

View File

@ -3588,6 +3588,7 @@ fn mesh_object(obj: &object::Body) -> BoneMeshes {
Body::BoltFireBig => ("weapon.projectile.fire-bolt-1", Vec3::new(-6.0, -6.0, -6.0)),
Body::TrainingDummy => ("object.training_dummy", Vec3::new(-7.0, -5.0, 0.0)),
Body::MultiArrow => ("weapon.projectile.multi-arrow", Vec3::new(-4.0, -9.5, -5.0)),
Body::BoltNature => ("weapon.projectile.nature-bolt", Vec3::new(-6.0, -6.0, -6.0)),
};
load_mesh(name, offset)
}

View File

@ -913,6 +913,7 @@ impl FigureMgr {
StageSection::Recover => {
stage_time / s.static_data.recover_duration.as_secs_f64()
},
_ => 0.0,
};
anim::character::DashAnimation::update_skeleton(
&target_base,
@ -972,6 +973,22 @@ impl FigureMgr {
skeleton_attr,
)
},
CharacterState::BasicBeam(_) => {
anim::character::ChargeAnimation::update_skeleton(
&target_base,
(
active_tool_kind,
second_tool_kind,
vel.0.magnitude(),
ori,
state.last_ori,
time,
),
state.state_time,
&mut state_animation_rate,
skeleton_attr,
)
},
CharacterState::ComboMelee(s) => {
let stage_index = (s.stage - 1) as usize;
let stage_time = s.timer.as_secs_f64();

View File

@ -390,6 +390,7 @@ impl Scene {
pos,
power,
reagent,
percent_damage,
} => self.event_lights.push(EventLight {
light: Light::new(
*pos,
@ -399,7 +400,13 @@ impl Scene {
Some(Reagent::Purple) => Rgb::new(0.7, 0.0, 1.0),
Some(Reagent::Red) => Rgb::new(1.0, 0.0, 0.0),
Some(Reagent::Yellow) => Rgb::new(1.0, 1.0, 0.0),
None => Rgb::new(1.0, 0.5, 0.0),
None => {
if *percent_damage < 0.5 {
Rgb::new(0.0, 1.0, 0.0)
} else {
Rgb::new(1.0, 0.5, 0.0)
}
},
},
*power
* match reagent {

View File

@ -14,6 +14,7 @@ use common::{
span,
spiral::Spiral2d,
state::DeltaTime,
states::utils::StageSection,
terrain::TerrainChunk,
vol::{RectRasterableVol, SizedVol},
};
@ -58,37 +59,54 @@ impl ParticleMgr {
pos,
power,
reagent,
percent_damage,
} => {
self.particles.resize_with(
self.particles.len() + if reagent.is_some() { 300 } else { 150 },
|| {
Particle::new(
Duration::from_millis(if reagent.is_some() { 1000 } else { 250 }),
time,
match reagent {
Some(Reagent::Blue) => ParticleMode::FireworkBlue,
Some(Reagent::Green) => ParticleMode::FireworkGreen,
Some(Reagent::Purple) => ParticleMode::FireworkPurple,
Some(Reagent::Red) => ParticleMode::FireworkRed,
Some(Reagent::Yellow) => ParticleMode::FireworkYellow,
None => ParticleMode::Shrapnel,
},
*pos,
)
},
);
if *percent_damage < 0.5 {
self.particles.resize_with(
self.particles.len() + (200.0 * power) as usize,
|| {
Particle::new(
Duration::from_secs(1),
time,
ParticleMode::EnergyNature,
*pos + Vec3::<f32>::zero()
.map(|_| rng.gen_range(-3.0, 3.0) * power),
)
},
);
} else {
self.particles.resize_with(
self.particles.len() + if reagent.is_some() { 300 } else { 150 },
|| {
Particle::new(
Duration::from_millis(if reagent.is_some() { 1000 } else { 250 }),
time,
match reagent {
Some(Reagent::Blue) => ParticleMode::FireworkBlue,
Some(Reagent::Green) => ParticleMode::FireworkGreen,
Some(Reagent::Purple) => ParticleMode::FireworkPurple,
Some(Reagent::Red) => ParticleMode::FireworkRed,
Some(Reagent::Yellow) => ParticleMode::FireworkYellow,
None => ParticleMode::Shrapnel,
},
*pos,
)
},
);
self.particles.resize_with(
self.particles.len() + if reagent.is_some() { 100 } else { 200 },
|| {
Particle::new(
Duration::from_secs(4),
time,
ParticleMode::CampfireSmoke,
*pos + Vec2::<f32>::zero().map(|_| rng.gen_range(-1.0, 1.0) * power),
)
},
);
self.particles.resize_with(
self.particles.len() + if reagent.is_some() { 100 } else { 200 },
|| {
Particle::new(
Duration::from_secs(4),
time,
ParticleMode::CampfireSmoke,
*pos + Vec2::<f32>::zero()
.map(|_| rng.gen_range(-1.0, 1.0) * power),
)
},
);
}
},
Outcome::ProjectileShot { .. } => {},
}
@ -112,6 +130,7 @@ impl ParticleMgr {
// add new Particle
self.maintain_body_particles(scene_data);
self.maintain_boost_particles(scene_data);
self.maintain_beam_particles(scene_data);
self.maintain_block_particles(scene_data, terrain);
self.maintain_shockwave_particles(scene_data);
} else {
@ -143,6 +162,9 @@ impl ParticleMgr {
Body::Object(object::Body::BoltFireBig) => {
self.maintain_boltfirebig_particles(scene_data, pos)
},
Body::Object(object::Body::BoltNature) => {
self.maintain_boltnature_particles(scene_data, pos)
},
Body::Object(
object::Body::Bomb
| object::Body::FireworkBlue
@ -240,6 +262,23 @@ impl ParticleMgr {
);
}
fn maintain_boltnature_particles(&mut self, scene_data: &SceneData, pos: &Pos) {
let time = scene_data.state.get_time();
// nature
self.particles.resize_with(
self.particles.len() + usize::from(self.scheduler.heartbeats(Duration::from_millis(3))),
|| {
Particle::new(
Duration::from_millis(250),
time,
ParticleMode::EnergyNature,
pos.0,
)
},
);
}
fn maintain_bomb_particles(&mut self, scene_data: &SceneData, pos: &Pos) {
span!(
_guard,
@ -300,6 +339,37 @@ impl ParticleMgr {
}
}
fn maintain_beam_particles(&mut self, scene_data: &SceneData) {
let state = scene_data.state;
let ecs = state.ecs();
let time = state.get_time();
for (pos, ori, character_state) in (
&ecs.read_storage::<Pos>(),
&ecs.read_storage::<Ori>(),
&ecs.read_storage::<CharacterState>(),
)
.join()
{
if let CharacterState::BasicBeam(b) = character_state {
let particle_ori = b.particle_ori.unwrap_or(*ori.vec());
if b.stage_section == StageSection::Cast {
for i in 0..self.scheduler.heartbeats(Duration::from_millis(1)) {
self.particles.push(Particle::new_beam(
b.static_data.beam_duration,
time + i as f64 / 1000.0,
ParticleMode::HealingBeam,
pos.0 + particle_ori * 0.5 + Vec3::new(0.0, 0.0, b.offset),
pos.0
+ particle_ori * b.static_data.range
+ Vec3::new(0.0, 0.0, b.offset),
));
}
}
}
}
}
#[allow(clippy::same_item_push)] // TODO: Pending review in #587
fn maintain_block_particles(
&mut self,
@ -646,4 +716,17 @@ impl Particle {
instance: ParticleInstance::new(time, lifespan.as_secs_f32(), mode, pos),
}
}
fn new_beam(
lifespan: Duration,
time: f64,
mode: ParticleMode,
pos1: Vec3<f32>,
pos2: Vec3<f32>,
) -> Self {
Particle {
alive_until: time + lifespan.as_secs_f64(),
instance: ParticleInstance::new_beam(time, lifespan.as_secs_f32(), mode, pos1, pos2),
}
}
}