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) => { | ||||
|                                                 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, | ||||
|     #[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,7 +374,12 @@ 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() { | ||||
|                                         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 { | ||||
|                                         Err(TradeError::InvalidStackAmount(stacked_inventory_item.item_id, amount).into()) | ||||
|  | ||||
| @ -14,12 +14,19 @@ 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 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 { | ||||
|             TradeItem::Individual(item_id) => *item_id, | ||||
|             TradeItem::Stacked(item_id, _) => *item_id, | ||||
| @ -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