|
|
@ -42,6 +42,14 @@ pub enum TradeError { |
|
|
|
NoStackSpace,
|
|
|
|
#[error("invalid meseta amount")]
|
|
|
|
InvalidMeseta,
|
|
|
|
#[error("tried starting a trade while in one already")]
|
|
|
|
ClientAlreadyInTrade,
|
|
|
|
#[error("tried starting a trade while with player already in a trade")]
|
|
|
|
OtherAlreadyInTrade,
|
|
|
|
#[error("tried to trade item not specified in trade request")]
|
|
|
|
SketchyTrade,
|
|
|
|
#[error("items in trade window and items attempted to trade do not match")]
|
|
|
|
MismatchedTradeItems,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -63,6 +71,9 @@ where |
|
|
|
TradeRequestCommand::Initialize(ref act, meseta) => {
|
|
|
|
match act {
|
|
|
|
TradeRequestInitializeCommand::Initialize => {
|
|
|
|
if trades.in_trade(&id) {
|
|
|
|
return Err(TradeError::ClientAlreadyInTrade.into())
|
|
|
|
}
|
|
|
|
let trade_partner = client_location.get_client_neighbors(id)?
|
|
|
|
.into_iter()
|
|
|
|
.filter(|ac| {
|
|
|
@ -70,6 +81,9 @@ where |
|
|
|
})
|
|
|
|
.next()
|
|
|
|
.ok_or(TradeError::CouldNotFindTradePartner)?;
|
|
|
|
if trades.in_trade(&trade_partner.client) {
|
|
|
|
return Err(TradeError::OtherAlreadyInTrade.into())
|
|
|
|
}
|
|
|
|
trades.new_trade(&id, &trade_partner.client);
|
|
|
|
Ok(Box::new(client_location.get_all_clients_by_client(id)?.into_iter()
|
|
|
|
.filter(move |client| client.local_client.id() == target as u8)
|
|
|
@ -180,7 +194,7 @@ where |
|
|
|
|
|
|
|
match this.items[trade_item_index].stacked()?.1.cmp(&(amount as usize)) {
|
|
|
|
std::cmp::Ordering::Greater => {
|
|
|
|
this.items[trade_item_index].stacked()?.1 -= amount as usize;
|
|
|
|
*this.items[trade_item_index].stacked_mut()?.1 -= amount as usize;
|
|
|
|
},
|
|
|
|
std::cmp::Ordering::Equal => {
|
|
|
|
this.items.remove(trade_item_index);
|
|
|
@ -267,6 +281,15 @@ where |
|
|
|
.chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))))
|
|
|
|
}))
|
|
|
|
},
|
|
|
|
TradeRequestCommand::Cancel => {
|
|
|
|
trades.remove_trade(&id);
|
|
|
|
Ok(Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter()
|
|
|
|
.filter(move |client| client.local_client.id() == target as u8)
|
|
|
|
.map(move |client| {
|
|
|
|
(client.client, SendShipPacket::CancelTrade(CancelTrade {}))
|
|
|
|
})
|
|
|
|
.chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {}))))))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
@ -297,17 +320,31 @@ where |
|
|
|
}
|
|
|
|
|
|
|
|
let client = clients.get(&this.client()).ok_or(ShipError::ClientNotFound(this.client()))?;
|
|
|
|
let other_client = clients.get(&other.client()).ok_or(ShipError::ClientNotFound(other.client()))?;
|
|
|
|
let inventory = item_manager.get_character_inventory(&client.character)?;
|
|
|
|
|
|
|
|
let item_blobs = items_to_trade.items.iter().take(items_to_trade.count as usize);
|
|
|
|
item_blobs
|
|
|
|
if items_to_trade.count as usize != (this.items.len() + (if this.meseta != 0 { 1 } else { 0 })) {
|
|
|
|
return Err(TradeError::MismatchedTradeItems.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
items_to_trade.items
|
|
|
|
.iter()
|
|
|
|
.take(items_to_trade.count as usize)
|
|
|
|
.map(|item| {
|
|
|
|
if ClientItemId(item.item_id) == OTHER_MESETA_ITEM_ID {
|
|
|
|
if item.item_data[0] != 4 {
|
|
|
|
return Err(TradeError::InvalidItemId(ClientItemId(item.item_id)).into())
|
|
|
|
}
|
|
|
|
let amount = u32::from_le_bytes(item.item_data2);
|
|
|
|
if amount > client.character.meseta {
|
|
|
|
let character_meseta = item_manager.get_character_meseta(&client.character.id).map_err(|_| TradeError::InvalidMeseta)?;
|
|
|
|
let other_character_meseta = item_manager.get_character_meseta(&other_client.character.id).map_err(|_| TradeError::InvalidMeseta)?;
|
|
|
|
if amount > character_meseta.0 {
|
|
|
|
return Err(TradeError::InvalidMeseta.into())
|
|
|
|
}
|
|
|
|
if (amount + other_character_meseta.0) > 999999 {
|
|
|
|
return Err(TradeError::InvalidMeseta.into())
|
|
|
|
}
|
|
|
|
if amount != this.meseta as u32{
|
|
|
|
return Err(TradeError::InvalidMeseta.into())
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
@ -315,6 +352,10 @@ where |
|
|
|
else {
|
|
|
|
let real_item = inventory.get_item_by_id(ClientItemId(item.item_id))
|
|
|
|
.ok_or(ItemManagerError::NoSuchItemId(ClientItemId(item.item_id)))?;
|
|
|
|
let real_trade_item = this.items
|
|
|
|
.iter()
|
|
|
|
.find(|i| i.item_id() == ClientItemId(item.item_id))
|
|
|
|
.ok_or_else(|| TradeError::SketchyTrade)?;
|
|
|
|
let trade_item_bytes: [u8; 16] = item.item_data.iter()
|
|
|
|
.chain(item.item_data2.iter())
|
|
|
|
.cloned().collect::<Vec<u8>>()
|
|
|
@ -333,12 +374,17 @@ where |
|
|
|
if real_item.as_client_bytes()[0..4] == trade_item_bytes[0..4] {
|
|
|
|
let amount = trade_item_bytes[5] as usize;
|
|
|
|
if amount <= stacked_inventory_item.entity_ids.len() {
|
|
|
|
if real_trade_item.stacked().ok_or_else(|| TradeError::SketchyTrade)?.1 == amount {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Err(TradeError::InvalidStackAmount(stacked_inventory_item.item_id, amount).into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Err(TradeError::InvalidStackAmount(stacked_inventory_item.item_id, amount).into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Err(TradeError::ClientItemIdDidNotMatchItem(ClientItemId(item.item_id), trade_item_bytes).into())
|
|
|
|
}
|
|
|
|