mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Combo counter now uses outcomes.
This commit is contained in:
parent
c29cb037e7
commit
940b4b5de7
@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use specs::{Component, DerefFlaggedStorage};
|
use specs::{Component, DerefFlaggedStorage};
|
||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
|
|
||||||
|
pub const COMBO_DECAY_START: f64 = 5.0; // seconds
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Combo {
|
pub struct Combo {
|
||||||
counter: u32,
|
counter: u32,
|
||||||
@ -24,14 +26,14 @@ impl Combo {
|
|||||||
|
|
||||||
pub fn reset(&mut self) { self.counter = 0; }
|
pub fn reset(&mut self) { self.counter = 0; }
|
||||||
|
|
||||||
pub fn increase_by(&mut self, amount: u32, time: f64) {
|
pub fn change_by(&mut self, amount: i32, time: f64) {
|
||||||
self.counter = self.counter.saturating_add(amount);
|
if amount > 0 {
|
||||||
|
self.counter = self.counter.saturating_add(amount as u32);
|
||||||
|
} else {
|
||||||
|
self.counter = self.counter.saturating_sub(amount.abs() as u32);
|
||||||
|
}
|
||||||
self.last_increase = time;
|
self.last_increase = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrease_by(&mut self, amount: u32) {
|
|
||||||
self.counter = self.counter.saturating_sub(amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Combo {
|
impl Component for Combo {
|
||||||
|
@ -37,16 +37,20 @@ pub enum Outcome {
|
|||||||
// TODO: Access ECS to get position from Uid to conserve bandwidth
|
// TODO: Access ECS to get position from Uid to conserve bandwidth
|
||||||
pos: Vec3<f32>,
|
pos: Vec3<f32>,
|
||||||
},
|
},
|
||||||
|
ComboChange {
|
||||||
|
uid: Uid,
|
||||||
|
combo: u32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Outcome {
|
impl Outcome {
|
||||||
pub fn get_pos(&self) -> Option<Vec3<f32>> {
|
pub fn get_pos(&self) -> Option<Vec3<f32>> {
|
||||||
match self {
|
match self {
|
||||||
Outcome::Explosion { pos, .. } => Some(*pos),
|
Outcome::Explosion { pos, .. }
|
||||||
Outcome::ProjectileShot { pos, .. } => Some(*pos),
|
| Outcome::ProjectileShot { pos, .. }
|
||||||
Outcome::Beam { pos, .. } => Some(*pos),
|
| Outcome::Beam { pos, .. }
|
||||||
Outcome::ExpChange { .. } => None,
|
| Outcome::SkillPointGain { pos, .. } => Some(*pos),
|
||||||
Outcome::SkillPointGain { pos, .. } => Some(*pos),
|
Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
|
self,
|
||||||
skills::{GeneralSkill, Skill},
|
skills::{GeneralSkill, Skill},
|
||||||
Body, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, Poise,
|
Body, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, Poise,
|
||||||
PoiseChange, PoiseSource, Pos, Stats,
|
PoiseChange, PoiseSource, Pos, Stats,
|
||||||
@ -18,7 +19,6 @@ use vek::Vec3;
|
|||||||
|
|
||||||
const ENERGY_REGEN_ACCEL: f32 = 10.0;
|
const ENERGY_REGEN_ACCEL: f32 = 10.0;
|
||||||
const POISE_REGEN_ACCEL: f32 = 2.0;
|
const POISE_REGEN_ACCEL: f32 = 2.0;
|
||||||
const COMBO_DECAY_START: f64 = 5.0; // seconds
|
|
||||||
|
|
||||||
#[derive(SystemData)]
|
#[derive(SystemData)]
|
||||||
pub struct ReadData<'a> {
|
pub struct ReadData<'a> {
|
||||||
@ -264,7 +264,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
// Decay combo
|
// Decay combo
|
||||||
for (_, mut combo) in (&read_data.entities, &mut combos).join() {
|
for (_, mut combo) in (&read_data.entities, &mut combos).join() {
|
||||||
if combo.counter() > 0 && read_data.time.0 - combo.last_increase() > COMBO_DECAY_START {
|
if combo.counter() > 0
|
||||||
|
&& read_data.time.0 - combo.last_increase() > comp::combo::COMBO_DECAY_START
|
||||||
|
{
|
||||||
combo.reset();
|
combo.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -895,11 +895,14 @@ fn handle_exp_gain(
|
|||||||
pub fn handle_combo_change(server: &Server, entity: EcsEntity, change: i32) {
|
pub fn handle_combo_change(server: &Server, entity: EcsEntity, change: i32) {
|
||||||
let ecs = &server.state.ecs();
|
let ecs = &server.state.ecs();
|
||||||
if let Some(mut combo) = ecs.write_storage::<comp::Combo>().get_mut(entity) {
|
if let Some(mut combo) = ecs.write_storage::<comp::Combo>().get_mut(entity) {
|
||||||
if change > 0 {
|
let time = ecs.read_resource::<Time>();
|
||||||
let time = ecs.read_resource::<Time>();
|
let mut outcomes = ecs.write_resource::<Vec<Outcome>>();
|
||||||
combo.increase_by(change as u32, time.0);
|
combo.change_by(change, time.0);
|
||||||
} else {
|
if let Some(uid) = ecs.read_storage::<Uid>().get(entity) {
|
||||||
combo.decrease_by(change.abs() as u32);
|
outcomes.push(Outcome::ComboChange {
|
||||||
|
uid: *uid,
|
||||||
|
combo: combo.counter(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,7 +364,7 @@ impl SfxMgr {
|
|||||||
audio.play_sfx(file_ref, *pos, None);
|
audio.play_sfx(file_ref, *pos, None);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outcome::ExpChange { .. } => {},
|
Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@ use crate::{
|
|||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::resources::Time;
|
|
||||||
use common::{
|
use common::{
|
||||||
combat,
|
combat,
|
||||||
comp::{
|
comp::{
|
||||||
@ -309,6 +308,13 @@ pub struct SkillPointGain {
|
|||||||
pub timer: f32,
|
pub timer: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct ComboFloater {
|
||||||
|
pub owner: Uid,
|
||||||
|
pub combo: u32,
|
||||||
|
pub timer: f64,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DebugInfo {
|
pub struct DebugInfo {
|
||||||
pub tps: f64,
|
pub tps: f64,
|
||||||
pub frame_time: Duration,
|
pub frame_time: Duration,
|
||||||
@ -732,6 +738,7 @@ pub struct Hud {
|
|||||||
crosshair_opacity: f32,
|
crosshair_opacity: f32,
|
||||||
exp_floaters: Vec<ExpFloater>,
|
exp_floaters: Vec<ExpFloater>,
|
||||||
skill_point_displays: Vec<SkillPointGain>,
|
skill_point_displays: Vec<SkillPointGain>,
|
||||||
|
combo_floaters: VecDeque<ComboFloater>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hud {
|
impl Hud {
|
||||||
@ -840,6 +847,7 @@ impl Hud {
|
|||||||
crosshair_opacity: 0.0,
|
crosshair_opacity: 0.0,
|
||||||
exp_floaters: Vec::new(),
|
exp_floaters: Vec::new(),
|
||||||
skill_point_displays: Vec::new(),
|
skill_point_displays: Vec::new(),
|
||||||
|
combo_floaters: VecDeque::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -887,7 +895,7 @@ impl Hud {
|
|||||||
let items = ecs.read_storage::<comp::Item>();
|
let items = ecs.read_storage::<comp::Item>();
|
||||||
let inventories = ecs.read_storage::<comp::Inventory>();
|
let inventories = ecs.read_storage::<comp::Inventory>();
|
||||||
let msm = ecs.read_resource::<MaterialStatManifest>();
|
let msm = ecs.read_resource::<MaterialStatManifest>();
|
||||||
let entities = ecs.entities();
|
let entities = ecs.entities();
|
||||||
let me = client.entity();
|
let me = client.entity();
|
||||||
|
|
||||||
if (client.pending_trade().is_some() && !self.show.trade)
|
if (client.pending_trade().is_some() && !self.show.trade)
|
||||||
@ -2158,8 +2166,19 @@ impl Hud {
|
|||||||
let controllers = ecs.read_storage::<comp::Controller>();
|
let controllers = ecs.read_storage::<comp::Controller>();
|
||||||
let ability_map = ecs.fetch::<comp::item::tool::AbilityMap>();
|
let ability_map = ecs.fetch::<comp::item::tool::AbilityMap>();
|
||||||
let bodies = ecs.read_storage::<comp::Body>();
|
let bodies = ecs.read_storage::<comp::Body>();
|
||||||
let combos = ecs.read_storage::<comp::Combo>();
|
// Combo floater stuffs
|
||||||
let time = ecs.read_resource::<Time>();
|
for combo_floater in self.combo_floaters.iter_mut() {
|
||||||
|
combo_floater.timer -= dt.as_secs_f64();
|
||||||
|
}
|
||||||
|
self.combo_floaters.retain(|f| f.timer > 0_f64);
|
||||||
|
let combo = if let Some(uid) = ecs.read_storage::<Uid>().get(entity) {
|
||||||
|
self.combo_floaters
|
||||||
|
.iter()
|
||||||
|
.find(|c| c.owner == *uid)
|
||||||
|
.copied()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
if let (
|
if let (
|
||||||
Some(health),
|
Some(health),
|
||||||
@ -2167,16 +2186,12 @@ impl Hud {
|
|||||||
Some(energy),
|
Some(energy),
|
||||||
Some(_character_state),
|
Some(_character_state),
|
||||||
Some(_controller),
|
Some(_controller),
|
||||||
Some(combo),
|
|
||||||
time,
|
|
||||||
) = (
|
) = (
|
||||||
healths.get(entity),
|
healths.get(entity),
|
||||||
inventories.get(entity),
|
inventories.get(entity),
|
||||||
energies.get(entity),
|
energies.get(entity),
|
||||||
character_states.get(entity),
|
character_states.get(entity),
|
||||||
controllers.get(entity).map(|c| &c.inputs),
|
controllers.get(entity).map(|c| &c.inputs),
|
||||||
combos.get(entity),
|
|
||||||
time,
|
|
||||||
) {
|
) {
|
||||||
Skillbar::new(
|
Skillbar::new(
|
||||||
global_state,
|
global_state,
|
||||||
@ -2196,8 +2211,7 @@ impl Hud {
|
|||||||
i18n,
|
i18n,
|
||||||
&ability_map,
|
&ability_map,
|
||||||
&msm,
|
&msm,
|
||||||
&combo,
|
combo,
|
||||||
&time,
|
|
||||||
)
|
)
|
||||||
.set(self.ids.skillbar, ui_widgets);
|
.set(self.ids.skillbar, ui_widgets);
|
||||||
}
|
}
|
||||||
@ -3211,6 +3225,11 @@ impl Hud {
|
|||||||
total_points: *total_points,
|
total_points: *total_points,
|
||||||
timer: 5.0,
|
timer: 5.0,
|
||||||
}),
|
}),
|
||||||
|
Outcome::ComboChange { uid, combo } => self.combo_floaters.push_front(ComboFloater {
|
||||||
|
owner: *uid,
|
||||||
|
combo: *combo,
|
||||||
|
timer: comp::combo::COMBO_DECAY_START,
|
||||||
|
}),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use super::{
|
|||||||
STAMINA_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0,
|
STAMINA_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
hud::ComboFloater,
|
||||||
i18n::Localization,
|
i18n::Localization,
|
||||||
ui::{
|
ui::{
|
||||||
fonts::Fonts,
|
fonts::Fonts,
|
||||||
@ -15,16 +16,14 @@ use crate::{
|
|||||||
window::GameInput,
|
window::GameInput,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::comp::{
|
||||||
comp::{
|
self,
|
||||||
inventory::slot::EquipSlot,
|
inventory::slot::EquipSlot,
|
||||||
item::{
|
item::{
|
||||||
tool::{AbilityMap, Tool, ToolKind},
|
tool::{AbilityMap, Tool, ToolKind},
|
||||||
Hands, Item, ItemKind, MaterialStatManifest,
|
Hands, Item, ItemKind, MaterialStatManifest,
|
||||||
},
|
|
||||||
Combo, Energy, Health, Inventory,
|
|
||||||
},
|
},
|
||||||
resources::Time,
|
Energy, Health, Inventory,
|
||||||
};
|
};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
color,
|
color,
|
||||||
@ -149,8 +148,7 @@ pub struct Skillbar<'a> {
|
|||||||
common: widget::CommonBuilder,
|
common: widget::CommonBuilder,
|
||||||
ability_map: &'a AbilityMap,
|
ability_map: &'a AbilityMap,
|
||||||
msm: &'a MaterialStatManifest,
|
msm: &'a MaterialStatManifest,
|
||||||
combo: &'a Combo,
|
combo: Option<ComboFloater>,
|
||||||
time: &'a Time,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Skillbar<'a> {
|
impl<'a> Skillbar<'a> {
|
||||||
@ -173,8 +171,7 @@ impl<'a> Skillbar<'a> {
|
|||||||
localized_strings: &'a Localization,
|
localized_strings: &'a Localization,
|
||||||
ability_map: &'a AbilityMap,
|
ability_map: &'a AbilityMap,
|
||||||
msm: &'a MaterialStatManifest,
|
msm: &'a MaterialStatManifest,
|
||||||
combo: &'a Combo,
|
combo: Option<ComboFloater>,
|
||||||
time: &'a Time,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
global_state,
|
global_state,
|
||||||
@ -196,7 +193,6 @@ impl<'a> Skillbar<'a> {
|
|||||||
ability_map,
|
ability_map,
|
||||||
msm,
|
msm,
|
||||||
combo,
|
combo,
|
||||||
time,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -925,49 +921,50 @@ impl<'a> Widget for Skillbar<'a> {
|
|||||||
.set(state.ids.m2_ico, ui);
|
.set(state.ids.m2_ico, ui);
|
||||||
|
|
||||||
// Combo Counter
|
// Combo Counter
|
||||||
if self.combo.counter() > 0 {
|
if let Some(combo) = self.combo {
|
||||||
let combo_txt = format!("{} Combo", self.combo.counter());
|
if combo.combo > 0 {
|
||||||
let combo_cnt = self.combo.counter() as f32;
|
let combo_txt = format!("{} Combo", combo.combo);
|
||||||
let time_since_last_update = self.combo.last_increase() - self.time.0 as f64;
|
let combo_cnt = combo.combo as f32;
|
||||||
let fnt_col = Color::Rgba(
|
let time_since_last_update = comp::combo::COMBO_DECAY_START - combo.timer;
|
||||||
// White -> Yellow -> Red text color gradient depending on count
|
let fnt_col = Color::Rgba(
|
||||||
(1.0 - combo_cnt / (combo_cnt + tweak!(1.0))).max(0.79),
|
// White -> Yellow -> Red text color gradient depending on count
|
||||||
(1.0 - combo_cnt / (combo_cnt + tweak!(80.0))).max(0.19),
|
(1.0 - combo_cnt / (combo_cnt + tweak!(1.0))).max(0.79),
|
||||||
(1.0 - combo_cnt / (combo_cnt + tweak!(5.0))).max(0.17),
|
(1.0 - combo_cnt / (combo_cnt + tweak!(80.0))).max(0.19),
|
||||||
(time_since_last_update - 8.0).min(1.0) as f32,
|
(1.0 - combo_cnt / (combo_cnt + tweak!(5.0))).max(0.17),
|
||||||
);
|
|
||||||
|
|
||||||
let fnt_size = ((14.0 + self.combo.counter() as f32 * tweak!(0.5)).min(tweak!(20.0)))
|
|
||||||
as u32
|
|
||||||
+ if (time_since_last_update - 12.0) < 1.0 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}; // Increase size for higher counts, "flash" on update by increasing the font size by 2
|
|
||||||
println!("{}", time_since_last_update); // REMOVE THIS
|
|
||||||
Rectangle::fill_with([10.0, 10.0], color::TRANSPARENT)
|
|
||||||
.middle_of(ui.window)
|
|
||||||
.set(state.ids.combo_align, ui);
|
|
||||||
Text::new(combo_txt.as_str())
|
|
||||||
.mid_bottom_with_margin_on(
|
|
||||||
state.ids.combo_align,
|
|
||||||
tweak!(-350.0) + time_since_last_update * tweak!(4.0) - 8.0,
|
|
||||||
)
|
|
||||||
.font_size(self.fonts.cyri.scale(fnt_size))
|
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
|
||||||
.color(Color::Rgba(
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
(time_since_last_update - 8.0).min(1.0) as f32,
|
(time_since_last_update - 8.0).min(1.0) as f32,
|
||||||
))
|
);
|
||||||
.set(state.ids.combo_bg, ui);
|
|
||||||
Text::new(combo_txt.as_str())
|
let fnt_size = ((14.0 + combo.timer as f32 * tweak!(0.5)).min(tweak!(20.0))) as u32
|
||||||
.bottom_right_with_margins_on(state.ids.combo_bg, 1.0, 1.0)
|
+ if (time_since_last_update - 12.0) < 1.0 {
|
||||||
.font_size(self.fonts.cyri.scale(fnt_size))
|
1
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
} else {
|
||||||
.color(fnt_col)
|
0
|
||||||
.set(state.ids.combo, ui);
|
}; // Increase size for higher counts, "flash" on update by increasing the font size by 2
|
||||||
|
//dbg!(combo); // Delete this before merging
|
||||||
|
Rectangle::fill_with([10.0, 10.0], color::TRANSPARENT)
|
||||||
|
.middle_of(ui.window)
|
||||||
|
.set(state.ids.combo_align, ui);
|
||||||
|
Text::new(combo_txt.as_str())
|
||||||
|
.mid_bottom_with_margin_on(
|
||||||
|
state.ids.combo_align,
|
||||||
|
tweak!(-350.0) + time_since_last_update * tweak!(4.0) - 8.0,
|
||||||
|
)
|
||||||
|
.font_size(self.fonts.cyri.scale(fnt_size))
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.color(Color::Rgba(
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
(time_since_last_update - 8.0).min(1.0) as f32,
|
||||||
|
))
|
||||||
|
.set(state.ids.combo_bg, ui);
|
||||||
|
Text::new(combo_txt.as_str())
|
||||||
|
.bottom_right_with_margins_on(state.ids.combo_bg, 1.0, 1.0)
|
||||||
|
.font_size(self.fonts.cyri.scale(fnt_size))
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.color(fnt_col)
|
||||||
|
.set(state.ids.combo, ui);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user