1pub mod fee;
5pub mod vault;
6
7use crate::market::fee::MarketFee;
8use crate::market::vault::MarketVault;
9use crate::resources::gold::Gold;
10use crate::resources::{Food, Iron, Resources, Stone, Wood};
11use serde::{Deserialize, Serialize};
12use std::marker::PhantomData;
13
14#[derive(Clone, Debug, Deserialize, Serialize)]
15#[derive_const(Default)]
16#[serde(rename_all = "camelCase")]
17#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
18pub struct Market {
19 vault: MarketVault,
20 fee: MarketFee,
21
22 #[cfg_attr(feature = "typescript", ts(as = "MarketPriceTable"))]
27 #[cfg_attr(
28 not(feature = "typescript"),
29 serde(skip_deserializing, serialize_with = "serialize_market_price_table")
30 )]
31 price_table: PhantomData<MarketPriceTable>,
32}
33
34impl Market {
35 pub const fn new(fee: MarketFee) -> Self {
36 Self {
37 vault: MarketVault::default(),
38 fee: fee.clamped(),
39 price_table: PhantomData,
40 }
41 }
42
43 #[inline]
44 pub const fn vault(&self) -> &MarketVault {
45 &self.vault
46 }
47
48 pub(crate) const fn vault_mut(&mut self) -> &mut MarketVault {
49 &mut self.vault
50 }
51
52 #[inline]
53 pub const fn fee(&self) -> MarketFee {
54 self.fee
55 }
56
57 pub(crate) const fn set_fee(&mut self, fee: MarketFee) {
62 self.fee = fee.clamped();
63 }
64
65 #[inline]
66 pub const fn price_table(&self) -> MarketPriceTable {
67 MarketPriceTable::default()
68 }
69
70 #[inline]
71 pub const fn price_of(&self, op: MarketOperation, resources: Resources) -> Gold {
72 match op {
73 MarketOperation::Buy => Gold::from(resources + (resources * self.fee())),
74 MarketOperation::Sell => Gold::from(resources),
75 }
76 }
77
78 pub fn buyable_amount(&self, market_price: Gold, gold: Gold) -> u32 {
80 let fee = f64::from(self.fee());
81 let market_price = f64::from(market_price);
82 let gold = f64::from(gold);
83 let resource = gold / (market_price * (1.0 + fee));
84 resource.floor().max(0.0) as u32
85 }
86}
87
88#[derive(Copy, Debug, strum::Display, Hash, Deserialize, Serialize)]
89#[derive_const(Clone, PartialEq, Eq)]
90#[serde(rename_all = "kebab-case")]
91#[strum(serialize_all = "kebab-case")]
92#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
93pub enum MarketOperation {
94 Buy,
95 Sell,
96}
97
98#[derive(Copy, Debug, Deserialize, Serialize)]
99#[derive_const(Clone, PartialEq, Eq)]
100#[serde(rename_all = "camelCase")]
101#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
102pub struct MarketPriceTable {
103 food: Gold,
104 iron: Gold,
105 stone: Gold,
106 wood: Gold,
107}
108
109impl MarketPriceTable {
110 pub const fn new() -> Self {
111 Self::default()
112 }
113}
114
115const impl Default for MarketPriceTable {
116 fn default() -> Self {
117 Self {
118 food: Food::MARKET_PRICE,
119 iron: Iron::MARKET_PRICE,
120 stone: Stone::MARKET_PRICE,
121 wood: Wood::MARKET_PRICE,
122 }
123 }
124}
125
126#[cfg(not(feature = "typescript"))]
127#[allow(clippy::trivially_copy_pass_by_ref)]
128fn serialize_market_price_table<S>(
129 _: &PhantomData<MarketPriceTable>,
130 serializer: S,
131) -> Result<S::Ok, S::Error>
132where
133 S: serde::Serializer,
134{
135 MarketPriceTable::default().serialize(serializer)
136}