First 3 abilities for tidal warrior functional. Added bubble particles.

This commit is contained in:
Sam 2021-05-23 19:45:22 -05:00
parent 59ae5ec573
commit c81e1534f7
31 changed files with 184 additions and 32 deletions

View File

@ -109,9 +109,12 @@
abilities: [], abilities: [],
), ),
Custom("Tidal Claws"): ( Custom("Tidal Claws"): (
primary: "common.abilities.staff.flamethrower", primary: "common.abilities.custom.tidalwarrior.pincer",
secondary: "common.abilities.custom.wendigomagic.singlestrike", secondary: "common.abilities.custom.tidalwarrior.scuttle",
abilities: [], abilities: [
(None, "common.abilities.custom.tidalwarrior.bubbles"),
(None, "common.abilities.custom.tidalwarrior.totem"),
],
), ),
Custom("Quad Med Quick"): ( Custom("Quad Med Quick"): (
primary: "common.abilities.custom.quadmedquick.triplestrike", primary: "common.abilities.custom.quadmedquick.triplestrike",

View File

@ -3,7 +3,7 @@ BasicMelee(
buildup_duration: 0.25, buildup_duration: 0.25,
swing_duration: 0.1, swing_duration: 0.1,
recover_duration: 0.25, recover_duration: 0.25,
knockback: 25.0, knockback: ( strength: 25.0, direction: Away),
base_damage: 200, base_damage: 200,
base_poise_damage: 40, base_poise_damage: 40,
range: 5.0, range: 5.0,

View File

@ -5,7 +5,7 @@ BasicMelee(
recover_duration: 0.5, recover_duration: 0.5,
base_damage: 200, base_damage: 200,
base_poise_damage: 50, base_poise_damage: 50,
knockback: 10.0, knockback: ( strength: 10.0, direction: Away),
range: 4.0, range: 4.0,
max_angle: 45.0, max_angle: 45.0,
damage_effect: None, damage_effect: None,

View File

@ -5,7 +5,7 @@ BasicMelee(
recover_duration: 0.6, recover_duration: 0.6,
base_damage: 150.0, base_damage: 150.0,
base_poise_damage: 60.0, base_poise_damage: 60.0,
knockback: 15.0, knockback: ( strength: 15.0, direction: Away),
range: 5.0, range: 5.0,
max_angle: 60.0, max_angle: 60.0,
damage_effect: Some(Buff(( damage_effect: Some(Buff((

View File

@ -5,7 +5,7 @@ BasicMelee(
recover_duration: 0.35, recover_duration: 0.35,
base_damage: 100, base_damage: 100,
base_poise_damage: 28, base_poise_damage: 28,
knockback: 25.0, knockback: ( strength: 25.0, direction: Away),
range: 1.2, range: 1.2,
max_angle: 50.0, max_angle: 50.0,
damage_effect: None, damage_effect: None,

View File

@ -0,0 +1,19 @@
BasicBeam(
buildup_duration: 0.5,
recover_duration: 0.5,
beam_duration: 2.5,
damage: 100,
tick_rate: 2.0,
range: 25.0,
max_angle: 15.0,
damage_effect: Some(Buff((
kind: Wet,
dur_secs: 15.0,
strength: Value(4.5),
chance: 0.25,
))),
energy_regen: 0,
energy_drain: 0,
orientation_behavior: Normal,
specifier: Bubbles,
)

View File

@ -0,0 +1,13 @@
BasicMelee(
energy_cost: 0,
buildup_duration: 0.3,
swing_duration: 0.1,
recover_duration: 0.6,
base_damage: 50.0,
base_poise_damage: 0.0,
knockback: ( strength: 100.0, direction: Towards),
range: 5.0,
max_angle: 60.0,
damage_effect: None,
damage_kind: Crushing,
)

View File

@ -0,0 +1,20 @@
DashMelee(
energy_cost: 0,
base_damage: 50,
scaled_damage: 250,
base_poise_damage: 10,
scaled_poise_damage: 40,
base_knockback: 10.0,
scaled_knockback: 30.0,
range: 5.0,
angle: 90.0,
energy_drain: 0,
forward_speed: 10.0,
buildup_duration: 0.4,
charge_duration: 2.0,
swing_duration: 0.1,
recover_duration: 0.5,
charge_through: false,
is_interruptible: false,
damage_kind: Crushing,
)

View File

@ -0,0 +1,18 @@
BasicMelee(
energy_cost: 0,
buildup_duration: 0.3,
swing_duration: 0.1,
recover_duration: 0.6,
base_damage: 50.0,
base_poise_damage: 100.0,
knockback: ( strength: 50.0, direction: Towards),
range: 5.0,
max_angle: 60.0,
damage_effect: Some(Buff((
kind: Crippled,
dur_secs: 15.0,
strength: Value(0.5),
chance: 1.0,
))),
damage_kind: Slashing,
)

View File

@ -5,7 +5,7 @@ BasicMelee(
recover_duration: 0.3, recover_duration: 0.3,
base_damage: 50, base_damage: 50,
base_poise_damage: 0, base_poise_damage: 0,
knockback: 0.0, knockback: ( strength: 0.0, direction: Away),
range: 3.5, range: 3.5,
max_angle: 20.0, max_angle: 20.0,
damage_effect: None, damage_effect: None,

View File

@ -5,7 +5,7 @@ BasicMelee(
recover_duration: 0.9, recover_duration: 0.9,
base_damage: 20, base_damage: 20,
base_poise_damage: 0, base_poise_damage: 0,
knockback: 0.0, knockback: ( strength: 0.0, direction: Away),
range: 3.5, range: 3.5,
max_angle: 15.0, max_angle: 15.0,
damage_effect: None, damage_effect: None,

View File

@ -5,7 +5,7 @@ BasicMelee(
recover_duration: 0.15, recover_duration: 0.15,
base_damage: 50, base_damage: 50,
base_poise_damage: 0, base_poise_damage: 0,
knockback: 0.0, knockback: ( strength: 0.0, direction: Away),
range: 3.5, range: 3.5,
max_angle: 20.0, max_angle: 20.0,
damage_effect: None, damage_effect: None,

View File

@ -5,7 +5,7 @@ BasicMelee(
recover_duration: 0.15, recover_duration: 0.15,
base_damage: 50, base_damage: 50,
base_poise_damage: 0, base_poise_damage: 0,
knockback: 0.0, knockback: ( strength: 0.0, direction: Away),
range: 3.5, range: 3.5,
max_angle: 20.0, max_angle: 20.0,
damage_effect: None, damage_effect: None,

View File

@ -5,7 +5,7 @@ BasicMelee(
recover_duration: 0.3, recover_duration: 0.3,
base_damage: 40, base_damage: 40,
base_poise_damage: 0, base_poise_damage: 0,
knockback: 0.0, knockback: ( strength: 0.0, direction: Away),
range: 3.0, range: 3.0,
max_angle: 120.0, max_angle: 120.0,
damage_effect: None, damage_effect: None,

View File

@ -32,6 +32,8 @@
"buff.desc.crippled": "Your movement is crippled as your legs are heavily injured.", "buff.desc.crippled": "Your movement is crippled as your legs are heavily injured.",
"buff.title.frozen": "Frozen", "buff.title.frozen": "Frozen",
"buff.desc.frozen": "Your movements and attacks are slowed.", "buff.desc.frozen": "Your movements and attacks are slowed.",
"buff.title.wet": "Wet",
"buff.desc.wet": "The ground rejects your feet, making it hard to stop.",
// Buffs stats // Buffs stats
"buff.stat.health": "Restores {str_total} Health", "buff.stat.health": "Restores {str_total} Health",
"buff.stat.increase_max_stamina": "Raises Maximum Stamina by {strength}", "buff.stat.increase_max_stamina": "Raises Maximum Stamina by {strength}",

View File

@ -67,6 +67,7 @@ const int BLOOD = 25;
const int ENRAGED = 26; const int ENRAGED = 26;
const int BIG_SHRAPNEL = 27; const int BIG_SHRAPNEL = 27;
const int LASER = 28; const int LASER = 28;
const int BUBBLES = 29;
// meters per second squared (acceleration) // meters per second squared (acceleration)
const float earth_gravity = 9.807; const float earth_gravity = 9.807;
@ -489,6 +490,17 @@ void main() {
spin_in_axis(perp_axis, asin(inst_dir.z / length(inst_dir)) + PI / 2.0) spin_in_axis(perp_axis, asin(inst_dir.z / length(inst_dir)) + PI / 2.0)
); );
break; break;
case BUBBLES:
f_reflect = 0.0; // Magic water doesn't reflect light, it emits it
float blue_color = 1.5 + 0.2 * rand3 + 1.5 * max(floor(rand4 + 0.3), 0.0);
float size = 8.0 * (1 - slow_start(0.1)) * slow_end(0.15);
attr = Attr(
(inst_dir * slow_end(1.5)) + vec3(rand0, rand1, rand2) * (percent() + 2) * 0.1,
vec3(size),
vec4(0.5 * blue_color, 0.75 * blue_color, blue_color, 1),
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
);
break;
default: default:
attr = Attr( attr = Attr(
linear_motion( linear_motion(

View File

@ -271,6 +271,7 @@ lazy_static! {
BuffKind::Frenzied => "frenzied", BuffKind::Frenzied => "frenzied",
BuffKind::Crippled => "crippled", BuffKind::Crippled => "crippled",
BuffKind::Frozen => "frozen", BuffKind::Frozen => "frozen",
BuffKind::Wet => "wet",
}; };
let mut buff_parser = HashMap::new(); let mut buff_parser = HashMap::new();
BuffKind::iter().for_each(|kind| {buff_parser.insert(string_from_buff(kind).to_string(), kind);}); BuffKind::iter().for_each(|kind| {buff_parser.insert(string_from_buff(kind).to_string(), kind);});

View File

@ -65,7 +65,7 @@ pub enum CharacterAbility {
recover_duration: f32, recover_duration: f32,
base_damage: f32, base_damage: f32,
base_poise_damage: f32, base_poise_damage: f32,
knockback: f32, knockback: Knockback,
range: f32, range: f32,
max_angle: f32, max_angle: f32,
damage_effect: Option<CombatEffect>, damage_effect: Option<CombatEffect>,
@ -301,7 +301,10 @@ impl Default for CharacterAbility {
recover_duration: 0.5, recover_duration: 0.5,
base_damage: 10.0, base_damage: 10.0,
base_poise_damage: 0.0, base_poise_damage: 0.0,
knockback: 0.0, knockback: Knockback {
strength: 0.0,
direction: combat::KnockbackDir::Away,
},
range: 3.5, range: 3.5,
max_angle: 15.0, max_angle: 15.0,
damage_effect: None, damage_effect: None,

View File

@ -53,4 +53,5 @@ pub enum FrontendSpecifier {
HealingBeam, HealingBeam,
Cultist, Cultist,
ClayGolem, ClayGolem,
Bubbles,
} }

View File

@ -67,6 +67,10 @@ pub enum BuffKind {
/// speed, 1.0 is 33% speed. Movement speed debuff is scaled to be slightly /// speed, 1.0 is 33% speed. Movement speed debuff is scaled to be slightly
/// smaller than attack speed debuff. /// smaller than attack speed debuff.
Frozen, Frozen,
/// Makes you wet and causes you to have reduced friction on the ground.
/// Strength scales the friction you ignore non-linearly. 0.5 is 50% ground
/// friction, 1.0 is 33% ground friction.
Wet,
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -88,6 +92,7 @@ impl BuffKind {
BuffKind::Crippled => false, BuffKind::Crippled => false,
BuffKind::Frenzied => true, BuffKind::Frenzied => true,
BuffKind::Frozen => false, BuffKind::Frozen => false,
BuffKind::Wet => false,
} }
} }
@ -156,6 +161,8 @@ pub enum BuffEffect {
MovementSpeed(f32), MovementSpeed(f32),
/// Modifies attack speed of target /// Modifies attack speed of target
AttackSpeed(f32), AttackSpeed(f32),
/// Modifies ground friction of target
GroundFriction(f32),
} }
/// Actual de/buff. /// Actual de/buff.
@ -316,6 +323,10 @@ impl Buff {
], ],
data.duration, data.duration,
), ),
BuffKind::Wet => (
vec![BuffEffect::GroundFriction(1.0 - nn_scaling(data.strength))],
data.duration,
),
}; };
Buff { Buff {
kind, kind,

View File

@ -27,6 +27,7 @@ pub struct Stats {
pub max_health_modifier: f32, pub max_health_modifier: f32,
pub move_speed_modifier: f32, pub move_speed_modifier: f32,
pub attack_speed_modifier: f32, pub attack_speed_modifier: f32,
pub friction_modifier: f32,
} }
impl Stats { impl Stats {
@ -37,6 +38,7 @@ impl Stats {
max_health_modifier: 1.0, max_health_modifier: 1.0,
move_speed_modifier: 1.0, move_speed_modifier: 1.0,
attack_speed_modifier: 1.0, attack_speed_modifier: 1.0,
friction_modifier: 1.0,
} }
} }
@ -49,6 +51,7 @@ impl Stats {
max_health_modifier: 1.0, max_health_modifier: 1.0,
move_speed_modifier: 1.0, move_speed_modifier: 1.0,
attack_speed_modifier: 1.0, attack_speed_modifier: 1.0,
friction_modifier: 1.0,
} }
} }
@ -58,6 +61,7 @@ impl Stats {
self.max_health_modifier = 1.0; self.max_health_modifier = 1.0;
self.move_speed_modifier = 1.0; self.move_speed_modifier = 1.0;
self.attack_speed_modifier = 1.0; self.attack_speed_modifier = 1.0;
self.friction_modifier = 1.0;
} }
} }

View File

@ -1,11 +1,13 @@
use crate::{ use crate::{
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement}, combat::{
Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement, Damage,
DamageKind, DamageSource, GroupTarget, Knockback,
},
comp::{tool::ToolKind, CharacterState, Melee, StateUpdate}, comp::{tool::ToolKind, CharacterState, Melee, StateUpdate},
states::{ states::{
behavior::{CharacterBehavior, JoinData}, behavior::{CharacterBehavior, JoinData},
utils::*, utils::*,
}, },
Damage, DamageKind, DamageSource, GroupTarget, Knockback, KnockbackDir,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
@ -24,7 +26,7 @@ pub struct StaticData {
/// Base poise reduction /// Base poise reduction
pub base_poise_damage: f32, pub base_poise_damage: f32,
/// Knockback /// Knockback
pub knockback: f32, pub knockback: Knockback,
/// Max range /// Max range
pub range: f32, pub range: f32,
/// Max angle (45.0 will give you a 90.0 angle window) /// Max angle (45.0 will give you a 90.0 angle window)
@ -91,10 +93,7 @@ impl CharacterBehavior for Data {
.with_requirement(CombatRequirement::AnyDamage); .with_requirement(CombatRequirement::AnyDamage);
let knockback = AttackEffect::new( let knockback = AttackEffect::new(
Some(GroupTarget::OutOfGroup), Some(GroupTarget::OutOfGroup),
CombatEffect::Knockback(Knockback { CombatEffect::Knockback(self.static_data.knockback),
strength: self.static_data.knockback,
direction: KnockbackDir::Away,
}),
) )
.with_requirement(CombatRequirement::AnyDamage); .with_requirement(CombatRequirement::AnyDamage);
let energy = AttackEffect::new(None, CombatEffect::EnergyReward(50.0)) let energy = AttackEffect::new(None, CombatEffect::EnergyReward(50.0))

View File

@ -243,7 +243,7 @@ pub fn handle_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
/// Updates components to move player as if theyre on ground or in air /// Updates components to move player as if theyre on ground or in air
#[allow(clippy::assign_op_pattern)] // TODO: Pending review in #587 #[allow(clippy::assign_op_pattern)] // TODO: Pending review in #587
fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) { fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
let efficiency = efficiency * data.stats.move_speed_modifier; let efficiency = efficiency * data.stats.move_speed_modifier * data.stats.friction_modifier;
let accel = if data.physics.on_ground { let accel = if data.physics.on_ground {
data.body.base_accel() data.body.base_accel()
@ -269,14 +269,15 @@ pub fn handle_forced_movement(
movement: ForcedMovement, movement: ForcedMovement,
efficiency: f32, efficiency: f32,
) { ) {
let efficiency = efficiency * data.stats.move_speed_modifier; let efficiency = efficiency * data.stats.move_speed_modifier * data.stats.friction_modifier;
match movement { match movement {
ForcedMovement::Forward { strength } => { ForcedMovement::Forward { strength } => {
if let Some(accel) = data.physics.on_ground.then_some(data.body.base_accel()) { if let Some(accel) = data.physics.on_ground.then_some(data.body.base_accel()) {
update.vel.0 += Vec2::broadcast(data.dt.0) update.vel.0 += Vec2::broadcast(data.dt.0)
* accel * accel
* (data.inputs.move_dir * efficiency + Vec2::from(update.ori) * strength); * (data.inputs.move_dir + Vec2::from(update.ori) * strength)
* efficiency;
} }
}, },
ForcedMovement::Leap { ForcedMovement::Leap {
@ -328,7 +329,7 @@ pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, efficiency:
/// Updates components to move player as if theyre swimming /// Updates components to move player as if theyre swimming
fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, submersion: f32) -> bool { fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, submersion: f32) -> bool {
let efficiency = efficiency * data.stats.move_speed_modifier; let efficiency = efficiency * data.stats.move_speed_modifier * data.stats.friction_modifier;
if let Some(force) = data.body.swim_thrust() { if let Some(force) = data.body.swim_thrust() {
let force = efficiency * force; let force = efficiency * force;
let mut water_accel = force / data.mass.0; let mut water_accel = force / data.mass.0;
@ -366,7 +367,7 @@ fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, submers
/// Updates components to move entity as if it's flying /// Updates components to move entity as if it's flying
pub fn fly_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) -> bool { pub fn fly_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) -> bool {
let efficiency = efficiency * data.stats.move_speed_modifier; let efficiency = efficiency * data.stats.move_speed_modifier * data.stats.friction_modifier;
let glider = match data.character { let glider = match data.character {
CharacterState::Glide(data) => Some(data), CharacterState::Glide(data) => Some(data),

View File

@ -214,6 +214,9 @@ impl<'a> System<'a> for Sys {
BuffEffect::AttackSpeed(speed) => { BuffEffect::AttackSpeed(speed) => {
stat.attack_speed_modifier *= *speed; stat.attack_speed_modifier *= *speed;
}, },
BuffEffect::GroundFriction(gf) => {
stat.friction_modifier *= *gf;
},
}; };
} }
} }

View File

@ -3,7 +3,7 @@ use common::{
body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST}, body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST},
fluid_dynamics::{Fluid, Wings}, fluid_dynamics::{Fluid, Wings},
BeamSegment, Body, CharacterState, Collider, Density, Mass, Mounting, Ori, PhysicsState, BeamSegment, Body, CharacterState, Collider, Density, Mass, Mounting, Ori, PhysicsState,
Pos, PosVelDefer, PreviousPhysCache, Projectile, Scale, Shockwave, Sticky, Vel, Pos, PosVelDefer, PreviousPhysCache, Projectile, Scale, Shockwave, Stats, Sticky, Vel,
}, },
consts::{AIR_DENSITY, FRIC_GROUND, GRAVITY}, consts::{AIR_DENSITY, FRIC_GROUND, GRAVITY},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
@ -124,6 +124,7 @@ pub struct PhysicsRead<'a> {
bodies: ReadStorage<'a, Body>, bodies: ReadStorage<'a, Body>,
character_states: ReadStorage<'a, CharacterState>, character_states: ReadStorage<'a, CharacterState>,
densities: ReadStorage<'a, Density>, densities: ReadStorage<'a, Density>,
stats: ReadStorage<'a, Stats>,
} }
#[derive(SystemData)] #[derive(SystemData)]
@ -779,6 +780,7 @@ impl<'a> PhysicsData<'a> {
block_snap, block_snap,
climbing, climbing,
|entity, vel| land_on_ground = Some((entity, vel)), |entity, vel| land_on_ground = Some((entity, vel)),
read,
); );
tgt_pos = cpos.0; tgt_pos = cpos.0;
}, },
@ -808,6 +810,7 @@ impl<'a> PhysicsData<'a> {
block_snap, block_snap,
climbing, climbing,
|entity, vel| land_on_ground = Some((entity, vel)), |entity, vel| land_on_ground = Some((entity, vel)),
read,
); );
// Sticky things shouldn't move when on a surface // Sticky things shouldn't move when on a surface
@ -1048,6 +1051,7 @@ impl<'a> PhysicsData<'a> {
land_on_ground = land_on_ground =
Some((entity, Vel(ori_from.mul_direction(vel.0)))); Some((entity, Vel(ori_from.mul_direction(vel.0))));
}, },
read,
); );
cpos.0 = transform_from.mul_point(cpos.0) + wpos; cpos.0 = transform_from.mul_point(cpos.0) + wpos;
@ -1242,6 +1246,7 @@ fn box_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
block_snap: bool, block_snap: bool,
climbing: bool, climbing: bool,
mut land_on_ground: impl FnMut(Entity, Vel), mut land_on_ground: impl FnMut(Entity, Vel),
read: &PhysicsRead,
) { ) {
let (radius, z_min, z_max) = cylinder; let (radius, z_min, z_max) = cylinder;
@ -1567,8 +1572,9 @@ fn box_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
} }
} }
physics_state.on_wall = on_wall; physics_state.on_wall = on_wall;
let fric_mod = read.stats.get(entity).map_or(1.0, |s| s.friction_modifier);
if physics_state.on_ground || (physics_state.on_wall.is_some() && climbing) { if physics_state.on_ground || (physics_state.on_wall.is_some() && climbing) {
vel.0 *= (1.0 - FRIC_GROUND.min(1.0)).powf(dt.0 * 60.0); vel.0 *= (1.0 - FRIC_GROUND.min(1.0) * fric_mod).powf(dt.0 * 60.0);
physics_state.ground_vel = ground_vel; physics_state.ground_vel = ground_vel;
} }

View File

@ -403,7 +403,7 @@ impl SfxMgr {
audio.emit_sfx(sfx_trigger_item, *pos, None, false); audio.emit_sfx(sfx_trigger_item, *pos, None, false);
} }
}, },
beam::FrontendSpecifier::ClayGolem => {}, beam::FrontendSpecifier::ClayGolem | beam::FrontendSpecifier::Bubbles => {},
}, },
Outcome::BreakBlock { pos, .. } => { Outcome::BreakBlock { pos, .. } => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::BreakBlock); let sfx_trigger_item = triggers.get_key_value(&SfxEvent::BreakBlock);

View File

@ -756,6 +756,10 @@ fn insert_killing_buff(buff: BuffKind, localized_strings: &Localization, templat
tracing::error!("Player was killed by a positive buff!"); tracing::error!("Player was killed by a positive buff!");
localized_strings.get("hud.outcome.mysterious") localized_strings.get("hud.outcome.mysterious")
}, },
BuffKind::Wet => {
tracing::error!("Player was killed by a debuff that doesn't do damage!");
localized_strings.get("hud.outcome.mysterious")
},
}; };
template.replace("{died_of_buff}", buff_outcome) template.replace("{died_of_buff}", buff_outcome)

View File

@ -3777,6 +3777,8 @@ pub fn get_buff_image(buff: BuffKind, imgs: &Imgs) -> conrod_core::image::Id {
BuffKind::Burning { .. } => imgs.debuff_burning_0, BuffKind::Burning { .. } => imgs.debuff_burning_0,
BuffKind::Crippled { .. } => imgs.debuff_crippled_0, BuffKind::Crippled { .. } => imgs.debuff_crippled_0,
BuffKind::Frozen { .. } => imgs.debuff_frozen_0, BuffKind::Frozen { .. } => imgs.debuff_frozen_0,
// TODO: Get icon for this before merging. Anyone doing code review open a comment here.
BuffKind::Wet { .. } => imgs.debuff_burning_0,
} }
} }
@ -3798,6 +3800,7 @@ pub fn get_buff_title(buff: BuffKind, localized_strings: &Localization) -> &str
BuffKind::Burning { .. } => localized_strings.get("buff.title.burn"), BuffKind::Burning { .. } => localized_strings.get("buff.title.burn"),
BuffKind::Crippled { .. } => localized_strings.get("buff.title.crippled"), BuffKind::Crippled { .. } => localized_strings.get("buff.title.crippled"),
BuffKind::Frozen { .. } => localized_strings.get("buff.title.frozen"), BuffKind::Frozen { .. } => localized_strings.get("buff.title.frozen"),
BuffKind::Wet { .. } => localized_strings.get("buff.title.wet"),
} }
} }
@ -3831,6 +3834,7 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz
BuffKind::Burning { .. } => Cow::Borrowed(localized_strings.get("buff.desc.burn")), BuffKind::Burning { .. } => Cow::Borrowed(localized_strings.get("buff.desc.burn")),
BuffKind::Crippled { .. } => Cow::Borrowed(localized_strings.get("buff.desc.crippled")), BuffKind::Crippled { .. } => Cow::Borrowed(localized_strings.get("buff.desc.crippled")),
BuffKind::Frozen { .. } => Cow::Borrowed(localized_strings.get("buff.desc.frozen")), BuffKind::Frozen { .. } => Cow::Borrowed(localized_strings.get("buff.desc.frozen")),
BuffKind::Wet { .. } => Cow::Borrowed(localized_strings.get("buff.desc.wet")),
} }
} }

View File

@ -121,7 +121,8 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String {
| BuffKind::ProtectingWard | BuffKind::ProtectingWard
| BuffKind::Crippled | BuffKind::Crippled
| BuffKind::Frenzied | BuffKind::Frenzied
| BuffKind::Frozen => continue, | BuffKind::Frozen
| BuffKind::Wet => continue,
}; };
write!(&mut description, "{}", buff_desc).unwrap(); write!(&mut description, "{}", buff_desc).unwrap();
@ -144,7 +145,8 @@ pub fn consumable_desc(effects: &[Effect], i18n: &Localization) -> String {
| BuffKind::ProtectingWard | BuffKind::ProtectingWard
| BuffKind::Crippled | BuffKind::Crippled
| BuffKind::Frenzied | BuffKind::Frenzied
| BuffKind::Frozen => continue, | BuffKind::Frozen
| BuffKind::Wet => continue,
} }
} else if let BuffKind::Saturation | BuffKind::Regeneration = buff.kind { } else if let BuffKind::Saturation | BuffKind::Regeneration = buff.kind {
i18n.get("buff.text.every_second").to_string() i18n.get("buff.text.every_second").to_string()

View File

@ -79,6 +79,7 @@ pub enum ParticleMode {
Enraged = 26, Enraged = 26,
BigShrapnel = 27, BigShrapnel = 27,
Laser = 28, Laser = 28,
Bubbles = 29,
} }
impl ParticleMode { impl ParticleMode {

View File

@ -830,6 +830,31 @@ impl ParticleMgr {
) )
}) })
}, },
beam::FrontendSpecifier::Bubbles => {
let mut rng = thread_rng();
let (from, to) = (Vec3::<f32>::unit_z(), *ori.look_dir());
let m = Mat3::<f32>::rotation_from_to_3d(from, to);
self.particles.resize_with(
self.particles.len() + usize::from(beam_tick_count) / 15,
|| {
let phi: f32 = rng.gen_range(0.0..beam.properties.angle);
let theta: f32 = rng.gen_range(0.0..2.0 * PI);
let offset_z = Vec3::new(
phi.sin() * theta.cos(),
phi.sin() * theta.sin(),
phi.cos(),
);
let random_ori = offset_z * m * Vec3::new(-1.0, -1.0, 1.0);
Particle::new_directed(
beam.properties.duration,
time,
ParticleMode::Bubbles,
pos.0,
pos.0 + random_ori * range,
)
},
);
},
} }
} }
} }