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) {
|
pub fn remove_character_from_room(&mut self, character: &CharacterEntity) {
|
||||||
self.character_inventory.remove(&character.id);
|
self.character_inventory.remove(&character.id);
|
||||||
self.character_floor.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 p1_inventory = it.manager.get_character_inventory(p1.1)?;
|
||||||
let p2_inventory = it.manager.get_character_inventory(p2.1)?;
|
let p2_inventory = it.manager.get_character_inventory(p2.1)?;
|
||||||
|
|
||||||
[(p2_inventory, p1_inventory, p2.2), (p1_inventory, p2_inventory, p1.2)].iter()
|
[(p2_inventory, p1_inventory, p2.2, p1.2), (p1_inventory, p2_inventory, p1.2, p2.2)].iter()
|
||||||
.map(|(src_inventory, dest_inventory, to_trade)| {
|
.map(|(src_inventory, dest_inventory, trade_recv, trade_send)| {
|
||||||
to_trade
|
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()
|
.iter()
|
||||||
.try_fold(dest_inventory.count(), |acc, item| {
|
.try_fold(dest_inventory.count(), |acc, item| {
|
||||||
match item {
|
match item {
|
||||||
TradeItem::Individual(..) => {
|
TradeItem::Individual(..) => {
|
||||||
if acc >= 30 {
|
if acc >= (30 + item_slots_lost_to_trade) {
|
||||||
Err(TradeError::NoInventorySpace)
|
Err(TradeError::NoInventorySpace)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1017,7 +1035,12 @@ impl ItemManager {
|
|||||||
Err(TradeError::NoStackSpace)
|
Err(TradeError::NoStackSpace)
|
||||||
},
|
},
|
||||||
SpaceForStack::No(NoThereIsNotSpace::FullInventory) => {
|
SpaceForStack::No(NoThereIsNotSpace::FullInventory) => {
|
||||||
Err(TradeError::NoInventorySpace)
|
if acc >= (30 + item_slots_lost_to_trade) {
|
||||||
|
Err(TradeError::NoInventorySpace)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Ok(acc + 1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,14 @@ pub enum TradeError {
|
|||||||
NoStackSpace,
|
NoStackSpace,
|
||||||
#[error("invalid meseta amount")]
|
#[error("invalid meseta amount")]
|
||||||
InvalidMeseta,
|
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) => {
|
TradeRequestCommand::Initialize(ref act, meseta) => {
|
||||||
match act {
|
match act {
|
||||||
TradeRequestInitializeCommand::Initialize => {
|
TradeRequestInitializeCommand::Initialize => {
|
||||||
|
if trades.in_trade(&id) {
|
||||||
|
return Err(TradeError::ClientAlreadyInTrade.into())
|
||||||
|
}
|
||||||
let trade_partner = client_location.get_client_neighbors(id)?
|
let trade_partner = client_location.get_client_neighbors(id)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|ac| {
|
.filter(|ac| {
|
||||||
@ -70,6 +81,9 @@ where
|
|||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
.ok_or(TradeError::CouldNotFindTradePartner)?;
|
.ok_or(TradeError::CouldNotFindTradePartner)?;
|
||||||
|
if trades.in_trade(&trade_partner.client) {
|
||||||
|
return Err(TradeError::OtherAlreadyInTrade.into())
|
||||||
|
}
|
||||||
trades.new_trade(&id, &trade_partner.client);
|
trades.new_trade(&id, &trade_partner.client);
|
||||||
Ok(Box::new(client_location.get_all_clients_by_client(id)?.into_iter()
|
Ok(Box::new(client_location.get_all_clients_by_client(id)?.into_iter()
|
||||||
.filter(move |client| client.local_client.id() == target as u8)
|
.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)) {
|
match this.items[trade_item_index].stacked()?.1.cmp(&(amount as usize)) {
|
||||||
std::cmp::Ordering::Greater => {
|
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 => {
|
std::cmp::Ordering::Equal => {
|
||||||
this.items.remove(trade_item_index);
|
this.items.remove(trade_item_index);
|
||||||
@ -267,6 +281,15 @@ where
|
|||||||
.chain(std::iter::once((id, SendShipPacket::CancelTrade(CancelTrade {})))))
|
.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 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 inventory = item_manager.get_character_inventory(&client.character)?;
|
||||||
|
|
||||||
let item_blobs = items_to_trade.items.iter().take(items_to_trade.count as usize);
|
if items_to_trade.count as usize != (this.items.len() + (if this.meseta != 0 { 1 } else { 0 })) {
|
||||||
item_blobs
|
return Err(TradeError::MismatchedTradeItems.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
items_to_trade.items
|
||||||
|
.iter()
|
||||||
|
.take(items_to_trade.count as usize)
|
||||||
.map(|item| {
|
.map(|item| {
|
||||||
if ClientItemId(item.item_id) == OTHER_MESETA_ITEM_ID {
|
if ClientItemId(item.item_id) == OTHER_MESETA_ITEM_ID {
|
||||||
if item.item_data[0] != 4 {
|
if item.item_data[0] != 4 {
|
||||||
return Err(TradeError::InvalidItemId(ClientItemId(item.item_id)).into())
|
return Err(TradeError::InvalidItemId(ClientItemId(item.item_id)).into())
|
||||||
}
|
}
|
||||||
let amount = u32::from_le_bytes(item.item_data2);
|
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())
|
return Err(TradeError::InvalidMeseta.into())
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -315,6 +352,10 @@ where
|
|||||||
else {
|
else {
|
||||||
let real_item = inventory.get_item_by_id(ClientItemId(item.item_id))
|
let real_item = inventory.get_item_by_id(ClientItemId(item.item_id))
|
||||||
.ok_or(ItemManagerError::NoSuchItemId(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()
|
let trade_item_bytes: [u8; 16] = item.item_data.iter()
|
||||||
.chain(item.item_data2.iter())
|
.chain(item.item_data2.iter())
|
||||||
.cloned().collect::<Vec<u8>>()
|
.cloned().collect::<Vec<u8>>()
|
||||||
@ -333,7 +374,12 @@ where
|
|||||||
if real_item.as_client_bytes()[0..4] == trade_item_bytes[0..4] {
|
if real_item.as_client_bytes()[0..4] == trade_item_bytes[0..4] {
|
||||||
let amount = trade_item_bytes[5] as usize;
|
let amount = trade_item_bytes[5] as usize;
|
||||||
if amount <= stacked_inventory_item.entity_ids.len() {
|
if amount <= stacked_inventory_item.entity_ids.len() {
|
||||||
Ok(())
|
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 {
|
else {
|
||||||
Err(TradeError::InvalidStackAmount(stacked_inventory_item.item_id, amount).into())
|
Err(TradeError::InvalidStackAmount(stacked_inventory_item.item_id, amount).into())
|
||||||
|
@ -14,12 +14,19 @@ pub enum TradeItem {
|
|||||||
impl TradeItem {
|
impl TradeItem {
|
||||||
pub fn stacked(&self) -> Option<(items::ClientItemId, usize)> {
|
pub fn stacked(&self) -> Option<(items::ClientItemId, usize)> {
|
||||||
match self {
|
match self {
|
||||||
TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount as usize)),
|
TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn item_id(&self) -> items::ClientItemId {
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn item_id(&self) -> items::ClientItemId {
|
||||||
match self {
|
match self {
|
||||||
TradeItem::Individual(item_id) => *item_id,
|
TradeItem::Individual(item_id) => *item_id,
|
||||||
TradeItem::Stacked(item_id, _) => *item_id,
|
TradeItem::Stacked(item_id, _) => *item_id,
|
||||||
@ -125,6 +132,10 @@ impl TradeState {
|
|||||||
self.trades.insert(*receiver, RefCell::new(state));
|
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>
|
pub fn with<T, F> (&self, client: &ClientId, func: F) -> Result<T, TradeStateError>
|
||||||
where
|
where
|
||||||
F: Fn(&mut ClientTradeState, &mut ClientTradeState) -> T
|
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