Added shop commands
+ Ton of refactoring + clippy + fmt
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::utils::MessageBuilder;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum InventoryError {
|
||||
NotEnoughItems,
|
||||
UnkownItem,
|
||||
}
|
||||
|
||||
impl Display for InventoryError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
InventoryError::NotEnoughItems => write!(f, "Not enough items"),
|
||||
InventoryError::UnkownItem => write!(f, "Not sure that that is, maybe check Walmart?"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
|
||||
#[serde(tag = "type", content = "data")]
|
||||
pub enum ItemData {
|
||||
Nft(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Copy)]
|
||||
pub enum ItemType {
|
||||
CancelInsurance,
|
||||
TheConceptOfLove,
|
||||
GoodFortune,
|
||||
Nft,
|
||||
}
|
||||
|
||||
impl FromStr for ItemType {
|
||||
type Err = InventoryError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let item = s.to_lowercase().replace(' ', "");
|
||||
|
||||
if item.starts_with("cancelinsurance") {
|
||||
Ok(ItemType::CancelInsurance)
|
||||
} else if item.starts_with("theconceptoflove") {
|
||||
Ok(ItemType::TheConceptOfLove)
|
||||
} else if item.starts_with("goodfortune") {
|
||||
Ok(ItemType::GoodFortune)
|
||||
} else if item.starts_with("nft") {
|
||||
Ok(ItemType::Nft)
|
||||
} else {
|
||||
Err(InventoryError::UnkownItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ItemType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let name = match self {
|
||||
ItemType::CancelInsurance => "Cancel Insurance".to_string(),
|
||||
ItemType::TheConceptOfLove => "The Concept of Love".to_string(),
|
||||
ItemType::GoodFortune => "Good Fortune".to_string(),
|
||||
ItemType::Nft => "NFT".to_string(),
|
||||
};
|
||||
|
||||
write!(f, "{}", name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InventorySlot {
|
||||
pub quantity: i64,
|
||||
pub item_type: ItemType,
|
||||
pub item_data: Option<ItemData>,
|
||||
}
|
||||
impl InventorySlot {
|
||||
pub fn value(&self) -> i64 {
|
||||
match self.item_type {
|
||||
ItemType::CancelInsurance => 50,
|
||||
ItemType::TheConceptOfLove => 300,
|
||||
ItemType::GoodFortune => 75,
|
||||
ItemType::Nft => 100,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sell_value(&self) -> i64 {
|
||||
match self.item_type {
|
||||
ItemType::Nft => {
|
||||
if let Some(ItemData::Nft(s)) = &self.item_data {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
s.hash(&mut hasher);
|
||||
|
||||
let hash = hasher.finish();
|
||||
|
||||
let per_value = (hash as f64) / (u64::MAX as f64);
|
||||
|
||||
((2000.0 * per_value) as i64) - 1000
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => self.value() / 2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn use_cost(&self) -> i64 {
|
||||
match self.item_type {
|
||||
ItemType::Nft => 0,
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct InventoryManager {
|
||||
pub inventory: Vec<InventorySlot>,
|
||||
}
|
||||
|
||||
impl InventoryManager {
|
||||
pub fn get_item(&mut self, item_type: ItemType) -> Option<&mut InventorySlot> {
|
||||
if let Some(inv_ndx) = self.inventory.iter().position(|i| i.item_type == item_type) {
|
||||
Some(&mut self.inventory[inv_ndx])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn give_item(&mut self, item_type: ItemType, quantity: i64, item_data: Option<ItemData>) {
|
||||
match self.get_item(item_type) {
|
||||
None => self.inventory.push(InventorySlot {
|
||||
quantity,
|
||||
item_type,
|
||||
item_data,
|
||||
}),
|
||||
Some(slot) => {
|
||||
slot.item_data = item_data;
|
||||
slot.quantity += quantity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_take_item(
|
||||
&mut self,
|
||||
item: ItemType,
|
||||
quantity: i64,
|
||||
) -> Result<Option<ItemData>, InventoryError> {
|
||||
let slot = self.get_item(item);
|
||||
|
||||
if let Some(slot) = slot {
|
||||
if slot.quantity < quantity {
|
||||
return Err(InventoryError::NotEnoughItems);
|
||||
}
|
||||
slot.quantity -= quantity;
|
||||
|
||||
Ok(slot.item_data.clone())
|
||||
} else {
|
||||
Err(InventoryError::NotEnoughItems)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_items(&self, buy_value: bool) -> String {
|
||||
let mut msg_builder = MessageBuilder::new();
|
||||
|
||||
for item_slot in &self.inventory {
|
||||
if item_slot.quantity != 0 {
|
||||
let value = if buy_value {
|
||||
item_slot.value()
|
||||
} else {
|
||||
item_slot.sell_value()
|
||||
};
|
||||
msg_builder.push_line(format!(
|
||||
"* {} [{} coins] (x{})",
|
||||
item_slot.item_type, value, item_slot.quantity
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
msg_builder.build()
|
||||
}
|
||||
|
||||
pub fn try_use_item(&mut self, item: ItemType) -> Result<Option<ItemData>, InventoryError> {
|
||||
let item_slot = self.get_item(item).ok_or(InventoryError::NotEnoughItems)?;
|
||||
|
||||
if item_slot.quantity < item_slot.use_cost() {
|
||||
return Err(InventoryError::NotEnoughItems);
|
||||
}
|
||||
|
||||
item_slot.quantity -= item_slot.use_cost();
|
||||
|
||||
Ok(item_slot.item_data.clone())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user