Added shop commands

+ Ton of refactoring
+ clippy + fmt
This commit is contained in:
2023-01-13 21:37:53 -07:00
parent 335751a978
commit 1db0c5b3c0
12 changed files with 701 additions and 144 deletions
+192
View File
@@ -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())
}
}