Fixed bugs with negative DR buffs bypassing admin tabard, auras only being cleared if entity had entered_auras component, and shockwaves with 0 combo cost resetting combo. Other balance feedback.

This commit is contained in:
Sam 2024-04-14 12:46:53 -04:00
parent aeb887963e
commit b6fbcbb204
23 changed files with 101 additions and 55 deletions

View File

@ -1,10 +1,10 @@
SelfBuff( SelfBuff(
buildup_duration: 0.1, buildup_duration: 0.1,
cast_duration: 2.0, cast_duration: 1.0,
recover_duration: 0.1, recover_duration: 0.1,
buff_kind: Defiance, buff_kind: Defiance,
buff_strength: 1.0, buff_strength: 1.0,
buff_duration: Some(5.0), buff_duration: Some(8.0),
energy_cost: 20, energy_cost: 20,
enforced_limit: false, enforced_limit: false,
) )

View File

@ -13,6 +13,7 @@ BasicMelee(
), ),
range: 3, range: 3,
angle: 360, angle: 360,
multi_target: Some(Normal),
simultaneous_hits: 2, simultaneous_hits: 2,
), ),
ori_modifier: 0.2, ori_modifier: 0.2,

View File

@ -2,7 +2,7 @@ DashMelee(
energy_cost: 15, energy_cost: 15,
energy_drain: 0, energy_drain: 0,
forward_speed: 2.5, forward_speed: 2.5,
buildup_duration: 0.1, buildup_duration: 0.2,
charge_duration: 1.5, charge_duration: 1.5,
swing_duration: 0.1, swing_duration: 0.1,
recover_duration: 0.3, recover_duration: 0.3,

View File

@ -8,7 +8,7 @@ BasicMelee(
kind: Bash( kind: Bash(
damage: 15, damage: 15,
poise: 15, poise: 15,
knockback: 30, knockback: 0,
energy_regen: 0, energy_regen: 0,
), ),
range: 3, range: 3,
@ -20,6 +20,13 @@ BasicMelee(
strength: Value(0.5), strength: Value(0.5),
chance: 1.0, chance: 1.0,
))), ))),
attack_effect: Some((
Knockback((
direction: Up,
strength: 20,
)),
AnyDamage,
)),
), ),
ori_modifier: 0.2, ori_modifier: 0.2,
) )

View File

@ -15,8 +15,8 @@ FinisherMelee(
multi_target: Some(Normal), multi_target: Some(Normal),
damage_effect: Some(Buff(( damage_effect: Some(Buff((
kind: Winded, kind: Winded,
dur_secs: 5.0, dur_secs: 15.0,
strength: Value(2.0), strength: Value(5.0),
chance: 1.0, chance: 1.0,
))), ))),
), ),

View File

@ -13,6 +13,7 @@ BasicMelee(
), ),
range: 3, range: 3,
angle: 360, angle: 360,
multi_target: Some(Normal),
), ),
ori_modifier: 0.2, ori_modifier: 0.2,
) )

View File

@ -2,7 +2,7 @@ DashMelee(
energy_cost: 15, energy_cost: 15,
energy_drain: 0, energy_drain: 0,
forward_speed: 2.5, forward_speed: 2.5,
buildup_duration: 0.1, buildup_duration: 0.2,
charge_duration: 1.5, charge_duration: 1.5,
swing_duration: 0.1, swing_duration: 0.1,
recover_duration: 0.3, recover_duration: 0.3,

View File

@ -4,8 +4,8 @@ RapidMelee(
recover_duration: 0.3, recover_duration: 0.3,
melee_constructor: ( melee_constructor: (
kind: Bash( kind: Bash(
damage: 12, damage: 8,
poise: 15, poise: 10,
knockback: 3, knockback: 3,
energy_regen: 0, energy_regen: 0,
), ),

View File

@ -17,6 +17,6 @@ Shockwave(
ori_rate: 0.0, ori_rate: 0.0,
timing: PostAction, timing: PostAction,
emit_outcome: false, emit_outcome: false,
minimum_combo: 20, minimum_combo: Some(20),
combo_consumption: Cost, combo_consumption: Cost,
) )

View File

@ -5,7 +5,7 @@ FinisherMelee(
recover_duration: 0.3, recover_duration: 0.3,
melee_constructor: ( melee_constructor: (
kind: Bash( kind: Bash(
damage: 20, damage: 25,
poise: 0, poise: 0,
knockback: 0, knockback: 0,
energy_regen: 0, energy_regen: 0,
@ -13,7 +13,7 @@ FinisherMelee(
range: 4.0, range: 4.0,
angle: 15.0, angle: 15.0,
attack_effect: Some((Poise(50), BehindTarget)), attack_effect: Some((Poise(50), BehindTarget)),
precision_flank_multipliers: (front: 1.0, side: 1.0, back: 2.0), precision_flank_multipliers: (front: 1.0, side: 1.0, back: 3.0),
), ),
minimum_combo: 10, minimum_combo: 10,
combo_consumption: Cost, combo_consumption: Cost,

View File

@ -1,10 +1,10 @@
SelfBuff( SelfBuff(
buildup_duration: 0.1, buildup_duration: 0.1,
cast_duration: 2.0, cast_duration: 1.0,
recover_duration: 0.1, recover_duration: 0.1,
buff_kind: Tenacity, buff_kind: Tenacity,
buff_strength: 1.0, buff_strength: 1.0,
buff_duration: Some(5.0), buff_duration: Some(8.0),
energy_cost: 20, energy_cost: 20,
enforced_limit: false, enforced_limit: false,
meta: ( meta: (

View File

@ -5,7 +5,7 @@ FinisherMelee(
recover_duration: 0.7, recover_duration: 0.7,
melee_constructor: ( melee_constructor: (
kind: Bash( kind: Bash(
damage: 100, damage: 80,
poise: 100, poise: 100,
knockback: 0, knockback: 0,
energy_regen: 0, energy_regen: 0,

View File

@ -8,7 +8,7 @@ BasicMelee(
kind: Bash( kind: Bash(
damage: 20, damage: 20,
poise: 20, poise: 20,
knockback: 40, knockback: 0,
energy_regen: 0, energy_regen: 0,
), ),
range: 3, range: 3,
@ -19,6 +19,13 @@ BasicMelee(
strength: Value(0.5), strength: Value(0.5),
chance: 1.0, chance: 1.0,
))), ))),
attack_effect: Some((
Knockback((
direction: Up,
strength: 30,
)),
AnyDamage,
)),
), ),
ori_modifier: 0.2, ori_modifier: 0.2,
) )

View File

@ -10,15 +10,15 @@ ChargedMelee(
), ),
scaled: Some(( scaled: Some((
kind: Bash( kind: Bash(
damage: 20, damage: 40,
poise: 30, poise: 100,
knockback: 20, knockback: 20,
energy_regen: 30, energy_regen: 30,
))), ))),
range: 4.5, range: 4.5,
angle: 15.0, angle: 15.0,
), ),
charge_duration: 0.6, charge_duration: 1.4,
swing_duration: 0.2, swing_duration: 0.2,
hit_timing: 0.5, hit_timing: 0.5,
recover_duration: 0.5, recover_duration: 0.5,

View File

@ -391,7 +391,7 @@ common-abilities-hammer-tremor = Tremor
Strike the earth with enough force that the ground beneath your foes trembles. Strike the earth with enough force that the ground beneath your foes trembles.
common-abilities-hammer-vigorous_bash = Vigorous Bash common-abilities-hammer-vigorous_bash = Vigorous Bash
.desc = .desc =
Use the head of your hammer to quickly strike your foes. Use the head of your hammer to quickly strike your foes, giving a surge of adrenaline if the target is off balance.
common-abilities-hammer-heavy_whorl = Heavy Whorl common-abilities-hammer-heavy_whorl = Heavy Whorl
.desc = .desc =
You strike all foes surrounding you with your hammer. You strike all foes surrounding you with your hammer.

View File

@ -1169,7 +1169,12 @@ impl Damage {
} else { } else {
0.0 0.0
}; };
1.0 - (1.0 - inventory_dr) * (1.0 - stats_dr) // Return 100% if either DR is at 100% (admin tabard or safezone buff)
if protection.is_none() || stats_dr >= 1.0 {
1.0
} else {
1.0 - (1.0 - inventory_dr) * (1.0 - stats_dr)
}
} }
pub fn calculate_health_change( pub fn calculate_health_change(

View File

@ -942,8 +942,7 @@ pub enum CharacterAbility {
damage_effect: Option<CombatEffect>, damage_effect: Option<CombatEffect>,
timing: shockwave::Timing, timing: shockwave::Timing,
emit_outcome: bool, emit_outcome: bool,
#[serde(default)] minimum_combo: Option<u32>,
minimum_combo: u32,
#[serde(default)] #[serde(default)]
combo_consumption: ComboConsumption, combo_consumption: ComboConsumption,
#[serde(default)] #[serde(default)]
@ -1220,13 +1219,17 @@ impl CharacterAbility {
energy_cost, energy_cost,
combo_cost: minimum_combo, combo_cost: minimum_combo,
.. ..
} } => {
| CharacterAbility::Shockwave { data.combo.map_or(false, |c| c.counter() >= *minimum_combo)
&& update.energy.try_change_by(-*energy_cost).is_ok()
},
CharacterAbility::Shockwave {
energy_cost, energy_cost,
minimum_combo, minimum_combo,
.. ..
} => { } => {
data.combo.map_or(false, |c| c.counter() >= *minimum_combo) data.combo
.map_or(false, |c| c.counter() >= minimum_combo.unwrap_or(0))
&& update.energy.try_change_by(-*energy_cost).is_ok() && update.energy.try_change_by(-*energy_cost).is_ok()
}, },
CharacterAbility::DiveMelee { CharacterAbility::DiveMelee {
@ -1902,11 +1905,11 @@ impl CharacterAbility {
} }
| SelfBuff { | SelfBuff {
combo_cost: combo, .. combo_cost: combo, ..
} } => *combo,
| Shockwave { Shockwave {
minimum_combo: combo, minimum_combo: combo,
.. ..
} => *combo, } => combo.unwrap_or(0),
BasicMelee { .. } BasicMelee { .. }
| BasicRanged { .. } | BasicRanged { .. }
| RepeaterRanged { .. } | RepeaterRanged { .. }

View File

@ -12,6 +12,7 @@ use crate::{
lottery::LootSpec, lottery::LootSpec,
mounting::VolumePos, mounting::VolumePos,
outcome::Outcome, outcome::Outcome,
resources::Secs,
rtsim::RtSimEntity, rtsim::RtSimEntity,
terrain::SpriteKind, terrain::SpriteKind,
trade::{TradeAction, TradeId}, trade::{TradeAction, TradeId},
@ -437,6 +438,7 @@ pub struct CreateAuraEntityEvent {
pub auras: comp::Auras, pub auras: comp::Auras,
pub pos: Pos, pub pos: Pos,
pub creator_uid: Uid, pub creator_uid: Uid,
pub duration: Option<Secs>,
} }
pub struct EventBus<E> { pub struct EventBus<E> {

View File

@ -59,7 +59,7 @@ pub struct StaticData {
pub ori_rate: f32, pub ori_rate: f32,
/// Timing of shockwave /// Timing of shockwave
pub timing: Timing, pub timing: Timing,
pub minimum_combo: u32, pub minimum_combo: Option<u32>,
pub combo_on_use: u32, pub combo_on_use: u32,
pub combo_consumption: ComboConsumption, pub combo_consumption: ComboConsumption,
} }
@ -197,11 +197,11 @@ impl CharacterBehavior for Data {
impl Data { impl Data {
fn attack(&self, data: &JoinData, output_events: &mut OutputEvents) { fn attack(&self, data: &JoinData, output_events: &mut OutputEvents) {
self.static_data.combo_consumption.consume( if let Some(min_combo) = self.static_data.minimum_combo {
data, self.static_data
output_events, .combo_consumption
self.static_data.minimum_combo, .consume(data, output_events, min_combo);
); }
let poise = AttackEffect::new( let poise = AttackEffect::new(
Some(GroupTarget::OutOfGroup), Some(GroupTarget::OutOfGroup),

View File

@ -126,6 +126,7 @@ impl CharacterBehavior for Data {
auras: Auras::new(auras), auras: Auras::new(auras),
pos: *data.pos, pos: *data.pos,
creator_uid: *data.uid, creator_uid: *data.uid,
duration: self.static_data.aura_duration,
}); });
update.character = CharacterState::StaticAura(Data { update.character = CharacterState::StaticAura(Data {
static_data: self.static_data.clone(), static_data: self.static_data.clone(),

View File

@ -717,7 +717,7 @@ impl AbilityData {
energy: *energy_cost, energy: *energy_cost,
angle: *shockwave_angle, angle: *shockwave_angle,
range: *shockwave_speed * *shockwave_duration, range: *shockwave_speed * *shockwave_duration,
combo: *minimum_combo, combo: minimum_combo.unwrap_or(0),
}, },
StaticAura { energy_cost, .. } => Self::StaticAura { StaticAura { energy_cost, .. } => Self::StaticAura {
energy: *energy_cost, energy: *energy_cost,

View File

@ -8,8 +8,8 @@ use common::{
aura::{Aura, AuraKind, AuraTarget}, aura::{Aura, AuraKind, AuraTarget},
buff::{BuffCategory, BuffData, BuffKind, BuffSource}, buff::{BuffCategory, BuffData, BuffKind, BuffSource},
ship::figuredata::VOXEL_COLLIDER_MANIFEST, ship::figuredata::VOXEL_COLLIDER_MANIFEST,
Alignment, BehaviorCapability, ItemDrops, LightEmitter, Ori, Pos, TradingBehavior, Vel, Alignment, BehaviorCapability, ItemDrops, LightEmitter, Ori, Pos, Projectile,
WaypointArea, TradingBehavior, Vel, WaypointArea,
}, },
event::{ event::{
CreateAuraEntityEvent, CreateItemDropEvent, CreateNpcEvent, CreateObjectEvent, CreateAuraEntityEvent, CreateItemDropEvent, CreateNpcEvent, CreateObjectEvent,
@ -25,6 +25,7 @@ use common::{
}; };
use common_net::{msg::ServerGeneral, sync::WorldSyncExt}; use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
use specs::{Builder, Entity as EcsEntity, WorldExt}; use specs::{Builder, Entity as EcsEntity, WorldExt};
use std::time::Duration;
use vek::{Rgb, Vec3}; use vek::{Rgb, Vec3};
use super::group_manip::update_map_markers; use super::group_manip::update_map_markers;
@ -491,7 +492,7 @@ pub fn handle_create_object(
} }
pub fn handle_create_aura_entity(server: &mut Server, ev: CreateAuraEntityEvent) { pub fn handle_create_aura_entity(server: &mut Server, ev: CreateAuraEntityEvent) {
server let mut entity = server
.state .state
.ecs_mut() .ecs_mut()
.create_entity_synced() .create_entity_synced()
@ -499,6 +500,20 @@ pub fn handle_create_aura_entity(server: &mut Server, ev: CreateAuraEntityEvent)
.with(comp::Vel(Vec3::zero())) .with(comp::Vel(Vec3::zero()))
.with(comp::Ori::default()) .with(comp::Ori::default())
.with(ev.auras) .with(ev.auras)
.with(comp::Alignment::Owned(ev.creator_uid)) .with(comp::Alignment::Owned(ev.creator_uid));
.build();
// If a duration is specified, create a projectile component for the entity
if let Some(dur) = ev.duration {
let projectile = Projectile {
hit_solid: Vec::new(),
hit_entity: Vec::new(),
time_left: Duration::from_secs_f64(dur.0),
owner: Some(ev.creator_uid),
ignore_group: true,
is_sticky: false,
is_point: false,
};
entity = entity.with(projectile);
}
entity.build();
} }

View File

@ -1570,20 +1570,22 @@ impl ServerEvent for AuraEvent {
(mut auras, mut entered_auras): Self::SystemData<'_>, (mut auras, mut entered_auras): Self::SystemData<'_>,
) { ) {
for ev in events { for ev in events {
if let (Some(mut auras), Some(mut entered_auras)) = use aura::AuraChange;
(auras.get_mut(ev.entity), entered_auras.get_mut(ev.entity)) match ev.aura_change {
{ AuraChange::Add(new_aura) => {
use aura::AuraChange; if let Some(mut auras) = auras.get_mut(ev.entity) {
match ev.aura_change {
AuraChange::Add(new_aura) => {
auras.insert(new_aura); auras.insert(new_aura);
}, }
AuraChange::RemoveByKey(keys) => { },
AuraChange::RemoveByKey(keys) => {
if let Some(mut auras) = auras.get_mut(ev.entity) {
for key in keys { for key in keys {
auras.remove(key); auras.remove(key);
} }
}, }
AuraChange::EnterAura(uid, key, variant) => { },
AuraChange::EnterAura(uid, key, variant) => {
if let Some(mut entered_auras) = entered_auras.get_mut(ev.entity) {
entered_auras entered_auras
.auras .auras
.entry(variant) .entry(variant)
@ -1591,8 +1593,10 @@ impl ServerEvent for AuraEvent {
entered_auras.insert((uid, key)); entered_auras.insert((uid, key));
}) })
.or_insert_with(|| <_ as Into<_>>::into([(uid, key)])); .or_insert_with(|| <_ as Into<_>>::into([(uid, key)]));
}, }
AuraChange::ExitAura(uid, key, variant) => { },
AuraChange::ExitAura(uid, key, variant) => {
if let Some(mut entered_auras) = entered_auras.get_mut(ev.entity) {
if let Some(entered_auras_variant) = entered_auras.auras.get_mut(&variant) { if let Some(entered_auras_variant) = entered_auras.auras.get_mut(&variant) {
entered_auras_variant.remove(&(uid, key)); entered_auras_variant.remove(&(uid, key));
@ -1600,8 +1604,8 @@ impl ServerEvent for AuraEvent {
entered_auras.auras.remove(&variant); entered_auras.auras.remove(&variant);
} }
} }
}, }
} },
} }
} }
} }