veloren/common/src/comp/inventory/item.rs

427 lines
16 KiB
Rust
Raw Normal View History

use crate::{
assets::{self, Asset},
comp::{
body::{humanoid, object},
2020-03-24 19:31:54 +00:00
projectile, Body, CharacterAbility, Gravity, HealthChange, HealthSource, LightEmitter,
Projectile,
},
effect::Effect,
terrain::{Block, BlockKind},
};
use rand::seq::SliceRandom;
2019-07-26 21:01:41 +00:00
use specs::{Component, FlaggedStorage};
use specs_idvs::IDVStorage;
2020-03-22 04:49:32 +00:00
use std::{fs::File, io::BufReader, time::Duration};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
2019-12-29 23:47:42 +00:00
pub enum SwordKind {
2020-03-18 20:05:20 +00:00
BasicSword,
2019-12-29 23:47:42 +00:00
Rapier,
2020-03-18 20:05:20 +00:00
Zweihander0,
WoodTraining,
2020-03-18 22:09:58 +00:00
Short0,
2019-12-29 23:47:42 +00:00
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum AxeKind {
BasicAxe,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum HammerKind {
BasicHammer,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum BowKind {
BasicBow,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum DaggerKind {
BasicDagger,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum StaffKind {
BasicStaff,
2020-03-24 00:11:14 +00:00
Sceptre,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ShieldKind {
BasicShield,
}
2019-12-29 23:47:42 +00:00
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ToolKind {
Sword(SwordKind),
Axe(AxeKind),
Hammer(HammerKind),
Bow(BowKind),
Dagger(DaggerKind),
Staff(StaffKind),
Shield(ShieldKind),
2020-03-14 15:40:29 +00:00
Debug(DebugKind),
2020-03-16 13:27:52 +00:00
/// This is an placeholder item, it is used by non-humanoid npcs to attack
Empty,
2020-01-05 23:17:22 +00:00
}
2019-12-29 23:47:42 +00:00
impl ToolData {
pub fn equip_time(&self) -> Duration { Duration::from_millis(self.equip_time_millis) }
2020-03-14 15:40:29 +00:00
pub fn get_abilities(&self) -> Vec<CharacterAbility> {
use CharacterAbility::*;
use DebugKind::*;
2020-03-12 14:47:27 +00:00
use ToolKind::*;
match self.kind {
2020-03-26 13:46:08 +00:00
Sword(_) => vec![TripleStrike { base_damage: 5 }, DashMelee {
buildup_duration: Duration::from_millis(500),
recover_duration: Duration::from_millis(500),
base_damage: 20,
}],
Axe(_) => vec![BasicMelee {
2020-03-24 21:03:11 +00:00
energy_cost: 0,
buildup_duration: Duration::from_millis(700),
recover_duration: Duration::from_millis(100),
2020-03-24 21:03:11 +00:00
base_healthchange: -8,
range: 3.5,
max_angle: 30.0,
2020-03-14 15:40:29 +00:00
}],
Hammer(_) => vec![BasicMelee {
2020-03-24 21:03:11 +00:00
energy_cost: 0,
buildup_duration: Duration::from_millis(700),
recover_duration: Duration::from_millis(300),
2020-03-24 21:03:11 +00:00
base_healthchange: -10,
range: 3.5,
max_angle: 60.0,
2020-03-14 15:40:29 +00:00
}],
Bow(_) => vec![BasicRanged {
2020-03-24 19:09:23 +00:00
energy_cost: 0,
prepare_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(300),
projectile: Projectile {
hit_ground: vec![projectile::Effect::Stick],
hit_wall: vec![projectile::Effect::Stick],
hit_entity: vec![
projectile::Effect::Damage(HealthChange {
// TODO: This should not be fixed (?)
amount: -3,
cause: HealthSource::Projectile { owner: None },
}),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(15),
owner: None,
},
projectile_body: Body::Object(object::Body::Arrow),
2020-03-24 19:31:54 +00:00
projectile_light: None,
projectile_gravity: Some(Gravity(0.1)),
}],
Dagger(_) => vec![BasicMelee {
2020-03-24 21:03:11 +00:00
energy_cost: 0,
buildup_duration: Duration::from_millis(100),
recover_duration: Duration::from_millis(400),
2020-03-24 21:03:11 +00:00
base_healthchange: -5,
range: 3.5,
max_angle: 60.0,
2020-03-14 15:40:29 +00:00
}],
2020-03-24 21:03:11 +00:00
Staff(StaffKind::BasicStaff) => vec![
BasicMelee {
2020-03-24 21:03:11 +00:00
energy_cost: 0,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(300),
2020-03-24 21:03:11 +00:00
base_healthchange: -1,
range: 10.0,
max_angle: 45.0,
},
2020-03-24 12:59:53 +00:00
BasicRanged {
2020-03-24 19:09:23 +00:00
energy_cost: 0,
prepare_duration: Duration::from_millis(300),
recover_duration: Duration::from_millis(100),
2020-03-24 12:59:53 +00:00
projectile: Projectile {
hit_ground: vec![projectile::Effect::Vanish],
hit_wall: vec![projectile::Effect::Vanish],
hit_entity: vec![
projectile::Effect::Damage(HealthChange {
// TODO: This should not be fixed (?)
amount: -2,
cause: HealthSource::Projectile { owner: None },
}),
projectile::Effect::Vanish,
],
time_left: Duration::from_secs(20),
owner: None,
},
projectile_body: Body::Object(object::Body::BoltFire),
2020-03-24 19:31:54 +00:00
projectile_light: Some(LightEmitter {
col: (0.72, 0.11, 0.11).into(),
..Default::default()
}),
projectile_gravity: None,
2020-03-24 12:59:53 +00:00
},
2020-03-24 19:09:23 +00:00
BasicRanged {
energy_cost: 400,
prepare_duration: Duration::from_millis(800),
recover_duration: Duration::from_millis(300),
projectile: Projectile {
2020-03-22 19:39:50 +00:00
hit_ground: vec![
2020-03-23 21:52:35 +00:00
projectile::Effect::Explode { power: 1.4 },
2020-03-22 19:39:50 +00:00
projectile::Effect::Vanish,
],
hit_wall: vec![
2020-03-23 21:52:35 +00:00
projectile::Effect::Explode { power: 1.4 },
2020-03-22 19:39:50 +00:00
projectile::Effect::Vanish,
],
hit_entity: vec![
2020-03-23 21:52:35 +00:00
projectile::Effect::Explode { power: 1.4 },
projectile::Effect::Vanish,
],
2020-03-22 19:39:50 +00:00
time_left: Duration::from_secs(20),
owner: None,
},
projectile_body: Body::Object(object::Body::BoltFire),
2020-03-24 19:31:54 +00:00
projectile_light: Some(LightEmitter {
col: (0.72, 0.11, 0.11).into(),
..Default::default()
}),
projectile_gravity: None,
},
],
2020-03-24 21:03:11 +00:00
Staff(StaffKind::Sceptre) => vec![
BasicMelee {
energy_cost: 0,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(300),
base_healthchange: -1,
range: 10.0,
max_angle: 45.0,
},
BasicMelee {
energy_cost: 350,
buildup_duration: Duration::from_millis(0),
recover_duration: Duration::from_millis(1000),
base_healthchange: 15,
range: 10.0,
max_angle: 45.0,
},
],
Shield(_) => vec![BasicBlock],
2020-03-14 15:40:29 +00:00
Debug(kind) => match kind {
DebugKind::Boost => vec![
CharacterAbility::Boost {
2020-03-19 16:01:58 +00:00
duration: Duration::from_millis(50),
only_up: false,
},
CharacterAbility::Boost {
2020-03-19 16:01:58 +00:00
duration: Duration::from_millis(50),
only_up: true,
},
],
Possess => vec![BasicRanged {
2020-03-24 19:09:23 +00:00
energy_cost: 0,
prepare_duration: Duration::from_millis(300),
recover_duration: Duration::from_millis(300),
projectile: Projectile {
hit_ground: vec![projectile::Effect::Stick],
hit_wall: vec![projectile::Effect::Stick],
hit_entity: vec![projectile::Effect::Stick, projectile::Effect::Possess],
time_left: Duration::from_secs(10),
owner: None,
},
projectile_body: Body::Object(object::Body::ArrowSnake),
2020-03-24 19:31:54 +00:00
projectile_light: None,
projectile_gravity: None,
}],
2020-03-12 14:47:27 +00:00
},
2020-03-16 13:27:52 +00:00
Empty => vec![],
2020-03-12 14:47:27 +00:00
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
2020-03-14 15:40:29 +00:00
pub enum DebugKind {
Boost,
Possess,
2019-06-28 23:42:51 +00:00
}
2019-07-29 13:44:16 +00:00
2020-01-05 23:21:37 +00:00
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Armor {
Shoulder(humanoid::Shoulder),
Chest(humanoid::Chest),
Belt(humanoid::Belt),
Hand(humanoid::Hand),
Pants(humanoid::Pants),
Foot(humanoid::Foot),
}
pub type ArmorStats = u32;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
2019-09-25 14:56:57 +00:00
pub enum Consumable {
Apple,
Cheese,
2019-09-25 14:56:57 +00:00
Potion,
Mushroom,
2019-09-25 20:22:39 +00:00
Velorite,
VeloriteFrag,
PotionMinor,
2019-09-25 14:56:57 +00:00
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
2020-01-29 12:01:28 +00:00
pub enum Utility {
Collar,
}
2020-01-05 23:21:37 +00:00
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
2019-09-25 22:04:18 +00:00
pub enum Ingredient {
Flower,
Grass,
}
2020-03-14 15:40:29 +00:00
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
2019-12-29 23:47:42 +00:00
pub struct ToolData {
pub kind: ToolKind,
equip_time_millis: u64,
// TODO: item specific abilities
2019-12-29 23:47:42 +00:00
}
2020-03-19 13:30:50 +00:00
fn default_amount() -> u32 { 1 }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ItemKind {
/// Something wieldable
2019-12-29 23:47:42 +00:00
Tool(ToolData),
Armor {
kind: Armor,
stats: ArmorStats,
},
Consumable {
kind: Consumable,
effect: Effect,
2020-03-19 16:44:13 +00:00
#[serde(default = "default_amount")]
2020-03-19 13:30:50 +00:00
amount: u32,
},
Utility {
kind: Utility,
2020-03-19 16:44:13 +00:00
#[serde(default = "default_amount")]
2020-03-19 13:30:50 +00:00
amount: u32,
},
Ingredient {
kind: Ingredient,
2020-03-19 16:44:13 +00:00
#[serde(default = "default_amount")]
2020-03-19 13:30:50 +00:00
amount: u32,
},
2019-07-29 13:44:16 +00:00
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Item {
name: String,
description: String,
pub kind: ItemKind,
}
2019-10-09 19:28:05 +00:00
impl Asset for Item {
const ENDINGS: &'static [&'static str] = &["ron"];
fn parse(buf_reader: BufReader<File>) -> Result<Self, assets::Error> {
Ok(ron::de::from_reader(buf_reader).unwrap())
2019-10-09 19:28:05 +00:00
}
}
2019-10-09 19:28:05 +00:00
impl Item {
2020-03-16 13:27:52 +00:00
pub fn empty() -> Self {
Self {
name: "Empty Item".to_owned(),
description: "This item may grant abilities, but is invisible".to_owned(),
kind: ItemKind::Tool(ToolData {
kind: ToolKind::Empty,
equip_time_millis: 0,
}),
}
}
pub fn name(&self) -> &str { &self.name }
pub fn description(&self) -> &str { &self.description }
2019-09-25 14:56:57 +00:00
pub fn try_reclaim_from_block(block: Block) -> Option<Self> {
match block.kind() {
BlockKind::Apple => Some(assets::load_expect_cloned("common.items.apple")),
BlockKind::Mushroom => Some(assets::load_expect_cloned("common.items.mushroom")),
BlockKind::Velorite => Some(assets::load_expect_cloned("common.items.velorite")),
BlockKind::BlueFlower => Some(assets::load_expect_cloned("common.items.flowers.blue")),
BlockKind::PinkFlower => Some(assets::load_expect_cloned("common.items.flowers.pink")),
BlockKind::PurpleFlower => {
Some(assets::load_expect_cloned("common.items.flowers.purple"))
},
BlockKind::RedFlower => Some(assets::load_expect_cloned("common.items.flowers.red")),
BlockKind::WhiteFlower => {
Some(assets::load_expect_cloned("common.items.flowers.white"))
},
BlockKind::YellowFlower => {
Some(assets::load_expect_cloned("common.items.flowers.yellow"))
},
BlockKind::Sunflower => Some(assets::load_expect_cloned("common.items.flowers.sun")),
BlockKind::LongGrass => Some(assets::load_expect_cloned("common.items.grasses.long")),
BlockKind::MediumGrass => {
Some(assets::load_expect_cloned("common.items.grasses.medium"))
},
BlockKind::ShortGrass => Some(assets::load_expect_cloned("common.items.grasses.short")),
BlockKind::Chest => Some(assets::load_expect_cloned(
[
"common.items.apple",
"common.items.velorite",
"common.items.veloritefrag",
"common.items.cheese",
"common.items.potion_minor",
2020-01-29 12:01:28 +00:00
"common.items.collar",
"common.items.weapons.starter_sword",
"common.items.weapons.starter_axe",
"common.items.weapons.staff_nature",
"common.items.weapons.starter_hammer",
"common.items.weapons.starter_bow",
"common.items.weapons.starter_staff",
2020-03-20 00:11:02 +00:00
"common.items.armor.belt.plate_0",
"common.items.armor.belt.leather_0",
"common.items.armor.chest.plate_green_0",
"common.items.armor.chest.leather_0",
"common.items.armor.foot.plate_0",
"common.items.armor.foot.leather_0",
"common.items.armor.pants.plate_green_0",
"common.items.armor.belt.leather_0",
"common.items.armor.shoulder.plate_0",
"common.items.armor.shoulder.leather_1",
"common.items.armor.shoulder.leather_0",
2020-03-22 15:19:30 +00:00
"common.items.armor.hand.leather_0",
"common.items.armor.hand.plate_0",
2020-03-20 00:11:02 +00:00
"common.items.weapons.wood_sword",
"common.items.weapons.short_sword_0",
2020-03-22 15:19:30 +00:00
"common.items.armor.belt.cloth_blue_0",
"common.items.armor.chest.cloth_blue_0",
"common.items.armor.foot.cloth_blue_0",
"common.items.armor.pants.cloth_blue_0",
"common.items.armor.shoulder.cloth_blue_0",
"common.items.armor.hand.cloth_blue_0",
"common.items.armor.belt.cloth_green_0",
"common.items.armor.chest.cloth_green_0",
"common.items.armor.foot.cloth_green_0",
"common.items.armor.pants.cloth_green_0",
"common.items.armor.shoulder.cloth_green_0",
"common.items.armor.hand.cloth_green_0",
"common.items.armor.belt.cloth_purple_0",
"common.items.armor.chest.cloth_purple_0",
"common.items.armor.foot.cloth_purple_0",
"common.items.armor.pants.cloth_purple_0",
"common.items.armor.shoulder.cloth_purple_0",
"common.items.armor.hand.cloth_purple_0",
]
.choose(&mut rand::thread_rng())
.unwrap(), // Can't fail
)),
2019-09-25 14:56:57 +00:00
_ => None,
}
}
2019-07-25 22:52:28 +00:00
}
impl Component for Item {
2019-07-26 21:01:41 +00:00
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}