This commit is contained in:
parent
98260308e8
commit
b80f30ef9d
@ -960,6 +960,125 @@ impl ItemManager {
|
||||
Ok(weapon)
|
||||
}
|
||||
|
||||
pub async fn trade_items<EG: EntityGateway>(&mut self,
|
||||
entity_gateway: &mut EG,
|
||||
p1: (&AreaClient, &CharacterEntity, &Vec<TradeItem>),
|
||||
p2: (&AreaClient, &CharacterEntity, &Vec<TradeItem>))
|
||||
-> Result<Vec<ItemToTrade>, anyhow::Error> {
|
||||
let it = ItemTransaction::new(&self, (p1, p2))
|
||||
.act(|it, (p1, p2)| -> Result<_, anyhow::Error> {
|
||||
let p1_inventory = it.manager.get_character_inventory(p1.1)?;
|
||||
let p2_inventory = it.manager.get_character_inventory(p2.1)?;
|
||||
|
||||
//TODO: inv-selftrade+othertrade <= 30
|
||||
//if p1_inventory
|
||||
|
||||
let trade_items = [(p1, p2, p1_inventory), (p2, p1, p2_inventory)]
|
||||
.map(|((src_client, dest_client, src_inventory))| {
|
||||
src_client.2.iter()
|
||||
.map(|item| -> Option<(Option<ItemToTrade>, Vec<Box<dyn ItemAction<EG>>>)> {
|
||||
match item {
|
||||
TradeItem::Individual(item_id) => {
|
||||
let item = src_inventory.get_item_by_id(*item_id)?.individual()?;
|
||||
Some((
|
||||
Some(ItemToTrade {
|
||||
add_to: *dest_client.0,
|
||||
remove_from: *src_client.0,
|
||||
item_id: *item_id,
|
||||
item_detail: ItemToTradeDetail::Individual(item.item.clone())
|
||||
}),
|
||||
vec![
|
||||
Box::new(AddIndividualItemToInventory {
|
||||
character_id: dest_client.1.id,
|
||||
item_id: item.entity_id,
|
||||
}),
|
||||
Box::new(RemoveIndividualItemFromInventory {
|
||||
character_id: src_client.1.id,
|
||||
item_id: item.entity_id,
|
||||
})
|
||||
]
|
||||
))
|
||||
},
|
||||
TradeItem::Stacked(item_id, amount) => {
|
||||
let item = src_inventory.get_item_by_id(*item_id)?.stacked()?;
|
||||
if item.count() < *amount {
|
||||
None
|
||||
}
|
||||
else {
|
||||
Some((
|
||||
Some(ItemToTrade {
|
||||
add_to: *dest_client.0,
|
||||
remove_from: *src_client.0,
|
||||
item_id: *item_id,
|
||||
item_detail: ItemToTradeDetail::Stacked(item.tool, *amount)
|
||||
}),
|
||||
vec![
|
||||
Box::new(AddStackedItemToInventory {
|
||||
character_id: dest_client.1.id,
|
||||
item_ids: item.entity_ids.iter().cloned().take(*amount).collect(),
|
||||
}),
|
||||
Box::new(RemoveStackedItemFromInventory {
|
||||
character_id: src_client.1.id,
|
||||
item_ids: item.entity_ids.iter().cloned().take(*amount).collect(),
|
||||
}),
|
||||
]
|
||||
))
|
||||
}
|
||||
},
|
||||
TradeItem::Meseta(amount) => {
|
||||
Some((None,
|
||||
vec![
|
||||
Box::new(AddMesetaToInventory {
|
||||
character_id: dest_client.1.id,
|
||||
amount: *amount,
|
||||
}),
|
||||
Box::new(RemoveMesetaFromInventory {
|
||||
character_id: src_client.1.id,
|
||||
amount: *amount,
|
||||
}),
|
||||
]
|
||||
))
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()
|
||||
});
|
||||
|
||||
if let [Some(p1_trades), Some(p2_trades)] = trade_items {
|
||||
let (p1_item_trades, p1_item_actions): (Vec<Option<ItemToTrade>>, Vec<Vec<Box<dyn ItemAction<EG>>>>) = p1_trades.into_iter().unzip();
|
||||
let (p2_item_trades, p2_item_actions): (Vec<Option<ItemToTrade>>, Vec<Vec<Box<dyn ItemAction<EG>>>>) = p2_trades.into_iter().unzip();
|
||||
let item_trades = p1_item_trades.into_iter().flatten().chain(p2_item_trades.into_iter().flatten());
|
||||
let item_actions = p1_item_actions.into_iter().flatten().chain(p2_item_actions.into_iter().flatten());
|
||||
|
||||
for action in item_actions {
|
||||
it.action(action);
|
||||
}
|
||||
|
||||
Ok(item_trades.collect())
|
||||
}
|
||||
else {
|
||||
Err(ItemManagerError::InvalidTrade.into())
|
||||
}
|
||||
|
||||
});
|
||||
it.commit(self, entity_gateway)
|
||||
.await
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ItemToTradeDetail {
|
||||
Individual(ItemDetail),
|
||||
Stacked(Tool, usize),
|
||||
}
|
||||
|
||||
pub struct ItemToTrade {
|
||||
pub add_to: AreaClient,
|
||||
pub remove_from: AreaClient,
|
||||
pub item_id: ClientItemId,
|
||||
pub item_detail: ItemToTradeDetail,
|
||||
}
|
||||
|
||||
|
||||
struct RemoveFromLocalFloor {
|
||||
character_id: CharacterEntityId,
|
||||
@ -1050,3 +1169,76 @@ impl<EG: EntityGateway> ItemAction<EG> for AddMesetaFloorItemToInventory {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct AddIndividualItemToInventory {
|
||||
character_id: CharacterEntityId,
|
||||
item_id: ItemEntityId,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<EG: EntityGateway> ItemAction<EG> for AddIndividualItemToInventory {
|
||||
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct AddStackedItemToInventory {
|
||||
character_id: CharacterEntityId,
|
||||
item_ids: Vec<ItemEntityId>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<EG: EntityGateway> ItemAction<EG> for AddStackedItemToInventory {
|
||||
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct RemoveIndividualItemFromInventory {
|
||||
character_id: CharacterEntityId,
|
||||
item_id: ItemEntityId,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<EG: EntityGateway> ItemAction<EG> for RemoveIndividualItemFromInventory {
|
||||
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct RemoveStackedItemFromInventory {
|
||||
character_id: CharacterEntityId,
|
||||
item_ids: Vec<ItemEntityId>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<EG: EntityGateway> ItemAction<EG> for RemoveStackedItemFromInventory {
|
||||
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct AddMesetaToInventory {
|
||||
character_id: CharacterEntityId,
|
||||
amount: usize,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<EG: EntityGateway> ItemAction<EG> for AddMesetaToInventory {
|
||||
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct RemoveMesetaFromInventory {
|
||||
character_id: CharacterEntityId,
|
||||
amount: usize,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<EG: EntityGateway> ItemAction<EG> for RemoveMesetaFromInventory {
|
||||
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDr
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
|
||||
pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &item::ItemDetail) -> Result<CreateItem, ShipError> {
|
||||
let bytes = item.as_client_bytes();
|
||||
Ok(CreateItem {
|
||||
@ -39,6 +40,7 @@ pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, it
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
|
||||
pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> Result<CreateItem, ShipError> {
|
||||
let bytes = tool.as_stacked_bytes(amount);
|
||||
Ok(CreateItem {
|
||||
|
@ -9,7 +9,7 @@ use crate::common::serverstate::ClientId;
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops, TradeItem, TradeState, TradeStatus};
|
||||
use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||
use crate::ship::drops::ItemDrop;
|
||||
use crate::ship::items::{ItemManager, ItemManagerError, ClientItemId, TriggerCreateItem, FloorItem, FloorType};
|
||||
use crate::ship::items::{ItemManager, ItemManagerError, ClientItemId, TriggerCreateItem, FloorItem, FloorType, ItemToTradeDetail};
|
||||
use crate::ship::items::inventory::InventoryItem;
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use crate::entity::item;
|
||||
@ -125,7 +125,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// this function is a shitshow due to not thinking of what would happen if I needed more than 1 client at a time
|
||||
pub async fn trade_confirmed<EG>(id: ClientId,
|
||||
entity_gateway: &mut EG,
|
||||
client_location: &ClientLocation,
|
||||
@ -135,47 +134,76 @@ pub async fn trade_confirmed<EG>(id: ClientId,
|
||||
where
|
||||
EG: EntityGateway
|
||||
{
|
||||
let (this_client_confirmed, other_client_id) = {
|
||||
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
(client.confirmed_trade, client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.0)
|
||||
};
|
||||
let other_client_confirmed = {
|
||||
let client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
client.confirmed_trade
|
||||
};
|
||||
|
||||
{
|
||||
let this_client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
this_client.confirmed_trade = true;
|
||||
this_client.trade.as_mut().ok_or(TradeError::NotInTradeMenu)?.status = TradeStatus::Confirmed;
|
||||
}
|
||||
|
||||
let both_confirmed = {
|
||||
let this_client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let other_client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
this_client.confirmed_trade && other_client.confirmed_trade
|
||||
let other_client_id = this_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.other_client;
|
||||
let other_client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(other_client_id))?;
|
||||
|
||||
let this_client_trade = this_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?;
|
||||
let other_client_trade = other_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?;
|
||||
this_client_trade.status == TradeStatus::Confirmed && other_client_trade.status == TradeStatus::Confirmed
|
||||
};
|
||||
|
||||
|
||||
if both_confirmed {
|
||||
{
|
||||
let this_client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let other_client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
|
||||
let this_character_items = &this_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.1;
|
||||
item_manager.send_items_to_other_player(entity_gateway, &this_client.character, &other_client.character, this_character_items).await?;
|
||||
|
||||
let other_character_items = &other_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.1;
|
||||
item_manager.send_items_to_other_player(entity_gateway, &other_client.character, &this_client.character, other_character_items).await?;
|
||||
}
|
||||
{
|
||||
let this_client_trade = {
|
||||
let this_client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let this_client_trade = this_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.clone();
|
||||
this_client.trade = None;
|
||||
}
|
||||
{
|
||||
let other_client = clients.get_mut(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
this_client_trade
|
||||
};
|
||||
let other_client_trade = {
|
||||
let other_client = clients.get_mut(&this_client_trade.other_client).ok_or(ShipError::ClientNotFound(this_client_trade.other_client))?;
|
||||
let other_client_trade = other_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.clone();
|
||||
other_client.trade = None;
|
||||
}
|
||||
other_client_trade
|
||||
};
|
||||
let this_client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let other_client = clients.get(&this_client_trade.other_client).ok_or(ShipError::ClientNotFound(this_client_trade.other_client))?;
|
||||
|
||||
Ok(Box::new(None.into_iter()))
|
||||
let this_local_client = client_location.get_local_client(id)?;
|
||||
let other_local_client = client_location.get_local_client(this_client_trade.other_client)?;
|
||||
|
||||
let traded_items = item_manager.trade_items(
|
||||
entity_gateway,
|
||||
(&this_local_client, &this_client.character, &this_client_trade.items),
|
||||
(&other_local_client, &other_client.character, &other_client_trade.items)
|
||||
).await?;
|
||||
|
||||
let clients_in_room = client_location.get_all_clients_by_client(id)?;
|
||||
let traded_item_packets = traded_items
|
||||
.into_iter()
|
||||
.map(|item| {
|
||||
match item.item_detail {
|
||||
ItemToTradeDetail::Individual(item_detail) => {
|
||||
[
|
||||
GameMessage::CreateItem(builder::message::create_individual_item(item.add_to, item.item_id, &item_detail).unwrap()),
|
||||
GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(item.remove_from, item.item_id, 1)) // TODO: amount = ?
|
||||
]
|
||||
},
|
||||
ItemToTradeDetail::Stacked(tool, amount) => {
|
||||
[
|
||||
GameMessage::CreateItem(builder::message::create_stacked_item(item.add_to, item.item_id, &tool, amount).unwrap()),
|
||||
GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(item.remove_from, item.item_id, amount as u32))
|
||||
]
|
||||
},
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.map(move |packet| {
|
||||
clients_in_room
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(move |client| {
|
||||
(client.client, SendShipPacket::Message(Message::new(packet.clone())))
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
Ok(Box::new(traded_item_packets))
|
||||
}
|
||||
else {
|
||||
Ok(Box::new(None.into_iter()))
|
||||
|
Loading…
x
Reference in New Issue
Block a user