mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/sceptre-overhaul' into 'master'
Sceptre Rework Closes #760 See merge request veloren/veloren!1345
This commit is contained in:
commit
a2daad8c76
@ -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
|
||||
|
||||
|
@ -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,
|
@ -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,
|
13
assets/common/items/weapons/sceptre/starter_sceptre.ron
Normal file
13
assets/common/items/weapons/sceptre/starter_sceptre.ron
Normal 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,
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
@ -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"),
|
||||
|
@ -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
|
||||
|
@ -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"),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
BIN
assets/voxygen/element/icons/heal_bomb.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -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}]",
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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
BIN
assets/voxygen/voxel/weapon/sceptre/wood-simple.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -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),
|
||||
|
@ -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
49
common/src/comp/beam.rs
Normal 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>;
|
||||
}
|
@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -50,6 +50,7 @@ pub enum KillType {
|
||||
Melee,
|
||||
Projectile,
|
||||
Explosion,
|
||||
Energy,
|
||||
// Projectile(String), TODO: add projectile name when available
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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>,
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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));
|
||||
|
179
common/src/states/basic_beam.rs
Normal file
179
common/src/states/basic_beam.rs
Normal 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
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod basic_beam;
|
||||
pub mod basic_block;
|
||||
pub mod basic_melee;
|
||||
pub mod basic_ranged;
|
||||
|
@ -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,
|
||||
|
@ -363,4 +363,5 @@ pub enum StageSection {
|
||||
Swing,
|
||||
Recover,
|
||||
Charge,
|
||||
Cast,
|
||||
}
|
||||
|
@ -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
387
common/src/sys/beam.rs
Normal 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
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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
370
items.csv
@ -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
|
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
},
|
||||
|
@ -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';
|
@ -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';
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -180,6 +180,7 @@ impl Animation for DashAnimation {
|
||||
Quaternion::rotation_x(-1.5) * Quaternion::rotation_y(-1.0);
|
||||
next.control.scale = Vec3::one();
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
})
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user