TRADING JUST IN TIME TO BARELY MISS XMAS
This commit is contained in:
parent
ecf1f23c6c
commit
81916d1f57
@ -275,15 +275,6 @@ impl ItemManager {
|
||||
))
|
||||
}
|
||||
|
||||
/*pub fn get_character_bank_mut(&mut self, character: &CharacterEntity) -> Result<&CharacterBank, ItemManagerError> {
|
||||
Ok(self.character_bank
|
||||
.get_mut(&character.id)
|
||||
.ok_or(ItemManagerError::NoCharacter(character.id))?
|
||||
.entry(BankName("".to_string()))
|
||||
.or_insert(CharacterBank::new(Vec::new())))
|
||||
//.ok_or(ItemManagerError::InvalidBankName(BankName("".to_string())))?)
|
||||
}*/
|
||||
|
||||
pub fn remove_character_from_room(&mut self, character: &CharacterEntity) {
|
||||
self.character_inventory.remove(&character.id);
|
||||
self.character_floor.remove(&character.id);
|
||||
@ -986,14 +977,41 @@ impl ItemManager {
|
||||
let p1_inventory = it.manager.get_character_inventory(p1.1)?;
|
||||
let p2_inventory = it.manager.get_character_inventory(p2.1)?;
|
||||
|
||||
[(p2_inventory, p1_inventory, p2.2), (p1_inventory, p2_inventory, p1.2)].iter()
|
||||
.map(|(src_inventory, dest_inventory, to_trade)| {
|
||||
to_trade
|
||||
[(p2_inventory, p1_inventory, p2.2, p1.2), (p1_inventory, p2_inventory, p1.2, p2.2)].iter()
|
||||
.map(|(src_inventory, dest_inventory, trade_recv, trade_send)| {
|
||||
let item_slots_lost_to_trade = trade_send
|
||||
.iter()
|
||||
.fold(0, |acc, item| {
|
||||
match item {
|
||||
TradeItem::Individual(..) => {
|
||||
acc + 1
|
||||
},
|
||||
TradeItem::Stacked(item_id, amount) => {
|
||||
let stacked_inventory_item = try {
|
||||
src_inventory
|
||||
.get_item_by_id(*item_id)?
|
||||
.stacked()
|
||||
};
|
||||
if let Some(Some(item)) = stacked_inventory_item {
|
||||
if item.count() == *amount {
|
||||
acc + 1
|
||||
}
|
||||
else {
|
||||
acc
|
||||
}
|
||||
}
|
||||
else {
|
||||
acc
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
trade_recv
|
||||
.iter()
|
||||
.try_fold(dest_inventory.count(), |acc, item| {
|
||||
match item {
|
||||
TradeItem::Individual(..) => {
|
||||
if acc >= 30 {
|
||||
if acc >= (30 + item_slots_lost_to_trade) {
|
||||
Err(TradeError::NoInventorySpace)
|
||||
}
|
||||
else {
|
||||
@ -1017,7 +1035,12 @@ impl ItemManager {
|
||||
Err(TradeError::NoStackSpace)
|
||||
},
|
||||
SpaceForStack::No(NoThereIsNotSpace::FullInventory) => {
|
||||
if acc >= (30 + item_slots_lost_to_trade) {
|
||||
Err(TradeError::NoInventorySpace)
|
||||
}
|
||||
else {
|
||||
Ok(acc + 1)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -14,7 +14,14 @@ pub enum TradeItem {
|
||||
impl TradeItem {
|
||||
pub fn stacked(&self) -> Option<(items::ClientItemId, usize)> {
|
||||
match self {
|
||||
TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount as usize)),
|
||||
TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stacked_mut(&mut self) -> Option<(items::ClientItemId, &mut usize)> {
|
||||
match self {
|
||||
TradeItem::Stacked(item_id, ref mut amount) => Some((*item_id, amount)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@ -125,6 +132,10 @@ impl TradeState {
|
||||
self.trades.insert(*receiver, RefCell::new(state));
|
||||
}
|
||||
|
||||
pub fn in_trade(&self, client: &ClientId) -> bool {
|
||||
self.trades.contains_key(client)
|
||||
}
|
||||
|
||||
pub fn with<T, F> (&self, client: &ClientId, func: F) -> Result<T, TradeStateError>
|
||||
where
|
||||
F: Fn(&mut ClientTradeState, &mut ClientTradeState) -> T
|
||||
|
4271
tests/test_trade.rs
Normal file
4271
tests/test_trade.rs
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user