Skip to content

Commit

Permalink
Trade;
Browse files Browse the repository at this point in the history
Lootbox open window;
  • Loading branch information
makscee committed Aug 6, 2024
1 parent 9db8868 commit b494491
Show file tree
Hide file tree
Showing 20 changed files with 352 additions and 62 deletions.
68 changes: 41 additions & 27 deletions server/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ pub struct TItem {
#[primarykey]
pub id: u64,
pub owner: u64,
pub stack: ItemStack,
}

#[derive(SpacetimeType, Clone)]
pub struct ItemStack {
pub item: Item,
pub count: u32,
}
Expand All @@ -20,37 +25,40 @@ pub enum Item {
}

impl Item {
pub fn to_stack(self, count: u32) -> ItemStack {
ItemStack { item: self, count }
}
}

impl ItemStack {
pub fn take(self, owner: u64) -> Result<(), String> {
match &self {
match &self.item {
Item::HeroShard(base) => {
TItem::change_shards(owner, base.clone(), 1)?;
}
Item::Hero(_) => {
let item = TItem {
id: next_id(),
owner,
item: self,
count: 1,
stack: self,
};
TItem::insert(item)?;
}
Item::Lootbox => {
let mut item = if let Some(item) = TItem::filter_by_owner(&owner)
.filter(|d| d.item.eq(&self))
if let Some(mut item) = TItem::filter_by_owner(&owner)
.filter(|d| d.stack.item.eq(&self.item))
.at_most_one()
.map_err(|e| e.to_string())?
{
item
item.stack.count += self.count;
TItem::update_by_id(&item.id.clone(), item);
} else {
TItem::insert(TItem {
id: next_id(),
owner,
item: self.clone(),
count: 0,
})?
stack: self.clone(),
})?;
};
item.count += 1;
TItem::update_by_id(&item.id.clone(), item);
}
};
Ok(())
Expand All @@ -61,7 +69,7 @@ impl TItem {
fn change_shards(owner: u64, base: String, delta: i32) -> Result<(), String> {
let shard_item = Item::HeroShard(base.clone());
let mut item = if let Some(item) = Self::filter_by_owner(&owner)
.filter(|d| shard_item.eq(&d.item))
.filter(|d| shard_item.eq(&d.stack.item))
.at_most_one()
.map_err(|e| e.to_string())?
{
Expand All @@ -70,15 +78,17 @@ impl TItem {
Self::insert(Self {
id: next_id(),
owner,
item: shard_item,
count: 0,
stack: ItemStack {
item: shard_item,
count: 0,
},
})?
};
if item.count as i32 + delta < 0 {
if item.stack.count as i32 + delta < 0 {
return Err("Not enough shards".into());
}
item.count = (item.count as i32 + delta) as u32;
if item.count == 0 {
item.stack.count = (item.stack.count as i32 + delta) as u32;
if item.stack.count == 0 {
Self::delete_by_id(&item.id);
} else {
Self::update_by_id(&item.id.clone(), item);
Expand All @@ -91,13 +101,11 @@ impl TItem {
base.clone(),
-(GlobalSettings::get().craft_shards_cost as i32),
)?;
let id = next_id();
let hero = FusedUnit::from_base(base, id)?.mutate();
let hero = FusedUnit::from_base(base, next_id())?.mutate();
Self::insert(Self {
id: next_id(),
owner,
item: Item::Hero(hero),
count: 1,
stack: Item::Hero(hero).to_stack(1),
})?;
Ok(())
}
Expand All @@ -116,15 +124,21 @@ fn open_lootbox(ctx: ReducerContext, id: u64) -> Result<(), String> {
if item.owner != user.id {
return Err(format!("Item #{id} not owned by {}", user.id));
}
if item.count == 0 {
if item.stack.count == 0 {
return Err("Lootbox count is 0".into());
}
item.count -= 1;
item.stack.count -= 1;
let amount = thread_rng().gen_range(3..7);
for _ in 0..amount {
let name = TBaseUnit::iter().choose(&mut thread_rng()).unwrap().name;
Item::HeroShard(name).take(user.id)?;
let items = (0..amount)
.map(|_| {
Item::HeroShard(TBaseUnit::iter().choose(&mut thread_rng()).unwrap().name).to_stack(1)
})
.collect_vec();
TTrade::open_lootbox(user.id, id, items)?;
if item.stack.count == 0 {
TItem::delete_by_id(&id);
} else {
TItem::update_by_id(&id, item);
}
TItem::update_by_id(&id, item);
Ok(())
}
2 changes: 2 additions & 0 deletions server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod starting_hero;
mod status;
mod sync;
mod team;
mod trade;
mod user;
mod wallet;

Expand All @@ -38,6 +39,7 @@ pub use spacetimedb::{
};
pub use starting_hero::*;
pub use team::*;
pub use trade::*;
pub use user::*;
pub use wallet::*;

Expand Down
8 changes: 4 additions & 4 deletions server/src/meta_shop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub struct MetaSettings {
pub struct TMetaShop {
#[primarykey]
id: u64,
item: Item,
stack: ItemStack,
price: i64,
}

Expand All @@ -28,15 +28,15 @@ impl TMetaShop {
let ms = GlobalSettings::get().meta;
Self::insert(Self {
id: next_id(),
item: Item::Lootbox,
stack: Item::Lootbox.to_stack(1),
price: ms.price_lootbox,
})?;
for i in TBaseUnit::iter()
.choose_multiple(&mut thread_rng(), ms.shop_shard_slots as usize)
.into_iter()
.map(|u| Self {
id: next_id(),
item: Item::HeroShard(u.name),
stack: Item::HeroShard(u.name).to_stack(1),
price: ms.price_shard,
})
{
Expand Down Expand Up @@ -77,5 +77,5 @@ fn meta_buy(ctx: ReducerContext, id: u64) -> Result<(), String> {
let user = ctx.user()?;
let item = TMetaShop::filter_by_id(&id).context_str("Item not found")?;
TWallet::change(user.id, -item.price)?;
item.item.take(user.id)
item.stack.take(user.id)
}
2 changes: 1 addition & 1 deletion server/src/starting_hero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl TStartingHero {
if item.owner != owner {
return Err(format!("Item not owned by #{owner}"));
}
match item.item {
match item.stack.item {
Item::Hero(unit) => Ok(unit),
_ => {
return Err(format!("Wrong item type for #{}", item.id));
Expand Down
54 changes: 54 additions & 0 deletions server/src/trade.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use super::*;

#[spacetimedb(table)]
pub struct TTrade {
#[primarykey]
id: u64,
a_user: u64,
b_user: u64,
a_offers_items: Vec<ItemStack>,
b_offers_items: Vec<ItemStack>,
a_accepted: bool,
b_accepted: bool,
}

impl TTrade {
pub fn open_lootbox(owner: u64, id: u64, items: Vec<ItemStack>) -> Result<Self, String> {
let trade = TTrade {
id,
a_user: 0,
b_user: owner,
a_offers_items: items,
b_offers_items: Vec::new(),
a_accepted: true,
b_accepted: false,
};
TTrade::insert(trade).map_err(|e| e.to_string())
}
}

#[spacetimedb(reducer)]
fn accept_trade(ctx: ReducerContext, id: u64) -> Result<(), String> {
let user = ctx.user()?;
let mut trade = TTrade::filter_by_id(&id).context_str("Trade not found")?;
if trade.a_user == user.id {
trade.a_accepted = true;
}
if trade.b_user == user.id {
trade.b_accepted = true;
} else {
return Err(format!("User#{} not part of the Trade#{}", user.id, id));
}
if trade.a_accepted && trade.b_accepted {
for item in trade.a_offers_items {
item.take(trade.b_user)?;
}
for item in trade.b_offers_items {
item.take(trade.a_user)?;
}
TTrade::delete_by_id(&id);
} else {
TTrade::update_by_id(&id, trade);
}
Ok(())
}
2 changes: 1 addition & 1 deletion server/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ impl TWallet {
fn give_credits(ctx: ReducerContext) -> Result<(), String> {
ctx.is_admin()?;
let user = TUser::find_by_identity(&ctx.sender)?;
TWallet::change(user.id, 10)?;
TWallet::change(user.id, 100)?;
Ok(())
}
9 changes: 5 additions & 4 deletions src/plugins/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,26 +69,27 @@ impl LoginPlugin {
.push_op();
});
TItem::on_update(|before, after, _| {
let delta = after.count as i64 - before.count as i64;
let delta = after.stack.count as i64 - before.stack.count as i64;
let delta_txt = if delta > 0 {
format!(" +{delta}")
} else {
delta.to_string()
format!(" {delta}")
};
let txt = before
.stack
.item
.cstr()
.push(delta_txt.cstr_c(VISIBLE_LIGHT))
.take();
Notification::new(txt).push_op();
});
TItem::on_insert(|item, _| {
let txt = item.item.cstr();
let txt = item.stack.item.cstr();
Notification::new("New item: ".cstr().push(txt).take()).push_op();
TableState::reset_cache_op();
});
TItem::on_delete(|item, _| {
let txt = item.item.cstr();
let txt = item.stack.item.cstr();
Notification::new("Item removed: ".cstr_c(VISIBLE_LIGHT).push(txt).take())
.push_op();
TableState::reset_cache_op();
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ impl StdbQuery {
format!("select * from TArenaRun where owner = {uid}"),
format!("select * from TBattle where owner = {uid}"),
format!("select * from TWallet where owner = {uid}"),
format!("select * from TItem where owner = {uid} and count > 0"),
format!("select * from TItem where owner = {uid}"),
format!("select * from TStartingHero where owner = {uid}"),
format!("select * from TTrade where a_user = {uid} or b_user = {uid}"),
"select * from TBaseUnit".into(),
"select * from TRepresentation".into(),
"select * from GlobalSettings".into(),
Expand Down
1 change: 1 addition & 0 deletions src/plugins/widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ impl WidgetsPlugin {
}

Notification::show_recent(&wd, ctx, world);
Trade::show_active(ctx, world);
Confirmation::show_current(ctx, world);
world.insert_resource(wd);
world.insert_resource(ws);
Expand Down
23 changes: 14 additions & 9 deletions src/resources/ui_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,12 @@ impl ShowTable<TMetaShop> for Vec<TMetaShop> {
) -> TableState {
let mut t = Table::new(name)
.title()
.column_cstr("name", |d: &TMetaShop| match &d.item {
.column_cstr("name", |d: &TMetaShop| match &d.stack.item {
Item::HeroShard(name) => name.cstr_c(name_color(&name)),
Item::Hero(unit) => unit.cstr(),
Item::Lootbox => "lootbox".cstr_c(CYAN),
})
.column_cstr("type", |d| match &d.item {
.column_cstr("type", |d| match &d.stack.item {
Item::HeroShard(_) => "shard".cstr(),
Item::Hero(_) => "hero".cstr(),
Item::Lootbox => "normal".cstr(),
Expand Down Expand Up @@ -157,26 +157,26 @@ impl ShowTable<TItem> for Vec<TItem> {
) -> TableState {
let mut t = Table::new(name)
.title()
.column_cstr("name", |d: &TItem| match &d.item {
.column_cstr("name", |d: &TItem| match &d.stack.item {
Item::HeroShard(name) => name.cstr_c(name_color(&name)),
Item::Hero(unit) => unit.cstr(),
Item::Lootbox => "normal".cstr(),
})
.column_cstr("type", |d| match &d.item {
.column_cstr("type", |d| match &d.stack.item {
Item::HeroShard(_) => "shard".cstr(),
Item::Hero(_) => "hero".cstr_c(YELLOW),
Item::Lootbox => "lootbox".cstr_c(CYAN),
})
.column_int("count", |d| d.count as i32)
.column_int("count", |d| d.stack.count as i32)
.column(
"action",
|_| default(),
|d, _, ui, world| {
let craft_cost = GameAssets::get(world).global_settings.craft_shards_cost;
match &d.item {
match &d.stack.item {
Item::HeroShard(base) => {
let r = Button::click("craft".into())
.enabled(d.count >= craft_cost)
.enabled(d.stack.count >= craft_cost)
.ui(ui);
if r.clicked() {
craft_hero(base.clone());
Expand Down Expand Up @@ -215,9 +215,14 @@ impl ShowTable<TItem> for Vec<TItem> {
let r = Button::click("open".into()).ui(ui);
if r.clicked() {
open_lootbox(d.id);
once_on_open_lootbox(move |_, _, status, _| match status {
once_on_open_lootbox(move |_, _, status, id| match status {
StdbStatus::Committed => {
Notification::new_string("Lootbox opened".into()).push_op()
let id = *id;
OperationsPlugin::add(move |world| {
Notification::new_string("Lootbox opened".into())
.push(world);
Trade::open(id, &egui_context(world).unwrap());
});
}
StdbStatus::Failed(e) => e.notify_error(),
_ => panic!(),
Expand Down
1 change: 1 addition & 0 deletions src/resources/var_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ impl VarValue {
}
pub fn compare(a: &VarValue, b: &VarValue) -> Result<Ordering> {
match (a, b) {
(VarValue::None, VarValue::None) => Ok(Ordering::Equal),
(VarValue::Float(a), VarValue::Float(b)) => Ok(a.total_cmp(b)),
(VarValue::Int(a), VarValue::Int(b)) => Ok(a.cmp(b)),
(VarValue::U64(a), VarValue::U64(b)) => Ok(a.cmp(b)),
Expand Down
2 changes: 2 additions & 0 deletions src/resources/widgets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod slider;
mod subsection_menu;
mod table;
mod tile;
mod trade;
mod unit_card;
mod unit_container;

Expand All @@ -24,5 +25,6 @@ pub use slider::*;
pub use subsection_menu::*;
pub use table::*;
pub use tile::*;
pub use trade::*;
pub use unit_card::*;
pub use unit_container::*;
Loading

0 comments on commit b494491

Please sign in to comment.