Merge pull request 'equip_changes' (#241) from equip_changes into master
Reviewed-by: jake <jake@sharnoth.com>
This commit is contained in:
commit
a50f1d58a4
110
src/bin/main.rs
110
src/bin/main.rs
@ -194,6 +194,116 @@ fn main() {
|
|||||||
name: item::BankName("".to_string()),
|
name: item::BankName("".to_string()),
|
||||||
}
|
}
|
||||||
}).await;
|
}).await;
|
||||||
|
entity_gateway.create_item(
|
||||||
|
NewItemEntity {
|
||||||
|
item: ItemDetail::Armor(
|
||||||
|
item::armor::Armor {
|
||||||
|
armor: item::armor::ArmorType::Frame,
|
||||||
|
dfp: 0,
|
||||||
|
evp: 0,
|
||||||
|
slots: 4,
|
||||||
|
modifiers: Vec::new(),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: ItemLocation::Inventory {
|
||||||
|
character_id: character.id,
|
||||||
|
slot: 5,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).await;
|
||||||
|
entity_gateway.create_item(
|
||||||
|
NewItemEntity {
|
||||||
|
item: ItemDetail::Shield(
|
||||||
|
item::shield::Shield {
|
||||||
|
shield: item::shield::ShieldType::Barrier,
|
||||||
|
dfp: 0,
|
||||||
|
evp: 0,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: ItemLocation::Inventory {
|
||||||
|
character_id: character.id,
|
||||||
|
slot: 6,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).await;
|
||||||
|
entity_gateway.create_item(
|
||||||
|
NewItemEntity {
|
||||||
|
item: ItemDetail::Unit(
|
||||||
|
item::unit::Unit {
|
||||||
|
unit: item::unit::UnitType::PriestMind,
|
||||||
|
modifier: Some(item::unit::UnitModifier::Minus),
|
||||||
|
armor_slot: 0,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: ItemLocation::Inventory {
|
||||||
|
character_id: character.id,
|
||||||
|
slot: 7,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).await;
|
||||||
|
entity_gateway.create_item(
|
||||||
|
NewItemEntity {
|
||||||
|
item: ItemDetail::Unit(
|
||||||
|
item::unit::Unit {
|
||||||
|
unit: item::unit::UnitType::PriestMind,
|
||||||
|
modifier: Some(item::unit::UnitModifier::Minus),
|
||||||
|
armor_slot: 1,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: ItemLocation::Inventory {
|
||||||
|
character_id: character.id,
|
||||||
|
slot: 8,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).await;
|
||||||
|
entity_gateway.create_item(
|
||||||
|
NewItemEntity {
|
||||||
|
item: ItemDetail::Unit(
|
||||||
|
item::unit::Unit {
|
||||||
|
unit: item::unit::UnitType::PriestMind,
|
||||||
|
modifier: Some(item::unit::UnitModifier::Minus),
|
||||||
|
armor_slot: 2,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: ItemLocation::Inventory {
|
||||||
|
character_id: character.id,
|
||||||
|
slot: 9,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).await;
|
||||||
|
entity_gateway.create_item(
|
||||||
|
NewItemEntity {
|
||||||
|
item: ItemDetail::Unit(
|
||||||
|
item::unit::Unit {
|
||||||
|
unit: item::unit::UnitType::PriestMind,
|
||||||
|
modifier: Some(item::unit::UnitModifier::Minus),
|
||||||
|
armor_slot: 3,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
location: ItemLocation::Inventory {
|
||||||
|
character_id: character.id,
|
||||||
|
slot: 10,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).await;
|
||||||
|
entity_gateway.create_item(
|
||||||
|
NewItemEntity {
|
||||||
|
item: ItemDetail::Mag(
|
||||||
|
item::mag::Mag::baby_mag(5)
|
||||||
|
),
|
||||||
|
location: ItemLocation::Inventory {
|
||||||
|
character_id: character.id,
|
||||||
|
slot: 11,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("[patch] starting server");
|
info!("[patch] starting server");
|
||||||
|
@ -384,6 +384,7 @@ impl Into<shield::Shield> for PgShield {
|
|||||||
pub struct PgUnit {
|
pub struct PgUnit {
|
||||||
unit: unit::UnitType,
|
unit: unit::UnitType,
|
||||||
modifier: Option<unit::UnitModifier>,
|
modifier: Option<unit::UnitModifier>,
|
||||||
|
armor_slot: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<unit::Unit> for PgUnit {
|
impl From<unit::Unit> for PgUnit {
|
||||||
@ -391,6 +392,7 @@ impl From<unit::Unit> for PgUnit {
|
|||||||
PgUnit {
|
PgUnit {
|
||||||
unit: other.unit,
|
unit: other.unit,
|
||||||
modifier: other.modifier,
|
modifier: other.modifier,
|
||||||
|
armor_slot: other.armor_slot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,6 +402,7 @@ impl Into<unit::Unit> for PgUnit {
|
|||||||
unit::Unit {
|
unit::Unit {
|
||||||
unit: self.unit,
|
unit: self.unit,
|
||||||
modifier: self.modifier,
|
modifier: self.modifier,
|
||||||
|
armor_slot: self.armor_slot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,6 +335,7 @@ pub enum UnitModifier {
|
|||||||
pub struct Unit {
|
pub struct Unit {
|
||||||
pub unit: UnitType,
|
pub unit: UnitType,
|
||||||
pub modifier: Option<UnitModifier>,
|
pub modifier: Option<UnitModifier>,
|
||||||
|
pub armor_slot: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -361,7 +362,7 @@ impl Unit {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result[4] = self.armor_slot;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,6 +380,7 @@ impl Unit {
|
|||||||
Ok(Unit{
|
Ok(Unit{
|
||||||
unit: u.unwrap(),
|
unit: u.unwrap(),
|
||||||
modifier: m,
|
modifier: m,
|
||||||
|
armor_slot: data[4],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -89,6 +89,7 @@ impl GenericUnitTable {
|
|||||||
ItemDropType::Unit(Unit {
|
ItemDropType::Unit(Unit {
|
||||||
unit: unit_type,
|
unit: unit_type,
|
||||||
modifier: unit_modifier,
|
modifier: unit_modifier,
|
||||||
|
armor_slot: 0,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -116,6 +117,7 @@ mod test {
|
|||||||
assert!(gut.get_drop(&area, &mut rng) == Some(ItemDropType::Unit(Unit {
|
assert!(gut.get_drop(&area, &mut rng) == Some(ItemDropType::Unit(Unit {
|
||||||
unit: unit,
|
unit: unit,
|
||||||
modifier: umod,
|
modifier: umod,
|
||||||
|
armor_slot: 0,
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,6 +128,7 @@ impl RareDropTable {
|
|||||||
ItemDropType::Unit(Unit {
|
ItemDropType::Unit(Unit {
|
||||||
unit: unit,
|
unit: unit,
|
||||||
modifier: None,
|
modifier: None,
|
||||||
|
armor_slot: 0,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
RareDropItem::Tool(tool) => {
|
RareDropItem::Tool(tool) => {
|
||||||
|
@ -336,7 +336,11 @@ impl<'a> InventoryItemHandle<'a> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_slot(&self) -> usize {
|
||||||
|
self.slot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -418,6 +422,60 @@ impl CharacterInventory {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_equipped_armor_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> {
|
||||||
|
let (slot, _) = self.items.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, item)| {
|
||||||
|
if let InventoryItem::Individual(individual_inventory_item) = item {
|
||||||
|
if let ItemDetail::Armor(_) = &individual_inventory_item.item {
|
||||||
|
return individual_inventory_item.equipped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.nth(0)?;
|
||||||
|
Some(InventoryItemHandle {
|
||||||
|
inventory: self,
|
||||||
|
slot: slot,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_equipped_shield_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> {
|
||||||
|
let (slot, _) = self.items.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, item)| {
|
||||||
|
if let InventoryItem::Individual(individual_inventory_item) = item {
|
||||||
|
if let ItemDetail::Shield(_) = &individual_inventory_item.item {
|
||||||
|
return individual_inventory_item.equipped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.nth(0)?;
|
||||||
|
Some(InventoryItemHandle {
|
||||||
|
inventory: self,
|
||||||
|
slot: slot,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_equipped_weapon_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> {
|
||||||
|
let (slot, _) = self.items.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, item)| {
|
||||||
|
if let InventoryItem::Individual(individual_inventory_item) = item {
|
||||||
|
if let ItemDetail::Weapon(_) = &individual_inventory_item.item {
|
||||||
|
return individual_inventory_item.equipped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.nth(0)?;
|
||||||
|
Some(InventoryItemHandle {
|
||||||
|
inventory: self,
|
||||||
|
slot: slot,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&InventoryItem> {
|
pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&InventoryItem> {
|
||||||
self.items.iter()
|
self.items.iter()
|
||||||
.filter(|item| {
|
.filter(|item| {
|
||||||
@ -569,5 +627,9 @@ impl CharacterInventory {
|
|||||||
pub fn iter(&self) -> impl Iterator<Item = &InventoryItem> {
|
pub fn iter(&self) -> impl Iterator<Item = &InventoryItem> {
|
||||||
self.items.iter()
|
self.items.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn items(&self) -> &Vec<InventoryItem> {
|
||||||
|
&self.items
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,9 @@ use thiserror::Error;
|
|||||||
use crate::entity::gateway::EntityGateway;
|
use crate::entity::gateway::EntityGateway;
|
||||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||||
use crate::entity::item::{ItemDetail, ItemLocation, BankName};
|
use crate::entity::item::{ItemDetail, ItemLocation, BankName};
|
||||||
use crate::entity::item::{Meseta, NewItemEntity};
|
use crate::entity::item::{Meseta, NewItemEntity, ItemEntity};
|
||||||
use crate::entity::item::tool::{Tool, ToolType};
|
use crate::entity::item::tool::{Tool, ToolType};
|
||||||
|
use crate::entity::item::unit;
|
||||||
use crate::ship::map::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use crate::ship::ship::ItemDropLocation;
|
use crate::ship::ship::ItemDropLocation;
|
||||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||||
@ -42,7 +43,11 @@ pub enum ItemManagerError {
|
|||||||
UseItemError(#[from] use_tool::UseItemError),
|
UseItemError(#[from] use_tool::UseItemError),
|
||||||
CouldNotBuyItem,
|
CouldNotBuyItem,
|
||||||
CouldNotAddBoughtItemToInventory,
|
CouldNotAddBoughtItemToInventory,
|
||||||
ItemIdNotInInventory(ClientItemId)
|
ItemIdNotInInventory(ClientItemId),
|
||||||
|
CannotGetMutItem,
|
||||||
|
CannotGetIndividualItem,
|
||||||
|
InvalidSlot(u8, u8), // slots available, slot attempted
|
||||||
|
NoArmorEquipped,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -676,7 +681,6 @@ impl ItemManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn use_item<EG: EntityGateway>(&mut self,
|
pub async fn use_item<EG: EntityGateway>(&mut self,
|
||||||
used_item: ConsumedItem,
|
used_item: ConsumedItem,
|
||||||
entity_gateway: &mut EG,
|
entity_gateway: &mut EG,
|
||||||
@ -893,4 +897,82 @@ impl ItemManager {
|
|||||||
};
|
};
|
||||||
Ok(inventory_item)
|
Ok(inventory_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: check if slot exists before putting units into it
|
||||||
|
pub async fn player_equips_item<EG: EntityGateway>(&mut self,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
character: &CharacterEntity,
|
||||||
|
item_id: ClientItemId,
|
||||||
|
equip_slot: u8)
|
||||||
|
-> Result<(), ItemManagerError> {
|
||||||
|
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||||
|
let mut inventory_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?;
|
||||||
|
let slot = inventory_item_handle.get_slot();
|
||||||
|
let inventory_item = inventory_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?.individual().ok_or(ItemManagerError::CannotGetIndividualItem)?;
|
||||||
|
inventory_item.equipped = true;
|
||||||
|
if let ItemDetail::Unit(u) = inventory_item.item {
|
||||||
|
if equip_slot > 0 {
|
||||||
|
inventory_item.item = ItemDetail::Unit(unit::Unit {
|
||||||
|
unit: u.unit,
|
||||||
|
modifier: u.modifier,
|
||||||
|
armor_slot: ((equip_slot & 0x7) - 1) % 4, // or just be lazy and do equip_slot - 9
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
inventory_item.item = ItemDetail::Unit(unit::Unit {
|
||||||
|
unit: u.unit,
|
||||||
|
modifier: u.modifier,
|
||||||
|
armor_slot: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{
|
||||||
|
character_id: character.id,
|
||||||
|
slot: slot,
|
||||||
|
equipped: true,
|
||||||
|
}).await;
|
||||||
|
entity_gateway.save_item(&ItemEntity{
|
||||||
|
id: inventory_item.entity_id,
|
||||||
|
location: ItemLocation::Inventory{
|
||||||
|
character_id: character.id,
|
||||||
|
slot: slot,
|
||||||
|
equipped: true,
|
||||||
|
},
|
||||||
|
item: inventory_item.item.clone(),
|
||||||
|
}).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn player_unequips_item<EG: EntityGateway>(&mut self,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
character: &CharacterEntity,
|
||||||
|
item_id: ClientItemId)
|
||||||
|
-> Result<(), ItemManagerError> {
|
||||||
|
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
|
||||||
|
let mut inventory_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?;
|
||||||
|
let slot = inventory_item_handle.get_slot();
|
||||||
|
let inventory_item = inventory_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?.individual().ok_or(ItemManagerError::CannotGetIndividualItem)?;
|
||||||
|
inventory_item.equipped = false;
|
||||||
|
if let ItemDetail::Unit(u) = inventory_item.item {
|
||||||
|
inventory_item.item = ItemDetail::Unit(unit::Unit {
|
||||||
|
unit: u.unit,
|
||||||
|
modifier: u.modifier,
|
||||||
|
armor_slot: 0,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{
|
||||||
|
character_id: character.id,
|
||||||
|
slot: slot,
|
||||||
|
equipped: false,
|
||||||
|
}).await;
|
||||||
|
entity_gateway.save_item(&ItemEntity{
|
||||||
|
id: inventory_item.entity_id,
|
||||||
|
location: ItemLocation::Inventory{
|
||||||
|
character_id: character.id,
|
||||||
|
slot: slot,
|
||||||
|
equipped: false,
|
||||||
|
},
|
||||||
|
item: inventory_item.item.clone(),
|
||||||
|
}).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
use libpso::packet::ship::*;
|
use libpso::packet::ship::*;
|
||||||
use libpso::packet::messages::*;
|
use libpso::packet::messages::*;
|
||||||
use crate::entity::gateway::EntityGateway;
|
use crate::entity::gateway::EntityGateway;
|
||||||
use crate::entity::item::ItemDetail;
|
use crate::entity::item::{ItemType};
|
||||||
use crate::entity::item::tool::ToolType;
|
|
||||||
use crate::common::serverstate::ClientId;
|
use crate::common::serverstate::ClientId;
|
||||||
use crate::common::leveltable::CharacterLevelTable;
|
use crate::common::leveltable::CharacterLevelTable;
|
||||||
use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients, ItemDropLocation};
|
use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients, ItemDropLocation};
|
||||||
use crate::ship::location::{ClientLocation, ClientLocationError};
|
use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||||
use crate::ship::map::{MapArea};
|
|
||||||
use crate::ship::items::{ItemManager, ClientItemId};
|
use crate::ship::items::{ItemManager, ClientItemId};
|
||||||
use crate::ship::packet::builder;
|
use crate::ship::packet::builder;
|
||||||
|
|
||||||
@ -275,7 +273,7 @@ pub async fn player_used_medical_center<EG>(id: ClientId,
|
|||||||
clients: &mut Clients)
|
clients: &mut Clients)
|
||||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError>
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError>
|
||||||
where
|
where
|
||||||
EG: EntityGateway
|
EG: EntityGateway
|
||||||
{
|
{
|
||||||
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
if client.character.meseta >= 10 {
|
if client.character.meseta >= 10 {
|
||||||
@ -307,3 +305,54 @@ where
|
|||||||
(client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone()))))
|
(client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone()))))
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn player_equips_item<EG>(id: ClientId,
|
||||||
|
pkt: &PlayerEquipItem,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
clients: &Clients,
|
||||||
|
item_manager: &mut ItemManager)
|
||||||
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError>
|
||||||
|
where
|
||||||
|
EG: EntityGateway
|
||||||
|
{
|
||||||
|
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
|
item_manager.player_equips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id), pkt.sub_menu).await?;
|
||||||
|
Ok(Box::new(None.into_iter()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn player_unequips_item<EG>(id: ClientId,
|
||||||
|
pkt: &PlayerUnequipItem,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
clients: &Clients,
|
||||||
|
item_manager: &mut ItemManager)
|
||||||
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError>
|
||||||
|
where
|
||||||
|
EG: EntityGateway
|
||||||
|
{
|
||||||
|
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
|
let equipped_unit_ids: Vec<ClientItemId> = {
|
||||||
|
item_manager.player_unequips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id)).await?;
|
||||||
|
let inventory = item_manager.get_character_inventory(&client.character).unwrap();
|
||||||
|
let ue_item = inventory.get_item_by_id(ClientItemId(pkt.item_id)).ok_or(ShipError::ItemError)?;
|
||||||
|
if let ItemType::Armor(_) = ue_item.item_type() {
|
||||||
|
inventory.items()
|
||||||
|
.iter()
|
||||||
|
.filter(|inv_item| {
|
||||||
|
if let ItemType::Unit(_) = inv_item.item_type() {
|
||||||
|
return inv_item.equipped()
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.map(|u| u.item_id())
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for unit_id in equipped_unit_ids {
|
||||||
|
item_manager.player_unequips_item(entity_gateway, &client.character, unit_id).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Box::new(None.into_iter()))
|
||||||
|
}
|
@ -393,6 +393,13 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
|||||||
GameMessage::PlayerFeedMag(player_feed_mag) => {
|
GameMessage::PlayerFeedMag(player_feed_mag) => {
|
||||||
handler::message::player_feed_mag(id, &player_feed_mag, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await
|
handler::message::player_feed_mag(id, &player_feed_mag, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await
|
||||||
},
|
},
|
||||||
|
GameMessage::PlayerEquipItem(player_equip_item) => {
|
||||||
|
handler::message::player_equips_item(id, &player_equip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await
|
||||||
|
},
|
||||||
|
GameMessage::PlayerUnequipItem(player_unequip_item) => {
|
||||||
|
handler::message::player_unequips_item(id, &player_unequip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await
|
||||||
|
},
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let cmsg = msg.clone();
|
let cmsg = msg.clone();
|
||||||
Ok(Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter()
|
Ok(Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter()
|
||||||
|
@ -89,6 +89,7 @@ impl ShopItem for ArmorShopItem {
|
|||||||
ItemDetail::Unit(Unit {
|
ItemDetail::Unit(Unit {
|
||||||
unit: *unit,
|
unit: *unit,
|
||||||
modifier: None,
|
modifier: None,
|
||||||
|
armor_slot: 0,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ mod common;
|
|||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_save_options<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: ClientId, options: u32) {
|
async fn test_save_options() {
|
||||||
let mut entity_gateway = InMemoryGateway::new();
|
let mut entity_gateway = InMemoryGateway::new();
|
||||||
|
|
||||||
let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
|
let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
|
||||||
|
218
tests/test_item_equip.rs
Normal file
218
tests/test_item_equip.rs
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
use elseware::common::serverstate::{ClientId, ServerState};
|
||||||
|
use elseware::entity::gateway::{EntityGateway, InMemoryGateway};
|
||||||
|
use elseware::ship::ship::{ShipServerState, RecvShipPacket};
|
||||||
|
use elseware::entity::item;
|
||||||
|
|
||||||
|
use libpso::packet::ship::*;
|
||||||
|
use libpso::packet::messages::*;
|
||||||
|
|
||||||
|
#[path = "common.rs"]
|
||||||
|
mod common;
|
||||||
|
use common::*;
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_equip_unit_from_equip_menu() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::new();
|
||||||
|
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
|
||||||
|
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Armor(
|
||||||
|
item::armor::Armor{
|
||||||
|
armor: item::armor::ArmorType::Frame,
|
||||||
|
dfp: 0,
|
||||||
|
evp: 0,
|
||||||
|
slots: 4,
|
||||||
|
modifiers: Vec::new(),
|
||||||
|
}),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 0,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}).await;
|
||||||
|
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Unit(
|
||||||
|
item::unit::Unit{
|
||||||
|
unit: item::unit::UnitType::KnightPower,
|
||||||
|
modifier: None,
|
||||||
|
armor_slot: 0,
|
||||||
|
}),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 1,
|
||||||
|
equipped: false,
|
||||||
|
}
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Unit(
|
||||||
|
item::unit::Unit{
|
||||||
|
unit: item::unit::UnitType::KnightPower,
|
||||||
|
modifier: Some(item::unit::UnitModifier::Plus),
|
||||||
|
armor_slot: 0,
|
||||||
|
}),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 2,
|
||||||
|
equipped: false,
|
||||||
|
}
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
let mut ship = ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build();
|
||||||
|
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
||||||
|
join_lobby(&mut ship, ClientId(1)).await;
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerEquipItem(PlayerEquipItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10001,
|
||||||
|
sub_menu: 9,
|
||||||
|
unknown1: 0,
|
||||||
|
})))).await.unwrap().for_each(drop);
|
||||||
|
|
||||||
|
// case when someone tries to send invalid submenu? submenu is 9-12 in normal gameplay
|
||||||
|
ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerEquipItem(PlayerEquipItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10002,
|
||||||
|
sub_menu: 14,
|
||||||
|
unknown1: 0,
|
||||||
|
})))).await.unwrap().for_each(drop);
|
||||||
|
|
||||||
|
let items = entity_gateway.get_items_by_character(&char1).await;
|
||||||
|
let (unit1, unit2) = (&items[1], &items[2]);
|
||||||
|
|
||||||
|
let unit1_equipped = match unit1.location {
|
||||||
|
item::ItemLocation::Inventory{equipped, ..} => equipped,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let unit2_equipped = match unit2.location {
|
||||||
|
item::ItemLocation::Inventory{equipped, ..} => equipped,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!({
|
||||||
|
match unit1.item {
|
||||||
|
item::ItemDetail::Unit(u) => {
|
||||||
|
if u.armor_slot == 0 && unit1_equipped {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!({
|
||||||
|
match unit2.item {
|
||||||
|
item::ItemDetail::Unit(u) => {
|
||||||
|
if u.armor_slot == 1 && unit2_equipped {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_unequip_armor_with_units() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::new();
|
||||||
|
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
|
||||||
|
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Armor(
|
||||||
|
item::armor::Armor{
|
||||||
|
armor: item::armor::ArmorType::Frame,
|
||||||
|
dfp: 0,
|
||||||
|
evp: 0,
|
||||||
|
slots: 4,
|
||||||
|
modifiers: Vec::new(),
|
||||||
|
}),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 0,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}).await;
|
||||||
|
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Unit(
|
||||||
|
item::unit::Unit{
|
||||||
|
unit: item::unit::UnitType::KnightPower,
|
||||||
|
modifier: None,
|
||||||
|
armor_slot: 0,
|
||||||
|
}),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 1,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Unit(
|
||||||
|
item::unit::Unit{
|
||||||
|
unit: item::unit::UnitType::KnightPower,
|
||||||
|
modifier: Some(item::unit::UnitModifier::Plus),
|
||||||
|
armor_slot: 1,
|
||||||
|
}),
|
||||||
|
location: item::ItemLocation::Inventory {
|
||||||
|
character_id: char1.id,
|
||||||
|
slot: 2,
|
||||||
|
equipped: true,
|
||||||
|
}
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
let mut ship = ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build();
|
||||||
|
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
||||||
|
join_lobby(&mut ship, ClientId(1)).await;
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUnequipItem(PlayerUnequipItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10000,
|
||||||
|
unknown1: 0,
|
||||||
|
})))).await.unwrap().for_each(drop);
|
||||||
|
|
||||||
|
let items = entity_gateway.get_items_by_character(&char1).await;
|
||||||
|
let (armor, unit1, unit2) = (&items[0], &items[1], &items[2]);
|
||||||
|
|
||||||
|
let armor_equipped = match armor.location {
|
||||||
|
item::ItemLocation::Inventory{equipped, ..} => equipped,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let unit1_equipped = match unit1.location {
|
||||||
|
item::ItemLocation::Inventory{equipped, ..} => equipped,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let unit2_equipped = match unit2.location {
|
||||||
|
item::ItemLocation::Inventory{equipped, ..} => equipped,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(armor_equipped == false);
|
||||||
|
assert!(unit1_equipped == false);
|
||||||
|
assert!(unit2_equipped == false);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user