actually add and use AddKill modifier and remove dead code
This commit is contained in:
parent
c285d5cadc
commit
2d5b6c5c01
@ -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<Vec<ItemEntity>, 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!();
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ pub struct InMemoryGateway {
|
||||
equips: Arc<Mutex<BTreeMap<CharacterEntityId, EquippedEntity>>>,
|
||||
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
||||
weapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<weapon::WeaponModifier>>>>,
|
||||
unit_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<unit::UnitModifier>>>>,
|
||||
}
|
||||
|
||||
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<InventoryEntity, GatewayError> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<weapon::Weapon, anyhow::Error> {
|
||||
tek: WeaponModifier)
|
||||
-> Result<Weapon, anyhow::Error> {
|
||||
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<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, equipped_items: &EquippedEntity) -> Result<(), anyhow::Error> {
|
||||
pub async fn increase_kill_counters<EG: EntityGateway>(&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(())
|
||||
|
@ -399,9 +399,11 @@ where
|
||||
}
|
||||
|
||||
pub async fn player_killed_monster<EG>( 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<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + 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
|
||||
}
|
||||
|
@ -521,7 +521,8 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
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();
|
||||
|
@ -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::<Vec<_>>();
|
||||
|
||||
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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user