Make durations and damage depend on weapon type

This commit is contained in:
timokoesters 2020-03-15 14:34:17 +01:00
parent 598a4c6cbb
commit 447617dc69
18 changed files with 83 additions and 96 deletions

View File

@ -5,10 +5,6 @@ Item(
ToolData ( ToolData (
kind: Hammer, kind: Hammer,
equip_time_millis: 1000, equip_time_millis: 1000,
attack_buildup_millis: 700,
attack_recover_millis: 100,
range: 3,
base_damage: 10,
) )
) )
) )

View File

@ -5,10 +5,6 @@ Item(
ToolData ( ToolData (
kind: Staff, kind: Staff,
equip_time_millis: 800, equip_time_millis: 800,
attack_buildup_millis: 400,
attack_recover_millis: 300,
range: 3,
base_damage: 10,
) )
), ),
) )

View File

@ -5,10 +5,6 @@ Item(
ToolData ( ToolData (
kind: Axe, kind: Axe,
equip_time_millis: 1000, equip_time_millis: 1000,
attack_buildup_millis: 700,
attack_recover_millis: 100,
range: 3,
base_damage: 10,
) )
), ),
) )

View File

@ -5,10 +5,6 @@ Item(
ToolData ( ToolData (
kind: Bow, kind: Bow,
equip_time_millis: 800, equip_time_millis: 800,
attack_buildup_millis: 0,
attack_recover_millis: 800,
range: 3,
base_damage: 10,
) )
), ),
) )

View File

@ -5,10 +5,6 @@ Item(
ToolData ( ToolData (
kind: Dagger, kind: Dagger,
equip_time_millis: 300, equip_time_millis: 300,
attack_buildup_millis: 100,
attack_recover_millis: 400,
range: 3,
base_damage: 10,
) )
), ),
) )

View File

@ -5,10 +5,6 @@ Item(
ToolData ( ToolData (
kind: Hammer, kind: Hammer,
equip_time_millis: 1000, equip_time_millis: 1000,
attack_buildup_millis: 700,
attack_recover_millis: 100,
range: 3,
base_damage: 10,
) )
), ),
) )

View File

@ -5,10 +5,6 @@ Item(
ToolData ( ToolData (
kind: Sword(Rapier), kind: Sword(Rapier),
equip_time_millis: 800, equip_time_millis: 800,
attack_buildup_millis: 100,
attack_recover_millis: 500,
range: 3,
base_damage: 10,
) )
), ),
) )

View File

@ -10,14 +10,15 @@ pub enum CharacterAbility {
BasicAttack { BasicAttack {
buildup_duration: Duration, buildup_duration: Duration,
recover_duration: Duration, recover_duration: Duration,
base_damage: u32,
}, },
BasicBlock, BasicBlock,
Roll, Roll,
ChargeAttack, ChargeAttack,
TimedCombo { TimedCombo {
tool: ToolData,
buildup_duration: Duration, buildup_duration: Duration,
recover_duration: Duration, recover_duration: Duration,
base_damage: u32,
}, },
} }
@ -47,10 +48,12 @@ impl From<CharacterAbility> for CharacterState {
CharacterAbility::BasicAttack { CharacterAbility::BasicAttack {
buildup_duration, buildup_duration,
recover_duration, recover_duration,
base_damage,
} => CharacterState::BasicAttack(basic_attack::Data { } => CharacterState::BasicAttack(basic_attack::Data {
exhausted: false, exhausted: false,
buildup_duration, buildup_duration,
recover_duration, recover_duration,
base_damage,
}), }),
CharacterAbility::BasicBlock { .. } => CharacterState::BasicBlock, CharacterAbility::BasicBlock { .. } => CharacterState::BasicBlock,
CharacterAbility::Roll { .. } => CharacterState::Roll(roll::Data { CharacterAbility::Roll { .. } => CharacterState::Roll(roll::Data {
@ -62,16 +65,16 @@ impl From<CharacterAbility> for CharacterState {
}) })
}, },
CharacterAbility::TimedCombo { CharacterAbility::TimedCombo {
tool,
buildup_duration, buildup_duration,
recover_duration, recover_duration,
base_damage,
} => CharacterState::TimedCombo(timed_combo::Data { } => CharacterState::TimedCombo(timed_combo::Data {
tool,
buildup_duration, buildup_duration,
recover_duration, recover_duration,
stage: 0, stage: 0,
stage_exhausted: false, stage_exhausted: false,
stage_time_active: Duration::default(), stage_time_active: Duration::default(),
base_damage,
}), }),
} }
} }

View File

@ -29,7 +29,7 @@ pub enum CharacterState {
/// Player is busy equipping or unequipping weapons /// Player is busy equipping or unequipping weapons
Equipping(equipping::Data), Equipping(equipping::Data),
/// Player is holding a weapon and can perform other actions /// Player is holding a weapon and can perform other actions
Wielding(wielding::Data), Wielding,
/// Player rushes forward and slams an enemy with their weapon /// Player rushes forward and slams an enemy with their weapon
ChargeAttack(charge_attack::Data), ChargeAttack(charge_attack::Data),
/// A dodge where player can roll /// A dodge where player can roll
@ -47,7 +47,7 @@ pub enum CharacterState {
impl CharacterState { impl CharacterState {
pub fn is_wield(&self) -> bool { pub fn is_wield(&self) -> bool {
match self { match self {
CharacterState::Wielding(_) CharacterState::Wielding
| CharacterState::BasicAttack(_) | CharacterState::BasicAttack(_)
| CharacterState::TimedCombo(_) | CharacterState::TimedCombo(_)
| CharacterState::BasicBlock => true, | CharacterState::BasicBlock => true,

View File

@ -37,41 +37,37 @@ impl ToolData {
use ToolKind::*; use ToolKind::*;
match self.kind { match self.kind {
Sword(_) => vec![TimedCombo { Sword(_) => vec![BasicAttack {
buildup_duration: Duration::from_millis(500), buildup_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(1000), recover_duration: Duration::from_millis(500),
tool: *self, base_damage: 60,
}], }],
Axe => vec![BasicAttack { Axe => vec![BasicAttack {
buildup_duration: Duration::from_millis(1000), buildup_duration: Duration::from_millis(700),
recover_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(100),
base_damage: 80,
}], }],
Hammer => vec![BasicAttack { Hammer => vec![BasicAttack {
buildup_duration: Duration::from_millis(1000), buildup_duration: Duration::from_millis(700),
recover_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(300),
}], base_damage: 100,
Bow => vec![BasicAttack {
buildup_duration: Duration::from_millis(1000),
recover_duration: Duration::from_millis(500),
}], }],
Bow => vec![],
Dagger => vec![BasicAttack { Dagger => vec![BasicAttack {
buildup_duration: Duration::from_millis(1000), buildup_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(400),
base_damage: 50,
}], }],
Staff => vec![BasicAttack { Staff => vec![BasicAttack {
buildup_duration: Duration::from_millis(1000), buildup_duration: Duration::from_millis(400),
recover_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(300),
}], base_damage: 70,
Shield => vec![BasicAttack {
buildup_duration: Duration::from_millis(1000),
recover_duration: Duration::from_millis(500),
}], }],
Shield => vec![],
Debug(kind) => match kind { Debug(kind) => match kind {
Boost => vec![], Boost => vec![],
Possess => vec![], Possess => vec![],
}, },
_ => vec![],
} }
} }
} }
@ -125,18 +121,24 @@ pub enum Ingredient {
pub struct ToolData { pub struct ToolData {
pub kind: ToolKind, pub kind: ToolKind,
equip_time_millis: u64, equip_time_millis: u64,
attack_buildup_millis: u64, // TODO: item specific abilities
attack_recover_millis: u64,
range: u32,
pub base_damage: u32,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ItemKind { pub enum ItemKind {
/// Something wieldable
Tool(ToolData), Tool(ToolData),
Armor { kind: Armor, power: u32 }, Armor {
Consumable { kind: Consumable, effect: Effect }, kind: Armor,
Utility { kind: Utility }, power: u32,
},
Consumable {
kind: Consumable,
effect: Effect,
},
Utility {
kind: Utility,
},
Ingredient(Ingredient), Ingredient(Ingredient),
} }

View File

@ -134,7 +134,7 @@ impl Stats {
} }
// TODO: Delete this once stat points will be a thing // TODO: Delete this once stat points will be a thing
pub fn update_max_hp(&mut self) { self.health.set_maximum(27 + 15 * self.level.amount); } pub fn update_max_hp(&mut self) { self.health.set_maximum(200 + 47 * self.level.amount); }
} }
impl Stats { impl Stats {

View File

@ -11,6 +11,8 @@ pub struct Data {
pub buildup_duration: Duration, pub buildup_duration: Duration,
/// How long the state has until exiting /// How long the state has until exiting
pub recover_duration: Duration, pub recover_duration: Duration,
/// Base damage
pub base_damage: u32,
/// Whether the attack can deal more damage /// Whether the attack can deal more damage
pub exhausted: bool, pub exhausted: bool,
} }
@ -37,6 +39,7 @@ impl CharacterBehavior for Data {
.checked_sub(Duration::from_secs_f32(data.dt.0)) .checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(), .unwrap_or_default(),
recover_duration: self.recover_duration, recover_duration: self.recover_duration,
base_damage: self.base_damage,
exhausted: false, exhausted: false,
}); });
} }
@ -44,7 +47,7 @@ impl CharacterBehavior for Data {
else if !self.exhausted { else if !self.exhausted {
if let Some(tool) = unwrap_tool_data(data) { if let Some(tool) = unwrap_tool_data(data) {
data.updater.insert(data.entity, Attacking { data.updater.insert(data.entity, Attacking {
base_damage: tool.base_damage, base_damage: self.base_damage,
applied: false, applied: false,
hit_count: 0, hit_count: 0,
}); });
@ -53,6 +56,7 @@ impl CharacterBehavior for Data {
update.character = CharacterState::BasicAttack(Data { update.character = CharacterState::BasicAttack(Data {
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
recover_duration: self.recover_duration, recover_duration: self.recover_duration,
base_damage: self.base_damage,
exhausted: true, exhausted: true,
}); });
} }
@ -64,13 +68,14 @@ impl CharacterBehavior for Data {
.recover_duration .recover_duration
.checked_sub(Duration::from_secs_f32(data.dt.0)) .checked_sub(Duration::from_secs_f32(data.dt.0))
.unwrap_or_default(), .unwrap_or_default(),
base_damage: self.base_damage,
exhausted: true, exhausted: true,
}); });
} }
// Done // Done
else { else {
if let Some(tool) = unwrap_tool_data(data) { if let Some(tool) = unwrap_tool_data(data) {
update.character = CharacterState::Wielding(wielding::Data { tool }); update.character = CharacterState::Wielding;
// Make sure attack component is removed // Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity); data.updater.remove::<Attacking>(data.entity);
} else { } else {

View File

@ -31,7 +31,7 @@ impl CharacterBehavior for Data {
if self.time_left == Duration::default() { if self.time_left == Duration::default() {
// Wield delay has expired // Wield delay has expired
update.character = CharacterState::Wielding(wielding::Data { tool: self.tool }); update.character = CharacterState::Wielding;
} else { } else {
// Wield delay hasn't expired yet // Wield delay hasn't expired yet
// Update wield delay // Update wield delay

View File

@ -18,6 +18,7 @@ impl CharacterBehavior for Data {
local_events: VecDeque::new(), local_events: VecDeque::new(),
server_events: VecDeque::new(), server_events: VecDeque::new(),
}; };
handle_move(data, &mut update); handle_move(data, &mut update);
handle_jump(data, &mut update); handle_jump(data, &mut update);
handle_wield(data, &mut update); handle_wield(data, &mut update);

View File

@ -1,6 +1,5 @@
use crate::{ use crate::{
comp::{Attacking, CharacterState, EnergySource, StateUpdate, ToolData}, comp::{Attacking, CharacterState, EnergySource, StateUpdate},
states::wielding,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::{collections::VecDeque, time::Duration}; use std::{collections::VecDeque, time::Duration};
@ -16,8 +15,8 @@ pub struct Data {
pub recover_duration: Duration, pub recover_duration: Duration,
/// Tracks how long current stage has been active /// Tracks how long current stage has been active
pub stage_time_active: Duration, pub stage_time_active: Duration,
/// `ToolData` to be sent to `Attacking` component /// Base damage
pub tool: ToolData, pub base_damage: u32,
} }
impl CharacterBehavior for Data { impl CharacterBehavior for Data {
@ -44,17 +43,17 @@ impl CharacterBehavior for Data {
if data.inputs.primary.is_just_pressed() { if data.inputs.primary.is_just_pressed() {
println!("Failed"); println!("Failed");
// They failed, go back to `Wielding` // They failed, go back to `Wielding`
update.character = CharacterState::Wielding(wielding::Data { tool: self.tool }); update.character = CharacterState::Wielding;
} }
// Keep updating // Keep updating
else { else {
update.character = CharacterState::TimedCombo(Data { update.character = CharacterState::TimedCombo(Data {
tool: self.tool,
stage: self.stage, stage: self.stage,
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
recover_duration: self.recover_duration, recover_duration: self.recover_duration,
stage_exhausted: false, stage_exhausted: false,
stage_time_active: new_stage_time_active, stage_time_active: new_stage_time_active,
base_damage: self.base_damage,
}); });
} }
} }
@ -62,18 +61,18 @@ impl CharacterBehavior for Data {
else if !self.stage_exhausted { else if !self.stage_exhausted {
// Swing hits // Swing hits
data.updater.insert(data.entity, Attacking { data.updater.insert(data.entity, Attacking {
base_damage: self.tool.base_damage, base_damage: self.base_damage,
applied: false, applied: false,
hit_count: 0, hit_count: 0,
}); });
update.character = CharacterState::TimedCombo(Data { update.character = CharacterState::TimedCombo(Data {
tool: self.tool,
stage: self.stage, stage: self.stage,
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
recover_duration: self.recover_duration, recover_duration: self.recover_duration,
stage_exhausted: true, stage_exhausted: true,
stage_time_active: new_stage_time_active, stage_time_active: new_stage_time_active,
base_damage: self.base_damage,
}); });
} }
// Swing recovery window // Swing recovery window
@ -87,12 +86,12 @@ impl CharacterBehavior for Data {
if data.inputs.primary.is_just_pressed() { if data.inputs.primary.is_just_pressed() {
println!("Transition"); println!("Transition");
update.character = CharacterState::TimedCombo(Data { update.character = CharacterState::TimedCombo(Data {
tool: self.tool,
stage: self.stage + 1, stage: self.stage + 1,
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
recover_duration: self.recover_duration, recover_duration: self.recover_duration,
stage_exhausted: true, stage_exhausted: true,
stage_time_active: Duration::default(), stage_time_active: Duration::default(),
base_damage: self.base_damage,
}); });
} }
// Player didn't click this frame // Player didn't click this frame
@ -100,19 +99,19 @@ impl CharacterBehavior for Data {
// Update state // Update state
println!("Missed"); println!("Missed");
update.character = CharacterState::TimedCombo(Data { update.character = CharacterState::TimedCombo(Data {
tool: self.tool,
stage: self.stage, stage: self.stage,
buildup_duration: self.buildup_duration, buildup_duration: self.buildup_duration,
recover_duration: self.recover_duration, recover_duration: self.recover_duration,
stage_exhausted: true, stage_exhausted: true,
stage_time_active: new_stage_time_active, stage_time_active: new_stage_time_active,
base_damage: self.base_damage,
}); });
} }
} }
// Stage expired but missed transition to next stage // Stage expired but missed transition to next stage
else { else {
// Back to `Wielding` // Back to `Wielding`
update.character = CharacterState::Wielding(wielding::Data { tool: self.tool }); update.character = CharacterState::Wielding;
// Make sure attack component is removed // Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity); data.updater.remove::<Attacking>(data.entity);
} }
@ -121,12 +120,12 @@ impl CharacterBehavior for Data {
else { else {
println!("Success!"); println!("Success!");
// Back to `Wielding` // Back to `Wielding`
update.character = CharacterState::Wielding(wielding::Data { tool: self.tool }); update.character = CharacterState::Wielding;
// Make sure attack component is removed // Make sure attack component is removed
data.updater.remove::<Attacking>(data.entity); data.updater.remove::<Attacking>(data.entity);
} }
// Subtract energy on successful hit // Grant energy on successful hit
if let Some(attack) = data.attacking { if let Some(attack) = data.attacking {
if attack.applied && attack.hit_count > 0 { if attack.applied && attack.hit_count > 0 {
println!("Hit"); println!("Hit");

View File

@ -1,14 +1,11 @@
use super::utils::*; use super::utils::*;
use crate::{ use crate::{
comp::{StateUpdate, ToolData}, comp::StateUpdate,
sys::character_behavior::{CharacterBehavior, JoinData}, sys::character_behavior::{CharacterBehavior, JoinData},
}; };
use std::collections::VecDeque; use std::collections::VecDeque;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct Data { pub struct Data;
/// The weapon being wielded
pub tool: ToolData,
}
impl CharacterBehavior for Data { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate { fn behavior(&self, data: &JoinData) -> StateUpdate {

View File

@ -172,17 +172,17 @@ impl<'a> System<'a> for Sys {
} }
let mut state_update = match j.character { let mut state_update = match j.character {
CharacterState::Idle => states::idle::Data::behavior(&states::idle::Data, &j), CharacterState::Idle => states::idle::Data.behavior(&j),
CharacterState::Climb => states::climb::Data::behavior(&states::climb::Data, &j), CharacterState::Climb => states::climb::Data.behavior(&j),
CharacterState::Glide => states::glide::Data::behavior(&states::glide::Data, &j), CharacterState::Glide => states::glide::Data.behavior(&j),
CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j), CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j),
CharacterState::BasicBlock => states::basic_block::Data::behavior(&states::basic_block::Data, &j), CharacterState::BasicBlock => states::basic_block::Data.behavior(&j),
CharacterState::Roll (data) => data.behavior(&j), CharacterState::Roll(data) => data.behavior(&j),
CharacterState::Wielding (data) => data.behavior(&j), CharacterState::Wielding => states::wielding::Data.behavior(&j),
CharacterState::Equipping (data) => data.behavior(&j), CharacterState::Equipping(data) => data.behavior(&j),
CharacterState::ChargeAttack (data) => data.behavior(&j), CharacterState::ChargeAttack(data) => data.behavior(&j),
CharacterState::TripleStrike (data) => data.behavior(&j), CharacterState::TripleStrike(data) => data.behavior(&j),
CharacterState::BasicAttack (data) => data.behavior(&j), CharacterState::BasicAttack(data) => data.behavior(&j),
CharacterState::TimedCombo(data) => data.behavior(&j), CharacterState::TimedCombo(data) => data.behavior(&j),
// Do not use default match. // Do not use default match.

View File

@ -215,7 +215,9 @@ impl<'a> System<'a> for Sys {
loadout = comp::Loadout { loadout = comp::Loadout {
active_item: Some(comp::ItemConfig { active_item: Some(comp::ItemConfig {
item: assets::load_expect_cloned("common.items.weapons.hammer_1"), item: assets::load_expect_cloned("common.items.weapons.hammer_1"),
primary_ability: None, primary_ability: None, /* TODO: when implementing this, make sure
* to adjust the base damage (see todo
* below) */
secondary_ability: None, secondary_ability: None,
block_ability: None, block_ability: None,
dodge_ability: None, dodge_ability: None,
@ -228,14 +230,20 @@ impl<'a> System<'a> for Sys {
} }
stats.update_max_hp(); stats.update_max_hp();
stats stats
.health .health
.set_to(stats.health.maximum(), comp::HealthSource::Revive); .set_to(stats.health.maximum(), comp::HealthSource::Revive);
// TODO: This code sets an appropriate base_damage for the enemy. This doesn't
// work because the damage is now saved in an ability
/*
if let Some(item::ItemKind::Tool(item::ToolData { base_damage, .. })) = if let Some(item::ItemKind::Tool(item::ToolData { base_damage, .. })) =
&mut loadout.active_item.map(|i| i.item.kind) &mut loadout.active_item.map(|i| i.item.kind)
{ {
*base_damage = stats.level.level() as u32 * 3; *base_damage = stats.level.level() as u32 * 3;
} }
*/
server_emitter.emit(ServerEvent::CreateNpc { server_emitter.emit(ServerEvent::CreateNpc {
pos: Pos(entity.pos), pos: Pos(entity.pos),
stats, stats,