From 2d5b6c5c01c5b159f1bc2615970ed7c1fb76778b Mon Sep 17 00:00:00 2001 From: andy Date: Mon, 13 Jun 2022 23:24:38 +0000 Subject: [PATCH] actually add and use AddKill modifier and remove dead code --- src/entity/gateway/entitygateway.rs | 6 +- src/entity/gateway/inmemory.rs | 17 +++-- src/entity/item/mod.rs | 17 +---- src/entity/item/unit.rs | 20 ++++-- src/entity/item/weapon.rs | 99 ++++++++++++++++------------- src/ship/items/manager.rs | 27 ++++---- src/ship/packet/handler/message.rs | 15 ++++- src/ship/ship.rs | 3 +- tests/test_unseal_items.rs | 51 +++++++++++++-- 9 files changed, 156 insertions(+), 99 deletions(-) diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index 68b3a84..e510da3 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -85,6 +85,9 @@ pub trait EntityGateway: Send + Sync + Clone { unimplemented!(); } + async fn add_unit_modifier(&mut self, _item_id: &ItemEntityId, _modifier: unit::UnitModifier) -> Result<(), GatewayError> { + unimplemented!(); + } /* async fn get_items_by_character(&self, _char_id: &CharacterEntityId) -> Result, GatewayError> { @@ -131,7 +134,4 @@ pub trait EntityGateway: Send + Sync + Clone { async fn set_bank_meseta(&mut self, _char_id: &CharacterEntityId, _bank: BankName, _amount: Meseta) -> Result<(), GatewayError> { unimplemented!(); } - async fn increment_kill_counter(&mut self, _item_entity_id: &ItemEntityId) -> Result<(), GatewayError> { - unimplemented!(); - } } diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 24ba67b..cc208b4 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -21,6 +21,7 @@ pub struct InMemoryGateway { equips: Arc>>, mag_modifiers: Arc>>>, weapon_modifiers: Arc>>>, + unit_modifiers: Arc>>>, } impl Default for InMemoryGateway { @@ -37,6 +38,7 @@ impl Default for InMemoryGateway { equips: Arc::new(Mutex::new(BTreeMap::new())), mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())), weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())), + unit_modifiers: Arc::new(Mutex::new(BTreeMap::new())), } } } @@ -271,6 +273,14 @@ impl EntityGateway for InMemoryGateway { Ok(()) } + async fn add_unit_modifier(&mut self, item_id: &ItemEntityId, modifier: unit::UnitModifier) -> Result<(), GatewayError> { + self.unit_modifiers.lock().unwrap() + .entry(*item_id) + .or_insert_with(Vec::new) + .push(modifier); + Ok(()) + } + async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result { let inventories = self.inventories.lock().unwrap(); Ok(inventories @@ -349,11 +359,4 @@ impl EntityGateway for InMemoryGateway { Err(GatewayError::Error) } } - - async fn increment_kill_counter(&mut self, item_id: &ItemEntityId) -> Result<(), GatewayError> { - if let Some(item_entity) = self.items.lock().unwrap().get_mut(item_id) { - item_entity.item.increment_kill_counter(); - } - Ok(()) - } } diff --git a/src/entity/item/mod.rs b/src/entity/item/mod.rs index dae9f03..c4d326e 100644 --- a/src/entity/item/mod.rs +++ b/src/entity/item/mod.rs @@ -175,27 +175,14 @@ impl ItemDetail { ItemDetail::Weapon(w) => w.kills.is_some(), ItemDetail::Armor(_a) => false, ItemDetail::Shield(_s) => false, - // ItemDetail::Unit(u) => u.kills.is_some(), - ItemDetail::Unit(_u) => false, + ItemDetail::Unit(u) => u.kills.is_some(), + // ItemDetail::Unit(_u) => false, ItemDetail::Tool(_t) => false, ItemDetail::TechniqueDisk(_d) => false, ItemDetail::Mag(_m) => false, ItemDetail::ESWeapon(_e) => false, } } - - pub fn increment_kill_counter(&mut self) { - match self { - ItemDetail::Weapon(w) => {w.increment_kill_counter()}, - ItemDetail::Armor(_a) => {}, - ItemDetail::Shield(_s) => {}, - ItemDetail::Unit(u) => {u.increment_kill_counter()}, - ItemDetail::Tool(_t) => {}, - ItemDetail::TechniqueDisk(_d) => {}, - ItemDetail::Mag(_m) => {}, - ItemDetail::ESWeapon(_e) => {}, - } - } } #[derive(Clone, Debug)] diff --git a/src/entity/item/unit.rs b/src/entity/item/unit.rs index 99ebc17..979fb02 100644 --- a/src/entity/item/unit.rs +++ b/src/entity/item/unit.rs @@ -1,4 +1,6 @@ use serde::{Serialize, Deserialize}; +use crate::ship::monster::MonsterType; + #[derive(Debug, Copy, Clone)] pub enum ItemParseError { @@ -333,6 +335,10 @@ pub enum UnitModifier { Plus, Minus, MinusMinus, + AddKill { + enemy: MonsterType, + // attack: u32, // maybe one day for TURBO logging? + }, } #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] @@ -364,6 +370,7 @@ impl Unit { result[6] = 0xFE; result[7] = 0xFF; }, + _ => {}, } } if self.unit.has_counter() { @@ -472,9 +479,14 @@ impl Unit { } } - pub fn increment_kill_counter(&mut self) { - if let Some(kills) = self.kills { - self.kills = Some(kills + 1); - } + pub fn apply_modifier(&mut self, modifier: &UnitModifier) { + match modifier { + UnitModifier::AddKill{enemy: _} => { + if let Some(kills) = self.kills { + self.kills = Some(kills + 1); + } + }, + _ => {}, + }; } } diff --git a/src/entity/item/weapon.rs b/src/entity/item/weapon.rs index 64f7e88..3f7bc88 100644 --- a/src/entity/item/weapon.rs +++ b/src/entity/item/weapon.rs @@ -1,4 +1,5 @@ use crate::entity::item::ItemEntityId; +use crate::ship::monster::MonsterType; use serde::{Serialize, Deserialize}; #[derive(Debug, Copy, Clone)] @@ -1459,6 +1460,10 @@ pub enum WeaponModifier { percent: TekPercentModifier, grind: i32, }, + AddKill { + enemy: MonsterType, + // attack: u32, // maybe one day for TURBO logging? + }, } #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] @@ -1484,46 +1489,58 @@ impl Weapon { } } + // TODO: apply other modifiers pub fn apply_modifier(&mut self, modifier: &WeaponModifier) { - if let WeaponModifier::Tekked{special, percent, grind} = modifier { - match special { - TekSpecialModifier::Plus => { - self.special = self.special.map(|special| { - special.rank_up() - }); - }, - TekSpecialModifier::Minus => { - self.special = self.special.map(|special| { - special.rank_down() - }); - }, - TekSpecialModifier::Neutral => { - }, - } - for i in 0..3 { - self.attrs[i] = self.attrs[i].map(|mut attr| { - match percent { - TekPercentModifier::PlusPlus => { - attr.value += 10; - }, - TekPercentModifier::Plus => { - attr.value += 5; - }, - TekPercentModifier::MinusMinus => { - attr.value -= 10; - }, - TekPercentModifier::Minus => { - attr.value -= 5; - }, - TekPercentModifier::Neutral => { + match modifier { + WeaponModifier::AddPercents{attr: _, pds: _} => {}, + WeaponModifier::AddGrind{amount: _, grinder: _} => {}, + WeaponModifier::Tekked{special, percent, grind} => { + match special { + TekSpecialModifier::Plus => { + self.special = self.special.map(|special| { + special.rank_up() + }); + }, + TekSpecialModifier::Minus => { + self.special = self.special.map(|special| { + special.rank_down() + }); + }, + TekSpecialModifier::Neutral => { + }, + } + for i in 0..3 { + self.attrs[i] = self.attrs[i].map(|mut attr| { + match percent { + TekPercentModifier::PlusPlus => { + attr.value += 10; + }, + TekPercentModifier::Plus => { + attr.value += 5; + }, + TekPercentModifier::MinusMinus => { + attr.value -= 10; + }, + TekPercentModifier::Minus => { + attr.value -= 5; + }, + TekPercentModifier::Neutral => { + } } - } - attr - }); - } - self.grind = std::cmp::max(self.grind as i32 + grind, 0) as u8; - self.tekked = true; - } + attr + }); + } + self.grind = std::cmp::max(self.grind as i32 + grind, 0) as u8; + self.tekked = true; + }, + WeaponModifier::AddKill{enemy: _} => { + if let Some(kills) = self.kills { + println!("{:?} currently has {:?} kills", self.weapon, self.kills); + self.kills = Some(kills + 1); + println!("now {:?} has {:?} kills", self.weapon, self.kills); + } + }, + }; } pub fn as_bytes(&self) -> [u8; 16] { @@ -1671,10 +1688,4 @@ impl Weapon { | WeaponType::Scepter ) } - - pub fn increment_kill_counter(&mut self) { - if let Some(kills) = self.kills { - self.kills = Some(kills + 1); - } - } } diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 6ffb942..e431b42 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -8,7 +8,8 @@ use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel}; use crate::entity::item::{ItemDetail, ItemNote, BankName}; use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, BankItemEntity, EquippedEntity, ItemEntityId}; use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::weapon; +use crate::entity::item::weapon::{Weapon, WeaponModifier}; +use crate::entity::item::unit::UnitModifier; use crate::ship::map::MapArea; use crate::ship::ship::ItemDropLocation; use crate::ship::trade::TradeItem; @@ -22,6 +23,7 @@ use crate::ship::items::floor::*; use crate::ship::items::inventory::*; use crate::ship::items::use_tool; use crate::ship::items::transaction::{ItemTransaction, ItemAction, TransactionError, TransactionCommitError}; +use crate::ship::monster::MonsterType; #[derive(PartialEq, Eq)] pub enum FloorType { @@ -984,8 +986,8 @@ impl ItemManager { entity_gateway: &mut EG, character: &CharacterEntity, item_id: ClientItemId, - tek: weapon::WeaponModifier) - -> Result { + tek: WeaponModifier) + -> Result { let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; let item = inventory.remove_by_id(item_id) @@ -1194,20 +1196,11 @@ impl ItemManager { .map_err(|err| err.into()) } - pub async fn increase_kill_counters(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, equipped_items: &EquippedEntity) -> Result<(), anyhow::Error> { + pub async fn increase_kill_counters(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, equipped_items: &EquippedEntity, monstertype: MonsterType) -> Result<(), anyhow::Error> { let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; if let Some(weapon_entity) = equipped_items.weapon { - let weapon_id = inventory.get_item_by_entity_id(weapon_entity).ok_or(ItemManagerError::EntityIdNotInInventory(weapon_entity))?.item_id(); - let mut weapon_handle = inventory.get_item_handle_by_id(weapon_id).ok_or(ItemManagerError::NoSuchItemId(weapon_id))?; - let individual_item_w = weapon_handle.item_mut() - .ok_or(ItemManagerError::NoSuchItemId(weapon_id))? - .individual_mut() - .ok_or(ItemManagerError::WrongItemType(weapon_id))?; - let weapon = individual_item_w - .weapon_mut() - .ok_or(ItemManagerError::WrongItemType(weapon_id))?; - - weapon.increment_kill_counter(); + let wmodifier = WeaponModifier::AddKill { enemy: monstertype }; + entity_gateway.add_weapon_modifier(&weapon_entity, wmodifier).await?; } for units in equipped_items.unit.iter().flatten() { let unit_id = inventory.get_item_by_entity_id(*units).ok_or(ItemManagerError::EntityIdNotInInventory(*units))?.item_id(); @@ -1220,7 +1213,9 @@ impl ItemManager { .unit_mut() .ok_or(ItemManagerError::WrongItemType(unit_id))?; - unit.increment_kill_counter(); + let umodifier = UnitModifier::AddKill { enemy: monstertype }; + unit.apply_modifier(&umodifier); + entity_gateway.add_unit_modifier(units, umodifier).await?; } entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; Ok(()) diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 834657f..be437ec 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -399,9 +399,11 @@ where } pub async fn player_killed_monster( id: ClientId, - _pkt: &KillMonster, // use this later for turbo logging? + pkt: &KillMonster, entity_gateway: &mut EG, + client_location: &ClientLocation, clients: &Clients, + rooms: &mut Rooms, item_manager: &mut ItemManager) -> Result + Send>, anyhow::Error> where @@ -409,6 +411,13 @@ where { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; let equipped_items = entity_gateway.get_character_equips(&client.character.id).await?; - item_manager.increase_kill_counters(entity_gateway, &client.character, &equipped_items).await?; - Ok(Box::new(None.into_iter())) + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get_mut(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))? + .as_mut() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let enemy_id = u16::from_le_bytes([pkt.client, pkt.target]) & 0x0FFF; + let monstertype = room.maps.enemy_by_id(enemy_id as usize)?.monster; + item_manager.increase_kill_counters(entity_gateway, &client.character, &equipped_items, monstertype).await?; + Ok(Box::new(None.into_iter())) // TODO: forward to other clients in the room } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index db33110..f2af8be 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -521,7 +521,8 @@ impl ShipServerState { handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await? }, GameMessage::KillMonster(kill_monster) => { - handler::message::player_killed_monster(id, kill_monster, &mut self.entity_gateway, &self.clients, &mut self.item_manager).await? + let block = self.blocks.with_client(id, &self.clients)?; + handler::message::player_killed_monster(id, kill_monster, &mut self.entity_gateway, &block.client_location, &self.clients, &mut block.rooms, &mut self.item_manager).await? }, _ => { let cmsg = msg.clone(); diff --git a/tests/test_unseal_items.rs b/tests/test_unseal_items.rs index c789707..b61c219 100644 --- a/tests/test_unseal_items.rs +++ b/tests/test_unseal_items.rs @@ -1,7 +1,4 @@ /* TODO: -1. test to check if sjs/lame/limiter drop with Some() kill counter enabled -2. test to make sure other items drop with None kill counter -3. test kill counters get incremented per kill 4. test unsealing item: - client item id does not change - unsealed item no longer has kill counter @@ -24,13 +21,13 @@ mod common; use common::*; #[async_std::test] -async fn test_item_drops_with_kill_counter() { +async fn test_sjs_drops_with_kill_counter() { let mut entity_gateway = InMemoryGateway::default(); let (_user1, mut char1) = new_user_character_with_sid(&mut entity_gateway, "a1", "a", SectionID::Skyly).await; char1.exp = 80000000; - entity_gateway.save_character(&char1).await.unwrap(); + entity_gateway.save_character(&char1).await.unwrap(); let mut ship = Box::new(ShipServerState::builder() .gateway(entity_gateway.clone()) @@ -41,7 +38,7 @@ async fn test_item_drops_with_kill_counter() { create_ep2_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; let room = ship.blocks.0[0].rooms[0].as_mut().unwrap(); - room.toggle_redbox_mode(); // enable redbox mode for sjs + room.toggle_redbox_mode(); // enable redbox mode let gigue_id = room.maps.get_enemy_id_by_monster_type(MonsterType::GiGue).unwrap(); @@ -65,6 +62,48 @@ async fn test_item_drops_with_kill_counter() { } } +#[async_std::test] +async fn test_other_weapons_drop_without_kill_counter() { + let mut entity_gateway = InMemoryGateway::default(); + + let (_user1, mut char1) = new_user_character_with_sid(&mut entity_gateway, "a1", "a", SectionID::Skyly).await; + + char1.exp = 80000000; + entity_gateway.save_character(&char1).await.unwrap(); + + let mut ship = Box::new(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_ep2_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await; + + let room = ship.blocks.0[0].rooms[0].as_mut().unwrap(); + room.toggle_redbox_mode(); // enable redbox mode + + let enemy_id = room.maps.get_enemy_id_by_monster_type(MonsterType::Hildebear).unwrap(); + + let packets = ship.handle(ClientId(1), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::RequestItem(RequestItem { + client: 0, + target: 0, + map_area: 1, // temple alpha + pt_index: 0, // TODO: this is going to break if pt_index ever gets properly used + enemy_id: enemy_id, + x: 0.0, + y: 0.0, + z: 0.0, + })))).await.unwrap().collect::>(); + + assert!(packets.len() == 1); + match &packets[0].1 { + SendShipPacket::Message(Message {msg: GameMessage::ItemDrop(item_drop)}) => { + assert_ne!(item_drop.item_bytes[10], 0x80) + } + _ => panic!("Weapon didn't drop with the expected value! attr[2] should be less than 0x80 (128) because it shouldn't have a kill counter!") + } +} + #[async_std::test] async fn test_all_equipped_kill_counters_increase_per_kill() { let mut entity_gateway = InMemoryGateway::default();