Merge pull request 'tekking!' (#271) from andy_is_unable_to_tek_properly into master
This commit is contained in:
commit
03aa41ef6a
@ -84,7 +84,6 @@ fn main() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -119,8 +118,7 @@ fn main() {
|
||||
attrs: [Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Hit, value: 40}),
|
||||
Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 30}),
|
||||
None,],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
tekked: false,
|
||||
}
|
||||
),
|
||||
location: ItemLocation::Inventory {
|
||||
@ -138,7 +136,6 @@ fn main() {
|
||||
Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 30}),
|
||||
None,],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: ItemLocation::Inventory {
|
||||
@ -156,7 +153,6 @@ fn main() {
|
||||
Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}),
|
||||
None,],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: ItemLocation::Inventory {
|
||||
@ -174,7 +170,6 @@ fn main() {
|
||||
Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}),
|
||||
None,],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: ItemLocation::Inventory {
|
||||
@ -192,7 +187,6 @@ fn main() {
|
||||
Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 100}),
|
||||
Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Native, value: 100}),],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: ItemLocation::Inventory {
|
||||
@ -257,7 +251,6 @@ fn main() {
|
||||
Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 80}),
|
||||
None,],
|
||||
tekked: false,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: ItemLocation::Bank {
|
||||
@ -273,7 +266,6 @@ fn main() {
|
||||
dfp: 0,
|
||||
evp: 0,
|
||||
slots: 4,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: ItemLocation::Inventory {
|
||||
|
@ -65,11 +65,6 @@ pub trait EntityGateway: Send + Sync + Clone {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
async fn change_item(&mut self, _id: &ItemEntityId, _item: &ItemDetail) -> Result<(), GatewayError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
async fn change_item_location(&mut self, _item_id: &ItemEntityId, _item_location: ItemLocation) -> Result<(), GatewayError> {
|
||||
unimplemented!();
|
||||
}
|
||||
@ -86,6 +81,11 @@ pub trait EntityGateway: Send + Sync + Clone {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
async fn add_weapon_modifier(&mut self, _item_id: &ItemEntityId, _modifier: weapon::WeaponModifier) -> Result<(), GatewayError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
async fn get_items_by_character(&self, _char_id: &CharacterEntityId) -> Result<Vec<ItemEntity>, GatewayError> {
|
||||
unimplemented!();
|
||||
|
@ -18,6 +18,7 @@ pub struct InMemoryGateway {
|
||||
banks: Arc<Mutex<BTreeMap<CharacterEntityId, BankEntity>>>,
|
||||
equips: Arc<Mutex<BTreeMap<CharacterEntityId, EquippedEntity>>>,
|
||||
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
||||
weapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<weapon::WeaponModifier>>>>,
|
||||
}
|
||||
|
||||
impl InMemoryGateway {
|
||||
@ -31,6 +32,7 @@ impl InMemoryGateway {
|
||||
banks: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
equips: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -42,9 +44,16 @@ impl InMemoryGateway {
|
||||
.map(|item| {
|
||||
item.map_individual(|mut item| {
|
||||
item.item = match item.item {
|
||||
ItemDetail::Weapon(mut weapon) => {
|
||||
if let Some(weapon_modifiers) = self.weapon_modifiers.lock().unwrap().get(&item.id) {
|
||||
for weapon_modifier in weapon_modifiers.iter() {
|
||||
weapon.apply_modifier(&weapon_modifier);
|
||||
}
|
||||
}
|
||||
ItemDetail::Weapon(weapon)
|
||||
},
|
||||
ItemDetail::Mag(mag) => {
|
||||
let mut mag = mag::Mag::baby_mag(mag.color as u16);
|
||||
println!("mag! {:?}", mag);
|
||||
if let Some(mag_modifiers) = self.mag_modifiers.lock().unwrap().get(&item.id) {
|
||||
for mag_modifier in mag_modifiers.iter() {
|
||||
match mag_modifier {
|
||||
@ -69,7 +78,6 @@ impl InMemoryGateway {
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
println!("{:?} -> {:?}", mag_modifier, mag);
|
||||
}
|
||||
}
|
||||
ItemDetail::Mag(mag)
|
||||
@ -223,15 +231,6 @@ impl EntityGateway for InMemoryGateway {
|
||||
Ok(new_item)
|
||||
}
|
||||
|
||||
async fn change_item(&mut self, id: &ItemEntityId, item: &ItemDetail) -> Result<(), GatewayError> {
|
||||
let mut items = self.items.lock().unwrap();
|
||||
if let Some((_, ref mut old_item)) = items.iter_mut().find(|(existing_id, _)| **existing_id == *id) {
|
||||
old_item.item = item.clone();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn change_item_location(&mut self, item_id: &ItemEntityId, item_location: ItemLocation) -> Result<(), GatewayError> {
|
||||
self.items.lock().unwrap().get_mut(&item_id)
|
||||
.map(|item_entity| {
|
||||
@ -266,6 +265,14 @@ impl EntityGateway for InMemoryGateway {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> {
|
||||
self.weapon_modifiers.lock().unwrap()
|
||||
.entry(*item_id)
|
||||
.or_insert(Vec::new())
|
||||
.push(modifier);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result<InventoryEntity, GatewayError> {
|
||||
println!("getting inv");
|
||||
let inventories = self.inventories.lock().unwrap();
|
||||
|
@ -316,11 +316,16 @@ impl Into<weapon::Weapon> for PgWeapon {
|
||||
grind: self.grind,
|
||||
attrs: attrs,
|
||||
tekked: self.tekked,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
pub struct PgWeaponModifier {
|
||||
pub weapon: i32,
|
||||
pub modifier: sqlx::types::Json<weapon::WeaponModifier>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct PgArmor {
|
||||
armor: armor::ArmorType,
|
||||
@ -347,7 +352,6 @@ impl Into<armor::Armor> for PgArmor {
|
||||
dfp: self.dfp,
|
||||
evp: self.evp,
|
||||
slots: self.slots,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,23 @@ impl PostgresGateway {
|
||||
let ItemEntity {id, item, location} = item;
|
||||
|
||||
let item = match item {
|
||||
ItemDetail::Weapon(mut weapon) => {
|
||||
let q = r#"select weapon, modifier
|
||||
from weapon_modifier
|
||||
where weapon = $1
|
||||
order by created_at"#;
|
||||
let weapon_modifiers = sqlx::query_as::<_, PgWeaponModifier>(q)
|
||||
.bind(id.0 as i32)
|
||||
.fetch(&self.pool);
|
||||
|
||||
weapon_modifiers.for_each(|modifier| {
|
||||
if let Ok(modifier) = modifier {
|
||||
weapon.apply_modifier(&modifier.modifier);
|
||||
}
|
||||
}).await;
|
||||
|
||||
ItemDetail::Weapon(weapon)
|
||||
},
|
||||
ItemDetail::Mag(mut mag) => {
|
||||
let q = r#"select mag, modifier, item.item -> 'Tool' as feed, item2.item -> 'Tool' as cell
|
||||
from mag_modifier
|
||||
@ -331,14 +348,6 @@ impl EntityGateway for PostgresGateway {
|
||||
*/
|
||||
}
|
||||
|
||||
async fn change_item(&mut self, id: &ItemEntityId, item: &ItemDetail) -> Result<(), GatewayError> {
|
||||
sqlx::query("update item set item = $1 where id = $2")
|
||||
.bind(sqlx::types::Json(PgItemDetail::from(item.clone())))
|
||||
.bind(id.0)
|
||||
.execute(&self.pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn change_item_location(&mut self, item_id: &ItemEntityId, item_location: ItemLocation) -> Result<(), GatewayError> {
|
||||
sqlx::query("insert into item_location (item, location) values ($1, $2)")
|
||||
.bind(item_id.0)
|
||||
@ -398,6 +407,15 @@ impl EntityGateway for PostgresGateway {
|
||||
.execute(&self.pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_weapon_modifier(&mut self, item_id: &ItemEntityId, modifier: weapon::WeaponModifier) -> Result<(), GatewayError> {
|
||||
sqlx::query("insert into weapon_modifier (weapon, modifier) values ($1, $2);")
|
||||
.bind(item_id.0)
|
||||
.bind(sqlx::types::Json(modifier))
|
||||
.execute(&self.pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
async fn get_items_by_character(&self, char_id: &CharacterEntityId) -> Result<Vec<ItemEntity>, GatewayError> {
|
||||
let q = r#"select * from (
|
||||
|
@ -303,7 +303,6 @@ pub struct Armor {
|
||||
pub dfp: u8,
|
||||
pub evp: u8,
|
||||
pub slots: u8,
|
||||
pub modifiers: Vec<ArmorModifier>
|
||||
}
|
||||
|
||||
impl Armor {
|
||||
@ -324,7 +323,6 @@ impl Armor {
|
||||
dfp: data[6],
|
||||
evp: data[8],
|
||||
slots: data[5],
|
||||
modifiers: Vec::new(),
|
||||
})
|
||||
}
|
||||
else {
|
||||
|
@ -93,6 +93,95 @@ impl WeaponSpecial {
|
||||
pub fn value(&self) -> u8 {
|
||||
*self as u8
|
||||
}
|
||||
pub fn rank_up(&self) -> WeaponSpecial {
|
||||
match self {
|
||||
WeaponSpecial::Draw => WeaponSpecial::Drain,
|
||||
WeaponSpecial::Drain => WeaponSpecial::Fill,
|
||||
WeaponSpecial::Fill => WeaponSpecial::Gush,
|
||||
WeaponSpecial::Gush => WeaponSpecial::Gush,
|
||||
WeaponSpecial::Heart => WeaponSpecial::Mind,
|
||||
WeaponSpecial::Mind => WeaponSpecial::Soul,
|
||||
WeaponSpecial::Soul => WeaponSpecial::Geist,
|
||||
WeaponSpecial::Geist => WeaponSpecial::Geist,
|
||||
WeaponSpecial::Masters => WeaponSpecial::Lords,
|
||||
WeaponSpecial::Lords => WeaponSpecial::Kings,
|
||||
WeaponSpecial::Kings => WeaponSpecial::Kings,
|
||||
WeaponSpecial::Charge => WeaponSpecial::Charge,
|
||||
WeaponSpecial::Spirit => WeaponSpecial::Spirit,
|
||||
WeaponSpecial::Berserk => WeaponSpecial::Berserk,
|
||||
WeaponSpecial::Ice => WeaponSpecial::Frost,
|
||||
WeaponSpecial::Frost => WeaponSpecial::Freeze,
|
||||
WeaponSpecial::Freeze => WeaponSpecial::Blizzard,
|
||||
WeaponSpecial::Blizzard => WeaponSpecial::Blizzard,
|
||||
WeaponSpecial::Bind => WeaponSpecial::Hold,
|
||||
WeaponSpecial::Hold => WeaponSpecial::Seize,
|
||||
WeaponSpecial::Seize => WeaponSpecial::Arrest,
|
||||
WeaponSpecial::Arrest => WeaponSpecial::Arrest,
|
||||
WeaponSpecial::Heat => WeaponSpecial::Fire,
|
||||
WeaponSpecial::Fire => WeaponSpecial::Flame,
|
||||
WeaponSpecial::Flame => WeaponSpecial::Burning,
|
||||
WeaponSpecial::Burning => WeaponSpecial::Burning,
|
||||
WeaponSpecial::Shock => WeaponSpecial::Thunder,
|
||||
WeaponSpecial::Thunder => WeaponSpecial::Storm,
|
||||
WeaponSpecial::Storm => WeaponSpecial::Tempest,
|
||||
WeaponSpecial::Tempest => WeaponSpecial::Tempest,
|
||||
WeaponSpecial::Dim => WeaponSpecial::Shadow,
|
||||
WeaponSpecial::Shadow => WeaponSpecial::Dark,
|
||||
WeaponSpecial::Dark => WeaponSpecial::Hell,
|
||||
WeaponSpecial::Hell => WeaponSpecial::Hell,
|
||||
WeaponSpecial::Panic => WeaponSpecial::Riot,
|
||||
WeaponSpecial::Riot => WeaponSpecial::Havoc,
|
||||
WeaponSpecial::Havoc => WeaponSpecial::Chaos,
|
||||
WeaponSpecial::Chaos => WeaponSpecial::Chaos,
|
||||
WeaponSpecial::Devils => WeaponSpecial::Demons,
|
||||
WeaponSpecial::Demons => WeaponSpecial::Demons,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rank_down(&self) -> WeaponSpecial {
|
||||
match self {
|
||||
WeaponSpecial::Draw => WeaponSpecial::Draw,
|
||||
WeaponSpecial::Drain => WeaponSpecial::Draw,
|
||||
WeaponSpecial::Fill => WeaponSpecial::Drain,
|
||||
WeaponSpecial::Gush => WeaponSpecial::Fill,
|
||||
WeaponSpecial::Heart => WeaponSpecial::Heart,
|
||||
WeaponSpecial::Mind => WeaponSpecial::Heart,
|
||||
WeaponSpecial::Soul => WeaponSpecial::Mind,
|
||||
WeaponSpecial::Geist => WeaponSpecial::Soul,
|
||||
WeaponSpecial::Masters => WeaponSpecial::Masters,
|
||||
WeaponSpecial::Lords => WeaponSpecial::Masters,
|
||||
WeaponSpecial::Kings => WeaponSpecial::Lords,
|
||||
WeaponSpecial::Charge => WeaponSpecial::Charge,
|
||||
WeaponSpecial::Spirit => WeaponSpecial::Spirit,
|
||||
WeaponSpecial::Berserk => WeaponSpecial::Berserk,
|
||||
WeaponSpecial::Ice => WeaponSpecial::Ice,
|
||||
WeaponSpecial::Frost => WeaponSpecial::Ice,
|
||||
WeaponSpecial::Freeze => WeaponSpecial::Frost,
|
||||
WeaponSpecial::Blizzard => WeaponSpecial::Freeze,
|
||||
WeaponSpecial::Bind => WeaponSpecial::Bind,
|
||||
WeaponSpecial::Hold => WeaponSpecial::Bind,
|
||||
WeaponSpecial::Seize => WeaponSpecial::Hold,
|
||||
WeaponSpecial::Arrest => WeaponSpecial::Seize,
|
||||
WeaponSpecial::Heat => WeaponSpecial::Heat,
|
||||
WeaponSpecial::Fire => WeaponSpecial::Heat,
|
||||
WeaponSpecial::Flame => WeaponSpecial::Fire,
|
||||
WeaponSpecial::Burning => WeaponSpecial::Flame,
|
||||
WeaponSpecial::Shock => WeaponSpecial::Shock,
|
||||
WeaponSpecial::Thunder => WeaponSpecial::Shock,
|
||||
WeaponSpecial::Storm => WeaponSpecial::Thunder,
|
||||
WeaponSpecial::Tempest => WeaponSpecial::Storm,
|
||||
WeaponSpecial::Dim => WeaponSpecial::Dim,
|
||||
WeaponSpecial::Shadow => WeaponSpecial::Dim,
|
||||
WeaponSpecial::Dark => WeaponSpecial::Shadow,
|
||||
WeaponSpecial::Hell => WeaponSpecial::Dark,
|
||||
WeaponSpecial::Panic => WeaponSpecial::Panic,
|
||||
WeaponSpecial::Riot => WeaponSpecial::Panic,
|
||||
WeaponSpecial::Havoc => WeaponSpecial::Riot,
|
||||
WeaponSpecial::Chaos => WeaponSpecial::Havoc,
|
||||
WeaponSpecial::Devils => WeaponSpecial::Devils,
|
||||
WeaponSpecial::Demons => WeaponSpecial::Devils,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from(data: u8) -> Option<WeaponSpecial> {
|
||||
match data {
|
||||
@ -1360,7 +1449,8 @@ pub enum WeaponModifier {
|
||||
},
|
||||
Tekked {
|
||||
special: TekSpecialModifier,
|
||||
percents: TekPercentModifier,
|
||||
percent: TekPercentModifier,
|
||||
grind: i32,
|
||||
},
|
||||
}
|
||||
|
||||
@ -1371,7 +1461,6 @@ pub struct Weapon {
|
||||
pub grind: u8,
|
||||
pub attrs: [Option<WeaponAttribute>; 3],
|
||||
pub tekked: bool,
|
||||
pub modifiers: Vec<WeaponModifier>
|
||||
}
|
||||
|
||||
|
||||
@ -1383,7 +1472,51 @@ impl Weapon {
|
||||
grind: 0,
|
||||
attrs: [None; 3],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_modifier(&mut self, modifier: &WeaponModifier) {
|
||||
match modifier {
|
||||
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;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1452,7 +1585,6 @@ impl Weapon {
|
||||
a[2],
|
||||
],
|
||||
tekked: t,
|
||||
modifiers: Vec::new(),
|
||||
})
|
||||
}
|
||||
else {
|
||||
|
@ -220,7 +220,6 @@ async fn new_character<EG: EntityGateway>(entity_gateway: &mut EG, user: &UserAc
|
||||
special: None,
|
||||
attrs: [None; 3],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}),
|
||||
location: ItemLocation::Inventory {
|
||||
character_id: character.id,
|
||||
@ -234,7 +233,6 @@ async fn new_character<EG: EntityGateway>(entity_gateway: &mut EG, user: &UserAc
|
||||
dfp: 0,
|
||||
evp: 0,
|
||||
slots: 0,
|
||||
modifiers: Vec::new(),
|
||||
}),
|
||||
location: ItemLocation::Inventory {
|
||||
character_id: character.id,
|
||||
|
@ -107,7 +107,6 @@ impl GenericArmorTable {
|
||||
dfp: dfp_modifier as u8,
|
||||
evp: evp_modifier as u8,
|
||||
slots: slots as u8,
|
||||
modifiers: Vec::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@ -127,28 +126,24 @@ mod test {
|
||||
dfp: 0,
|
||||
evp: 0,
|
||||
slots: 1,
|
||||
modifiers: Vec::new(),
|
||||
})));
|
||||
assert!(gat.get_drop(&MapArea::Caves3, &mut rng) == Some(ItemDropType::Armor(Armor {
|
||||
armor: ArmorType::AbsorbArmor,
|
||||
dfp: 1,
|
||||
evp: 1,
|
||||
slots: 1,
|
||||
modifiers: Vec::new(),
|
||||
})));
|
||||
assert!(gat.get_drop(&MapArea::Forest2, &mut rng) == Some(ItemDropType::Armor(Armor {
|
||||
armor: ArmorType::HyperFrame,
|
||||
dfp: 0,
|
||||
evp: 0,
|
||||
slots: 0,
|
||||
modifiers: Vec::new(),
|
||||
})));
|
||||
assert!(gat.get_drop(&MapArea::DarkFalz, &mut rng) == Some(ItemDropType::Armor(Armor {
|
||||
armor: ArmorType::ImperialArmor,
|
||||
dfp: 2,
|
||||
evp: 1,
|
||||
slots: 0,
|
||||
modifiers: Vec::new(),
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
@ -503,7 +503,6 @@ impl GenericWeaponTable {
|
||||
grind: weapon_grind as u8,
|
||||
attrs: weapon_attributes,
|
||||
tekked: weapon_special.is_none(),
|
||||
modifiers: Vec::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@ -525,7 +524,6 @@ mod test {
|
||||
grind: 0,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
})));
|
||||
|
||||
let gwt = GenericWeaponTable::new(Episode::One, Difficulty::Hard, SectionID::Skyly);
|
||||
@ -535,7 +533,6 @@ mod test {
|
||||
grind: 2,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
})));
|
||||
|
||||
let gwt = GenericWeaponTable::new(Episode::One, Difficulty::VeryHard, SectionID::Skyly);
|
||||
@ -545,7 +542,6 @@ mod test {
|
||||
grind: 0,
|
||||
attrs: [None, None, None],
|
||||
tekked: false,
|
||||
modifiers: Vec::new(),
|
||||
})));
|
||||
|
||||
let gwt = GenericWeaponTable::new(Episode::One, Difficulty::Ultimate, SectionID::Skyly);
|
||||
@ -555,7 +551,6 @@ mod test {
|
||||
grind: 0,
|
||||
attrs: [Some(WeaponAttribute {attr: Attribute::ABeast, value: 30}), Some(WeaponAttribute {attr: Attribute::Dark, value: 30}), None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,6 @@ impl RareDropTable {
|
||||
grind: 0,
|
||||
attrs: self.attribute_table.generate_rare_attributes(map_area, rng),
|
||||
tekked: false,
|
||||
modifiers: Vec::new(),
|
||||
})
|
||||
|
||||
},
|
||||
@ -114,7 +113,6 @@ impl RareDropTable {
|
||||
dfp: self.armor_stats.dfp_modifier(&armor, rng) as u8,
|
||||
evp: self.armor_stats.evp_modifier(&armor, rng) as u8,
|
||||
slots: self.armor_stats.slots(map_area, rng) as u8,
|
||||
modifiers: Vec::new(),
|
||||
})
|
||||
},
|
||||
RareDropItem::Shield(shield) => {
|
||||
|
@ -5,6 +5,7 @@ use crate::entity::character::CharacterEntityId;
|
||||
use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, ItemType, ItemLocation, InventoryEntity, InventoryItemEntity, EquippedEntity};
|
||||
use crate::entity::item::tool::Tool;
|
||||
use crate::entity::item::mag::Mag;
|
||||
use crate::entity::item::weapon::Weapon;
|
||||
use crate::ship::items::{ClientItemId, BankItem, BankItemHandle};
|
||||
use crate::ship::items::floor::{IndividualFloorItem, StackedFloorItem};
|
||||
|
||||
@ -30,6 +31,13 @@ impl IndividualInventoryItem {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn weapon(&self) -> Option<&Weapon> {
|
||||
match self.item {
|
||||
ItemDetail::Weapon(ref weapon) => Some(weapon),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mag_mut(&mut self) -> Option<&mut Mag> {
|
||||
match self.item {
|
||||
ItemDetail::Mag(ref mut mag) => Some(mag),
|
||||
@ -198,7 +206,14 @@ impl InventoryItem {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn individual(&mut self) -> Option<&mut IndividualInventoryItem> {
|
||||
pub fn individual(&self) -> Option<&IndividualInventoryItem> {
|
||||
match self {
|
||||
InventoryItem::Individual(ref individual_inventory_item) => Some(individual_inventory_item),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn individual_mut(&mut self) -> Option<&mut IndividualInventoryItem> {
|
||||
match self {
|
||||
InventoryItem::Individual(ref mut individual_inventory_item) => Some(individual_inventory_item),
|
||||
_ => None
|
||||
@ -640,6 +655,14 @@ impl CharacterInventory {
|
||||
self.items = sorted_items;
|
||||
}
|
||||
|
||||
pub fn remove_by_id(&mut self, id: ClientItemId) -> Option<InventoryItem> {
|
||||
self.items.iter()
|
||||
.position(|i| i.item_id() == id)
|
||||
.map(|position| {
|
||||
self.items.remove(position)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn equip(&mut self, id: &ClientItemId, equip_slot: u8) {
|
||||
for item in &self.items {
|
||||
if let InventoryItem::Individual(inventory_item) = item {
|
||||
|
@ -7,6 +7,7 @@ use crate::entity::item::{ItemDetail, ItemLocation, BankName};
|
||||
use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, EquippedEntity, InventoryEntity, BankItemEntity, BankEntity};
|
||||
use crate::entity::item::tool::{Tool, ToolType};
|
||||
use crate::entity::item::unit;
|
||||
use crate::entity::item::weapon;
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::ship::ItemDropLocation;
|
||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||
@ -611,7 +612,7 @@ impl ItemManager {
|
||||
|
||||
let individual_item = mag_handle.item_mut()
|
||||
.ok_or(ItemManagerError::NoSuchItemId(mag_id))?
|
||||
.individual()
|
||||
.individual_mut()
|
||||
.ok_or(ItemManagerError::WrongItemType(mag_id))?;
|
||||
let mag = individual_item
|
||||
.mag_mut()
|
||||
@ -888,4 +889,38 @@ impl ItemManager {
|
||||
entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn replace_item_with_tekked<EG: EntityGateway>(&mut self,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: ClientItemId,
|
||||
tek: weapon::WeaponModifier)
|
||||
-> Result<weapon::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)
|
||||
.ok_or(ItemManagerError::NoSuchItemId(item_id))?;
|
||||
let individual = item
|
||||
.individual()
|
||||
.ok_or(ItemManagerError::WrongItemType(item_id))?;
|
||||
|
||||
let entity_id = individual.entity_id;
|
||||
let mut weapon = individual
|
||||
.weapon()
|
||||
.ok_or(ItemManagerError::WrongItemType(item_id))?
|
||||
.clone();
|
||||
|
||||
weapon.apply_modifier(&tek);
|
||||
entity_gateway.add_weapon_modifier(&entity_id, tek).await?;
|
||||
|
||||
inventory.add_item(InventoryItem::Individual(IndividualInventoryItem {
|
||||
entity_id: entity_id,
|
||||
item_id: item_id,
|
||||
item: ItemDetail::Weapon(weapon.clone()),
|
||||
}));
|
||||
|
||||
entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
|
||||
|
||||
Ok(weapon)
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ async fn mag_cell<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &Consum
|
||||
let mag_item = mag_handle.item_mut()
|
||||
.ok_or(UseItemError::InvalidItem)?;
|
||||
let actual_mag = mag_item
|
||||
.individual()
|
||||
.individual_mut()
|
||||
.ok_or(UseItemError::InvalidItem)?
|
||||
.mag_mut()
|
||||
.ok_or(UseItemError::InvalidItem)?;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use libpso::packet::messages::*;
|
||||
use libpso::packet::ship::*;
|
||||
use crate::entity::item;
|
||||
use crate::common::leveltable::CharacterStats;
|
||||
use crate::ship::ship::{ShipError};
|
||||
use crate::ship::items::{ClientItemId, InventoryItem, StackedFloorItem, FloorItem, CharacterBank};
|
||||
@ -26,13 +27,13 @@ pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDr
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_item(area_client: AreaClient, item: &FloorItem) -> Result<CreateItem, ShipError> {
|
||||
pub fn create_item(area_client: AreaClient, item_id: ClientItemId, item: &item::ItemDetail) -> Result<CreateItem, ShipError> {
|
||||
let bytes = item.as_client_bytes();
|
||||
Ok(CreateItem {
|
||||
client: area_client.local_client.id(),
|
||||
target: 0,
|
||||
item_data: bytes[0..12].try_into()?,
|
||||
item_id: item.item_id().0,
|
||||
item_id: item_id.0,
|
||||
item_data2: bytes[12..16].try_into()?,
|
||||
unknown: 0,
|
||||
})
|
||||
@ -162,3 +163,14 @@ pub fn shop_list<I: ShopItem>(shop_type: u8, items: &Vec<I>) -> ShopList {
|
||||
items: items,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tek_preview(id: ClientItemId, weapon: &item::weapon::Weapon) -> Result<TekPreview, ShipError> {
|
||||
let bytes = weapon.as_bytes();
|
||||
Ok(TekPreview {
|
||||
client: 0x79,
|
||||
target: 0,
|
||||
item_bytes: bytes[0..12].try_into()?,
|
||||
item_id: id.0,
|
||||
item_bytes2: bytes[12..16].try_into()?,
|
||||
})
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
use log::warn;
|
||||
use rand::Rng;
|
||||
use rand::seq::SliceRandom;
|
||||
use libpso::packet::ship::*;
|
||||
use libpso::packet::messages::*;
|
||||
use crate::common::leveltable::CharacterLevelTable;
|
||||
@ -6,8 +8,9 @@ use crate::common::serverstate::ClientId;
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops};
|
||||
use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||
use crate::ship::drops::ItemDrop;
|
||||
use crate::ship::items::{ItemManager, ClientItemId, TriggerCreateItem, FloorItem, FloorType};
|
||||
use crate::ship::items::{ItemManager, ItemManagerError, ClientItemId, TriggerCreateItem, FloorItem, FloorType};
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use crate::entity::item;
|
||||
use libpso::utf8_to_utf16_array;
|
||||
use crate::ship::packet::builder;
|
||||
use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem};
|
||||
@ -24,6 +27,13 @@ const BANK_MESETA_CAPACITY: u32 = 999999;
|
||||
|
||||
//const BANK_ACTION_: u8 = 1;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("")]
|
||||
pub enum MessageError {
|
||||
InvalidTek(ClientItemId),
|
||||
MismatchedTekIds(ClientItemId, ClientItemId),
|
||||
}
|
||||
|
||||
fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation)
|
||||
-> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
|
||||
Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter()
|
||||
@ -127,8 +137,10 @@ where
|
||||
let (item, floor_type) = item_manager.get_floor_item_by_id(&client.character, ClientItemId(pickup_item.item_id))?;
|
||||
let remove_item = builder::message::remove_item_from_floor(area_client, &item)?;
|
||||
let create_item = match item {
|
||||
FloorItem::Individual(individual_floor_item) => Some(builder::message::create_item(area_client, item.item_id(), &individual_floor_item.item)?),
|
||||
FloorItem::Stacked(stacked_floor_item) => Some(builder::message::create_item(area_client, item.item_id(), &item::ItemDetail::Tool(stacked_floor_item.tool))?),
|
||||
FloorItem::Meseta(_) => None,
|
||||
_ => Some(builder::message::create_item(area_client, &item)?),
|
||||
//_ => Some(builder::message::create_item(area_client, &item)?),
|
||||
};
|
||||
|
||||
match item_manager.character_picks_up_item(entity_gateway, &mut client.character, ClientItemId(pickup_item.item_id)).await {
|
||||
@ -393,3 +405,96 @@ where
|
||||
})))
|
||||
|
||||
}
|
||||
|
||||
|
||||
const TEK_SPECIAL_MODIFIER: [item::weapon::TekSpecialModifier; 3] = [item::weapon::TekSpecialModifier::Plus,
|
||||
item::weapon::TekSpecialModifier::Neutral,
|
||||
item::weapon::TekSpecialModifier::Minus];
|
||||
const TEK_PERCENT_MODIFIER: [item::weapon::TekPercentModifier; 5] = [item::weapon::TekPercentModifier::PlusPlus,
|
||||
item::weapon::TekPercentModifier::Plus,
|
||||
item::weapon::TekPercentModifier::Neutral,
|
||||
item::weapon::TekPercentModifier::Minus,
|
||||
item::weapon::TekPercentModifier::MinusMinus];
|
||||
|
||||
pub async fn request_tek_item<EG>(id: ClientId,
|
||||
tek_request: &TekRequest,
|
||||
entity_gateway: &mut EG,
|
||||
clients: &mut Clients,
|
||||
item_manager: &mut ItemManager)
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
|
||||
where
|
||||
EG: EntityGateway
|
||||
{
|
||||
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
|
||||
let (grind_mod, special_mod, percent_mod) = {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let grind_mod = rng.gen_range(-4, 4);
|
||||
let special_mod = TEK_SPECIAL_MODIFIER.choose(&mut rng).cloned().unwrap();
|
||||
let percent_mod = TEK_PERCENT_MODIFIER.choose(&mut rng).cloned().unwrap();
|
||||
(grind_mod, special_mod, percent_mod)
|
||||
};
|
||||
|
||||
client.tek = Some((ClientItemId(tek_request.item_id), special_mod, percent_mod, grind_mod));
|
||||
|
||||
let inventory = item_manager.get_character_inventory(&client.character)?;
|
||||
let item = inventory.get_item_by_id(ClientItemId(tek_request.item_id))
|
||||
.ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))?;
|
||||
let mut weapon = item.individual()
|
||||
.ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))?
|
||||
.weapon()
|
||||
.ok_or(ItemManagerError::WrongItemType(ClientItemId(tek_request.item_id)))?
|
||||
.clone();
|
||||
|
||||
weapon.apply_modifier(&item::weapon::WeaponModifier::Tekked {
|
||||
special: special_mod,
|
||||
percent: percent_mod,
|
||||
grind: grind_mod,
|
||||
});
|
||||
|
||||
client.character.meseta -= 100;
|
||||
entity_gateway.save_character(&client.character).await?;
|
||||
|
||||
let preview_pkt = builder::message::tek_preview(ClientItemId(tek_request.item_id), &weapon)?;
|
||||
|
||||
Ok(Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::TekPreview(preview_pkt))))].into_iter()))
|
||||
}
|
||||
|
||||
pub async fn accept_tek_item<EG>(id: ClientId,
|
||||
tek_accept: &TekAccept,
|
||||
entity_gateway: &mut EG,
|
||||
client_location: &ClientLocation,
|
||||
clients: &mut Clients,
|
||||
item_manager: &mut ItemManager)
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
|
||||
where
|
||||
EG: EntityGateway
|
||||
{
|
||||
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
|
||||
if let Some((item_id, special_mod, percent_mod, grind_mod)) = client.tek {
|
||||
if item_id.0 != tek_accept.item_id {
|
||||
return Err(MessageError::MismatchedTekIds(item_id, ClientItemId(tek_accept.item_id)).into());
|
||||
}
|
||||
|
||||
let modifier = item::weapon::WeaponModifier::Tekked {
|
||||
special: special_mod,
|
||||
percent: percent_mod,
|
||||
grind: grind_mod,
|
||||
};
|
||||
let weapon = item_manager.replace_item_with_tekked(entity_gateway, &client.character, item_id, modifier).await?;
|
||||
|
||||
let create_item_pkt = builder::message::create_item(area_client, item_id, &item::ItemDetail::Weapon(weapon))?;
|
||||
|
||||
let neighbors = client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
Ok(Box::new(neighbors.into_iter()
|
||||
.map(move |c| {
|
||||
(c.client, SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item_pkt.clone()))))
|
||||
})))
|
||||
}
|
||||
else {
|
||||
Err(MessageError::InvalidTek(ClientItemId(tek_accept.item_id)).into())
|
||||
}
|
||||
}
|
||||
|
@ -114,48 +114,59 @@ pub fn drop_coordinates(id: ClientId,
|
||||
Ok(Box::new(None.into_iter()))
|
||||
}
|
||||
|
||||
pub async fn split_item_stack<EG>(id: ClientId,
|
||||
no_longer_has_item: &PlayerNoLongerHasItem,
|
||||
entity_gateway: &mut EG,
|
||||
client_location: &ClientLocation,
|
||||
clients: &mut Clients,
|
||||
item_manager: &mut ItemManager)
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
|
||||
pub async fn no_longer_has_item<EG>(id: ClientId,
|
||||
no_longer_has_item: &PlayerNoLongerHasItem,
|
||||
entity_gateway: &mut EG,
|
||||
client_location: &ClientLocation,
|
||||
clients: &mut Clients,
|
||||
item_manager: &mut ItemManager)
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
|
||||
where
|
||||
EG: EntityGateway
|
||||
{
|
||||
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let drop_location = client.item_drop_location.ok_or(ShipError::ItemDropLocationNotSet)?;
|
||||
if let Some(drop_location) = client.item_drop_location {
|
||||
if drop_location.item_id.0 != no_longer_has_item.item_id {
|
||||
return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id).into());
|
||||
}
|
||||
|
||||
if drop_location.item_id.0 != no_longer_has_item.item_id {
|
||||
return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id).into());
|
||||
if no_longer_has_item.item_id == 0xFFFFFFFF {
|
||||
let dropped_meseta = item_manager.player_drops_meseta_on_shared_floor(entity_gateway, &mut client.character, drop_location, no_longer_has_item.amount as u32).await?;
|
||||
|
||||
let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?;
|
||||
client.item_drop_location = None;
|
||||
|
||||
let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
Ok(Box::new(clients_in_area.into_iter()
|
||||
.map(move |c| {
|
||||
(c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_meseta_pkt.clone()))))
|
||||
})))
|
||||
}
|
||||
else {
|
||||
let dropped_item = item_manager.player_drops_partial_stack_on_shared_floor(entity_gateway, &client.character, drop_location.item_id, drop_location, no_longer_has_item.amount as usize).await?;
|
||||
|
||||
let dropped_item_pkt = builder::message::drop_split_stack(area_client, dropped_item)?;
|
||||
client.item_drop_location = None;
|
||||
|
||||
let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
Ok(Box::new(clients_in_area.into_iter()
|
||||
.map(move |c| {
|
||||
(c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_item_pkt.clone()))))
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
if no_longer_has_item.item_id == 0xFFFFFFFF {
|
||||
let dropped_meseta = item_manager.player_drops_meseta_on_shared_floor(entity_gateway, &mut client.character, drop_location, no_longer_has_item.amount as u32).await?;
|
||||
|
||||
let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta)?;
|
||||
client.item_drop_location = None;
|
||||
|
||||
let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
Ok(Box::new(clients_in_area.into_iter()
|
||||
else if let Some(_tek) = client.tek {
|
||||
let neighbors = client_location.get_client_neighbors(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let no_longer_has_item = no_longer_has_item.clone();
|
||||
Ok(Box::new(neighbors.into_iter()
|
||||
.map(move |c| {
|
||||
(c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_meseta_pkt.clone()))))
|
||||
(c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(no_longer_has_item.clone()))))
|
||||
})))
|
||||
}
|
||||
else {
|
||||
let dropped_item = item_manager.player_drops_partial_stack_on_shared_floor(entity_gateway, &client.character, drop_location.item_id, drop_location, no_longer_has_item.amount as usize).await?;
|
||||
|
||||
let dropped_item_pkt = builder::message::drop_split_stack(area_client, dropped_item)?;
|
||||
client.item_drop_location = None;
|
||||
|
||||
let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
Ok(Box::new(clients_in_area.into_iter()
|
||||
.map(move |c| {
|
||||
(c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_item_pkt.clone()))))
|
||||
})))
|
||||
Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id)).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ use crate::login::character::SHIP_MENU_ID;
|
||||
use crate::entity::gateway::{EntityGateway, GatewayError};
|
||||
use crate::entity::account::{UserAccountEntity, UserSettingsEntity};
|
||||
use crate::entity::character::{CharacterEntity, SectionID};
|
||||
use crate::entity::item;
|
||||
|
||||
use crate::ship::location::{ClientLocation, RoomLobby, MAX_ROOMS, ClientLocationError, GetNeighborError, GetClientsError, GetAreaError};
|
||||
|
||||
@ -71,6 +72,7 @@ pub enum ShipError {
|
||||
UnknownMonster(crate::ship::monster::MonsterType),
|
||||
InvalidShip(usize),
|
||||
InvalidBlock(usize),
|
||||
InvalidItem(items::ClientItemId),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -254,6 +256,7 @@ pub struct ClientState {
|
||||
pub weapon_shop: Vec<WeaponShopItem>,
|
||||
pub tool_shop: Vec<ToolShopItem>,
|
||||
pub armor_shop: Vec<ArmorShopItem>,
|
||||
pub tek: Option<(items::ClientItemId, item::weapon::TekSpecialModifier, item::weapon::TekPercentModifier, i32)>,
|
||||
}
|
||||
|
||||
impl ClientState {
|
||||
@ -273,6 +276,7 @@ impl ClientState {
|
||||
weapon_shop: Vec::new(),
|
||||
tool_shop: Vec::new(),
|
||||
armor_shop: Vec::new(),
|
||||
tek: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,7 +449,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
},
|
||||
GameMessage::PlayerNoLongerHasItem(no_longer_has_item) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::message::split_item_stack(id, no_longer_has_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||
handler::message::no_longer_has_item(id, no_longer_has_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||
},
|
||||
GameMessage::PlayerChangedMap(_) | GameMessage::PlayerChangedMap2(_) | GameMessage::TellOtherPlayerMyLocation(_) |
|
||||
GameMessage::PlayerWarpingToFloor(_) | GameMessage::PlayerTeleported(_) | GameMessage::PlayerStopped(_) |
|
||||
@ -490,41 +494,40 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
|
||||
async fn direct_message(&mut self, id: ClientId, msg: &DirectMessage) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error> {
|
||||
let target = msg.flag;
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
Ok(match &msg.msg {
|
||||
GameMessage::GuildcardSend(guildcard_send) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients)
|
||||
},
|
||||
GameMessage::RequestItem(request_item) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await?
|
||||
},
|
||||
GameMessage::PickupItem(pickup_item) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||
},
|
||||
GameMessage::BoxDropRequest(box_drop_request) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &mut block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await?
|
||||
},
|
||||
GameMessage::BankRequest(_bank_request) => {
|
||||
handler::direct_message::send_bank_list(id, &self.clients, &mut self.item_manager).await?
|
||||
},
|
||||
GameMessage::BankInteraction(bank_interaction) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::direct_message::bank_interaction(id, bank_interaction, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||
},
|
||||
GameMessage::ShopRequest(shop_request) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::direct_message::shop_request(id, shop_request, &block.client_location, &mut self.clients, &block.rooms, &self.level_table, &mut self.shops).await?
|
||||
},
|
||||
GameMessage::BuyItem(buy_item) => {
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||
},
|
||||
GameMessage::TekRequest(tek_request) => {
|
||||
handler::direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await?
|
||||
},
|
||||
GameMessage::TekAccept(tek_accept) => {
|
||||
handler::direct_message::accept_tek_item(id, tek_accept, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
|
||||
},
|
||||
_ => {
|
||||
let cmsg = msg.clone();
|
||||
let block = self.blocks.with_client(id, &self.clients)?;
|
||||
Box::new(block.client_location.get_all_clients_by_client(id).unwrap().into_iter()
|
||||
.filter(move |client| client.local_client.id() == target as u8)
|
||||
.map(move |client| {
|
||||
|
@ -71,7 +71,6 @@ impl ShopItem for ArmorShopItem {
|
||||
dfp: 0,
|
||||
evp: 0,
|
||||
slots: *slot as u8,
|
||||
modifiers: Vec::new()
|
||||
})
|
||||
},
|
||||
ArmorShopItem::Barrier(barrier) => {
|
||||
|
@ -142,7 +142,6 @@ impl ShopItem for WeaponShopItem {
|
||||
grind: self.grind as u8,
|
||||
attrs: [self.attributes[0], self.attributes[1], None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ async fn test_bank_items_sent_in_character_login() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -69,7 +68,6 @@ async fn test_request_bank_items() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -167,7 +165,6 @@ async fn test_request_bank_items_sorted() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -196,7 +193,6 @@ async fn test_request_bank_items_sorted() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -247,7 +243,6 @@ async fn test_deposit_individual_item() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -263,7 +258,6 @@ async fn test_deposit_individual_item() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -623,7 +617,6 @@ async fn test_deposit_individual_item_in_full_bank() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -642,7 +635,6 @@ async fn test_deposit_individual_item_in_full_bank() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -722,7 +714,6 @@ async fn test_deposit_stacked_item_in_full_bank() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -819,7 +810,6 @@ async fn test_deposit_stacked_item_in_full_bank_with_partial_stack() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -998,7 +988,6 @@ async fn test_withdraw_individual_item() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -1358,7 +1347,6 @@ async fn test_withdraw_individual_item_in_full_inventory() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Bank {
|
||||
@ -1378,7 +1366,6 @@ async fn test_withdraw_individual_item_in_full_inventory() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -1454,7 +1441,6 @@ async fn test_withdraw_stacked_item_in_full_inventory() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -1537,7 +1523,6 @@ async fn test_withdraw_stacked_item_in_full_inventory_with_partial_stack() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
|
@ -25,7 +25,6 @@ async fn test_equip_unit_from_equip_menu() {
|
||||
dfp: 0,
|
||||
evp: 0,
|
||||
slots: 4,
|
||||
modifiers: Vec::new(),
|
||||
}),
|
||||
location: item::ItemLocation::Inventory {
|
||||
character_id: char1.id,
|
||||
@ -112,7 +111,6 @@ async fn test_unequip_armor_with_units() {
|
||||
dfp: 0,
|
||||
evp: 0,
|
||||
slots: 4,
|
||||
modifiers: Vec::new(),
|
||||
}),
|
||||
location: item::ItemLocation::Inventory {
|
||||
character_id: char1.id,
|
||||
@ -190,7 +188,6 @@ async fn test_sort_items() {
|
||||
dfp: 0,
|
||||
evp: 0,
|
||||
slots: 4,
|
||||
modifiers: Vec::new(),
|
||||
}),
|
||||
location: item::ItemLocation::Inventory {
|
||||
character_id: char1.id,
|
||||
|
@ -172,7 +172,6 @@ async fn test_pick_up_meseta_when_inventory_full() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -252,7 +251,6 @@ async fn test_pick_up_partial_stacked_item_when_inventory_is_otherwise_full() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -345,7 +343,6 @@ async fn test_can_not_pick_up_item_when_inventory_full() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -364,7 +361,6 @@ async fn test_can_not_pick_up_item_when_inventory_full() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
|
@ -29,7 +29,6 @@ async fn test_item_ids_reset_when_rejoining_rooms() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
@ -49,7 +48,6 @@ async fn test_item_ids_reset_when_rejoining_rooms() {
|
||||
special: None,
|
||||
attrs: [None, None, None],
|
||||
tekked: true,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
),
|
||||
location: item::ItemLocation::Inventory {
|
||||
|
Loading…
x
Reference in New Issue
Block a user