Browse Source

add remaining modifiers for item types and fix presents?

presents
andy 3 years ago
parent
commit
a238ae3846
  1. 62
      src/bin/main.rs
  2. 11
      src/entity/gateway/entitygateway.rs
  3. 95
      src/entity/gateway/inmemory.rs
  4. 14
      src/entity/gateway/postgres/migrations/V0001__initial.sql
  5. 19
      src/entity/gateway/postgres/models.rs
  6. 41
      src/entity/gateway/postgres/postgres.rs
  7. 4
      src/entity/item/armor.rs
  8. 16
      src/entity/item/esweapon.rs
  9. 4
      src/entity/item/mag.rs
  10. 67
      src/entity/item/mod.rs
  11. 3
      src/entity/item/shield.rs
  12. 15
      src/entity/item/tech.rs
  13. 14
      src/entity/item/tool.rs
  14. 60
      src/ship/items/inventory.rs
  15. 290
      src/ship/items/manager.rs
  16. 2
      tests/test_item_modifiers.rs

62
src/bin/main.rs

@ -121,7 +121,7 @@ fn main() {
Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 30}),
None,],
tekked: false,
wrapping: Some(item::WrappingPaper::Black_Yellow),
wrapping: Some(item::WrappingPaper::BlackYellow),
}
),
location: ItemLocation::Inventory {
@ -243,7 +243,8 @@ fn main() {
item: ItemDetail::Tool (
item::tool::Tool {
tool: item::tool::ToolType::CellOfMag502,
wrapping: None,
// wrapping: None,
wrapping: Some(item::WrappingPaper::PinkYellowGreen),
}
),
location: item::ItemLocation::Consumed,
@ -292,7 +293,7 @@ fn main() {
shield: item::shield::ShieldType::Barrier,
dfp: 0,
evp: 0,
wrapping: Some(item::WrappingPaper::Yellow),
wrapping: Some(item::WrappingPaper::Green),
}
),
location: ItemLocation::Inventory {
@ -320,7 +321,8 @@ fn main() {
item::unit::Unit {
unit: item::unit::UnitType::PriestMind,
modifier: Some(item::unit::UnitModifier::Minus),
wrapping: None,
// wrapping: None,
wrapping: Some(item::WrappingPaper::YellowBlue),
}
),
location: ItemLocation::Inventory {
@ -365,6 +367,56 @@ fn main() {
}
).await.unwrap();
// wrapping monomates doesn't do anything
let item14 = entity_gateway.create_item(
NewItemEntity {
item: ItemDetail::Tool (
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
// wrapping: None,
wrapping: Some(item::WrappingPaper::Yellow),
}
),
location: ItemLocation::Inventory {
character_id: character.id,
}
}
).await.unwrap();
/* wrapping techs is no bueno */
// let item15 = entity_gateway.create_item(
// NewItemEntity {
// item: ItemDetail::TechniqueDisk (
// item::tech::TechniqueDisk {
// tech: item::tech::Technique::Foie,
// level: 5,
// // wrapping: None,
// wrapping: Some(item::WrappingPaper::Blue),
// }
// ),
// location: ItemLocation::Inventory {
// character_id: character.id,
// }
// }
// ).await.unwrap();
let item16 = entity_gateway.create_item(
NewItemEntity {
item: ItemDetail::ESWeapon (
item::esweapon::ESWeapon {
esweapon: item::esweapon::ESWeaponType::Hammer,
special: Some(item::esweapon::ESWeaponSpecial::Hell),
name: "BAN".to_owned(),
grind: 69u8,
wrapping: Some(item::WrappingPaper::LightBlueOrange),
}
),
location: ItemLocation::Inventory {
character_id: character.id,
}
}
).await.unwrap();
let equipped = item::EquippedEntity {
weapon: Some(item2_w.id),
armor: Some(item7_a.id),
@ -374,7 +426,7 @@ fn main() {
};
entity_gateway.set_character_equips(&character.id, &equipped).await.unwrap();
let inventory = item::InventoryEntity::new(vec![item0, item1, item2_w, item3, item4, item5_m, item6, item7_a, item8_s, item9_u0, item10_u1, item11_u2, item12_u3, item13]);
let inventory = item::InventoryEntity::new(vec![item0, item1, item2_w, item3, item4, item5_m, item6, item7_a, item8_s, item9_u0, item10_u1, item11_u2, item12_u3, item13, item14, /*item15,*/ item16]);
entity_gateway.set_character_inventory(&character.id, &inventory).await.unwrap();
entity_gateway.set_character_bank(&character.id, &item::BankEntity::default(), item::BankName("".into())).await.unwrap();
}

11
src/entity/gateway/entitygateway.rs

@ -85,6 +85,10 @@ pub trait EntityGateway: Send + Sync + Clone {
unimplemented!();
}
async fn add_esweapon_modifier(&mut self, _item_id: &ItemEntityId, _modifier: esweapon::ESWeaponModifier) -> Result<(), GatewayError> {
unimplemented!();
}
async fn add_armor_modifier(&mut self, _item_id: &ItemEntityId, _modifier: armor::ArmorModifier) -> Result<(), GatewayError> {
unimplemented!();
}
@ -101,6 +105,13 @@ pub trait EntityGateway: Send + Sync + Clone {
unimplemented!();
}
async fn add_tech_modifier(&mut self, _item_id: &ItemEntityId, _modifier: tech::TechModifier) -> Result<(), GatewayError> {
unimplemented!();
}
async fn add_tool_modifier(&mut self, _item_id: &ItemEntityId, _modifier: tool::ToolModifier) -> Result<(), GatewayError> {
unimplemented!();
}
/*
async fn get_items_by_character(&self, _char_id: &CharacterEntityId) -> Result<Vec<ItemEntity>, GatewayError> {

95
src/entity/gateway/inmemory.rs

@ -19,9 +19,12 @@ 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>>>>,
esweapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<esweapon::ESWeaponModifier>>>>,
armor_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<armor::ArmorModifier>>>>,
shield_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<shield::ShieldModifier>>>>,
unit_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<unit::UnitModifier>>>>,
tech_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<tech::TechModifier>>>>,
tool_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<tool::ToolModifier>>>>,
}
impl InMemoryGateway {
@ -36,9 +39,12 @@ impl InMemoryGateway {
equips: Arc::new(Mutex::new(BTreeMap::new())),
mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
esweapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
armor_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
shield_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
unit_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
tech_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
tool_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
}
}
}
@ -58,8 +64,62 @@ impl InMemoryGateway {
}
ItemDetail::Weapon(weapon)
},
ItemDetail::ESWeapon(mut esweapon) => {
if let Some(esweapon_modifiers) = self.esweapon_modifiers.lock().unwrap().get(&item.id) {
for esweapon_modifier in esweapon_modifiers.iter() {
esweapon.apply_modifier(&esweapon_modifier);
}
}
ItemDetail::ESWeapon(esweapon)
},
ItemDetail::Armor(mut armor) => {
if let Some(armor_modifiers) = self.armor_modifiers.lock().unwrap().get(&item.id) {
for armor_modifier in armor_modifiers.iter() {
armor.apply_modifier(&armor_modifier);
}
}
ItemDetail::Armor(armor)
},
ItemDetail::Shield(mut shield) => {
if let Some(shield_modifiers) = self.shield_modifiers.lock().unwrap().get(&item.id) {
for shield_modifier in shield_modifiers.iter() {
shield.apply_modifier(&shield_modifier);
}
}
ItemDetail::Shield(shield)
},
ItemDetail::Unit(mut unit) => {
if let Some(unit_modifiers) = self.unit_modifiers.lock().unwrap().get(&item.id) {
for unit_modifier in unit_modifiers.iter() {
unit.apply_modifier(&unit_modifier);
}
}
ItemDetail::Unit(unit)
},
ItemDetail::TechniqueDisk(mut tech) => {
if let Some(tech_modifiers) = self.tech_modifiers.lock().unwrap().get(&item.id) {
for tech_modifier in tech_modifiers.iter() {
tech.apply_modifier(&tech_modifier);
}
}
ItemDetail::TechniqueDisk(tech)
},
ItemDetail::Tool(mut tool) => {
if let Some(tool_modifiers) = self.tool_modifiers.lock().unwrap().get(&item.id) {
for tool_modifier in tool_modifiers.iter() {
tool.apply_modifier(&tool_modifier);
}
}
ItemDetail::Tool(tool)
},
ItemDetail::Mag(mag) => {
let mut mag = mag::Mag::baby_mag(mag.color as u16);
let mut mag = {
if mag.wrapping.is_some() {
mag::Mag::wrapped_baby_mag(mag.color as u16)
} else {
mag::Mag::baby_mag(mag.color as u16)
}
};
if let Some(mag_modifiers) = self.mag_modifiers.lock().unwrap().get(&item.id) {
for mag_modifier in mag_modifiers.iter() {
match mag_modifier {
@ -87,12 +147,11 @@ impl InMemoryGateway {
}
}
ItemDetail::Mag(mag)
}
_ => {
item.item
}
},
// _ => {
// item.item
// }
};
item
})
})
@ -279,6 +338,14 @@ impl EntityGateway for InMemoryGateway {
Ok(())
}
async fn add_esweapon_modifier(&mut self, item_id: &ItemEntityId, modifier: esweapon::ESWeaponModifier) -> Result<(), GatewayError> {
self.esweapon_modifiers.lock().unwrap()
.entry(*item_id)
.or_insert(Vec::new())
.push(modifier);
Ok(())
}
async fn add_armor_modifier(&mut self, item_id: &ItemEntityId, modifier: armor::ArmorModifier) -> Result<(), GatewayError> {
self.armor_modifiers.lock().unwrap()
.entry(*item_id)
@ -311,6 +378,22 @@ impl EntityGateway for InMemoryGateway {
Ok(())
}
async fn add_tech_modifier(&mut self, item_id: &ItemEntityId, modifier: tech::TechModifier) -> Result<(), GatewayError> {
self.tech_modifiers.lock().unwrap()
.entry(*item_id)
.or_insert(Vec::new())
.push(modifier);
Ok(())
}
async fn add_tool_modifier(&mut self, item_id: &ItemEntityId, modifier: tool::ToolModifier) -> Result<(), GatewayError> {
self.tool_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();

14
src/entity/gateway/postgres/migrations/V0001__initial.sql

@ -50,7 +50,7 @@ create table player_character (
prop_y real not null,
techs bytea not null,
config bytea not null,
infoboard varchar(172) not null,
guildcard varchar(172) not null,
@ -111,6 +111,18 @@ create table unit_modifier (
created_at timestamptz default current_timestamp not null
);
create table tech_modifier (
tech integer references item (id) not null,
modifier jsonb not null,
created_at timestamptz default current_timestamp not null
);
create table tool_modifier (
tool integer references item (id) not null,
modifier jsonb not null,
created_at timestamptz default current_timestamp not null
);
create table esweapon_modifier (
esweapon integer references item (id) not null,
modifier jsonb not null,

19
src/entity/gateway/postgres/models.rs

@ -461,6 +461,12 @@ impl Into<tool::Tool> for PgTool {
}
}
#[derive(Debug, sqlx::FromRow)]
pub struct PgToolModifier {
pub tool: i32,
pub modifier: sqlx::types::Json<tool::ToolModifier>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PgTechDisk {
tech: tech::Technique,
@ -488,6 +494,12 @@ impl Into<tech::TechniqueDisk> for PgTechDisk {
}
}
#[derive(Debug, sqlx::FromRow)]
pub struct PgTechModifier {
pub tool: i32,
pub modifier: sqlx::types::Json<tech::TechModifier>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PgMag {
mag: mag::MagType,
@ -563,6 +575,13 @@ impl Into<esweapon::ESWeapon> for PgESWeapon {
}
}
#[derive(Debug, sqlx::FromRow)]
pub struct PgESWeaponModifier {
pub esweapon: i32,
pub modifier: sqlx::types::Json<esweapon::ESWeaponModifier>,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum PgItemDetail {
Weapon(PgWeapon),

41
src/entity/gateway/postgres/postgres.rs

@ -65,6 +65,23 @@ impl PostgresGateway {
ItemDetail::Weapon(weapon)
},
ItemDetail::ESWeapon(mut esweapon) => {
let q = r#"select esweapon, modifier
from esweapon_modifier
where esweapon = $1
order by created_at"#;
let esweapon_modifiers = sqlx::query_as::<_, PgESWeaponModifier>(q)
.bind(id.0 as i32)
.fetch(&self.pool);
esweapon_modifiers.for_each(|modifier| {
if let Ok(modifier) = modifier {
esweapon.apply_modifier(&modifier.modifier);
}
}).await;
ItemDetail::ESWeapon(esweapon)
},
ItemDetail::Mag(mut mag) => {
let q = r#"select mag, modifier, item.item -> 'Tool' as feed, item2.item -> 'Tool' as cell
from mag_modifier
@ -469,6 +486,14 @@ impl EntityGateway for PostgresGateway {
Ok(())
}
async fn add_esweapon_modifier(&mut self, item_id: &ItemEntityId, modifier: esweapon::ESWeaponModifier) -> Result<(), GatewayError> {
sqlx::query("insert into esweapon_modifier (esweapon, modifier) values ($1, $2);")
.bind(item_id.0)
.bind(sqlx::types::Json(modifier))
.execute(&self.pool).await?;
Ok(())
}
async fn add_armor_modifier(&mut self, item_id: &ItemEntityId, modifier: armor::ArmorModifier) -> Result<(), GatewayError> {
sqlx::query("insert into armor_modifier (armor, modifier) values ($1, $2);")
.bind(item_id.0)
@ -501,6 +526,22 @@ impl EntityGateway for PostgresGateway {
Ok(())
}
async fn add_tech_modifier(&mut self, item_id: &ItemEntityId, modifier: tech::TechModifier) -> Result<(), GatewayError> {
sqlx::query("insert into tech_modifier (tech, modifier) values ($1, $2);")
.bind(item_id.0)
.bind(sqlx::types::Json(modifier))
.execute(&self.pool).await?;
Ok(())
}
async fn add_tool_modifier(&mut self, item_id: &ItemEntityId, modifier: tool::ToolModifier) -> Result<(), GatewayError> {
sqlx::query("insert into tool_modifier (tool, 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 (

4
src/entity/item/armor.rs

@ -299,7 +299,7 @@ pub enum ArmorModifier {
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Armor {
pub armor: ArmorType,
pub dfp: u8,
@ -346,7 +346,7 @@ impl Armor {
pub fn apply_modifier(&mut self, modifier: &ArmorModifier) {
match modifier {
ArmorModifier::WrapPresent => {self.wrapping = Some(WrappingPaper::White_Pink)},
ArmorModifier::WrapPresent => {self.wrapping = Some(WrappingPaper::WhitePink)},
ArmorModifier::UnwrapPresent => {self.wrapping = None},
_ => {},
}

16
src/entity/item/esweapon.rs

@ -170,6 +170,14 @@ impl ESWeaponSpecial {
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum ESWeaponModifier {
WrapPresent {
paper: WrappingPaper,
},
UnwrapPresent,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ESWeapon {
pub esweapon: ESWeaponType,
@ -274,6 +282,14 @@ impl ESWeapon {
wrapping: wrapping,
}
}
pub fn apply_modifier(&mut self, modifier: &ESWeaponModifier) {
match modifier {
ESWeaponModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)},
ESWeaponModifier::UnwrapPresent => {self.wrapping = None},
_ => {},
}
}
}
#[cfg(test)]

4
src/entity/item/mag.rs

@ -531,7 +531,7 @@ pub enum PhotonBlast {
MyllaYoulla,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Mag {
pub mag: MagType,
def: u16,
@ -1133,7 +1133,7 @@ impl Mag {
pub fn apply_modifier(&mut self, modifier: &MagModifier) {
match modifier {
MagModifier::WrapPresent => {self.wrapping = WrappingPaper::from(self.color % 10)}, // prevents mag color from crashing wrapping papers
MagModifier::WrapPresent => {self.wrapping = WrappingPaper::from(self.color % 10)}, // prevents mag color from crashing wrapping papers. client always shows mags in default paper colour ?
MagModifier::UnwrapPresent => {self.wrapping = None},
_ => {}, // TODO: other modifiers are already handled elsewhere. do they need to be moved here?
}

67
src/entity/item/mod.rs

@ -160,33 +160,32 @@ impl ItemDetail {
}
}
pub fn is_wrapped(self) -> bool {
pub fn is_wrapped(&mut self) -> bool {
match self {
ItemDetail::Weapon(w) => w.wrapping.is_some(),
// ItemDetail::Armor(a) => a.wrapping.is_some(),
// ItemDetail::Shield(s) => s.wrapping.is_some(),
// ItemDetail::Unit(u) => u.wrapping.is_some(),
// ItemDetail::Tool(t) => t.wrapping.is_some(),
// ItemDetail::TechniqueDisk(d) => d.wrapping.is_some(),
// ItemDetail::Mag(m) => m.wrapping.is_some(),
// ItemDetail::ESWeapon(e) => e.wrapping.is_some(),
_ => false
ItemDetail::Armor(a) => a.wrapping.is_some(),
ItemDetail::Shield(s) => s.wrapping.is_some(),
ItemDetail::Unit(u) => u.wrapping.is_some(),
ItemDetail::Tool(t) => t.wrapping.is_some(),
ItemDetail::TechniqueDisk(d) => d.wrapping.is_some(),
ItemDetail::Mag(m) => m.wrapping.is_some(),
ItemDetail::ESWeapon(e) => e.wrapping.is_some(),
_ => unreachable!(),
}
}
pub fn unwrap_present(self) -> ItemDetail {
pub fn unwrap_present(&mut self) {
match self {
ItemDetail::Weapon(mut w) => w.wrapping = None,
// ItemDetail::Armor(a) => a.wrapping.is_some(),
// ItemDetail::Shield(s) => s.wrapping.is_some(),
// ItemDetail::Unit(u) => u.wrapping.is_some(),
// ItemDetail::Tool(t) => t.wrapping.is_some(),
// ItemDetail::TechniqueDisk(d) => d.wrapping.is_some(),
// ItemDetail::Mag(m) => m.wrapping.is_some(),
// ItemDetail::ESWeapon(e) => e.wrapping.is_some(),
_ => {},
ItemDetail::Weapon(ref mut w) => w.wrapping = None,
ItemDetail::Armor(ref mut a) => a.wrapping = None,
ItemDetail::Shield(ref mut s) => s.wrapping = None,
ItemDetail::Unit(ref mut u) => u.wrapping = None,
ItemDetail::Tool(ref mut t) => t.wrapping = None,
ItemDetail::TechniqueDisk(ref mut d) => d.wrapping = None,
ItemDetail::Mag(ref mut m) => m.wrapping = None,
ItemDetail::ESWeapon(ref mut e) => e.wrapping = None,
_ => unreachable!(),
};
self
}
}
@ -229,7 +228,7 @@ impl InventoryItemEntity {
_ => self,
}
}
//pub fn with_individual<T>(&self, func: fn(&ItemEntity) -> T) -> Option<T> {
pub fn with_individual<F: Fn(&ItemEntity) -> T, T>(&self, func: F) -> Option<T> {
match self {
InventoryItemEntity::Individual(item) => Some(func(item)),
@ -237,7 +236,6 @@ impl InventoryItemEntity {
}
}
//pub fn with_stacked<T>(&self, func: fn(&Vec<ItemEntity>) -> T) -> Option<T> {
pub fn with_stacked<F: Fn(&Vec<ItemEntity>) -> T, T>(&self, func: F) -> Option<T> {
match self {
InventoryItemEntity::Stacked(items) => Some(func(items)),
@ -319,7 +317,6 @@ impl BankItemEntity {
#[derive(Clone, Debug, Default)]
pub struct BankEntity {
//pub items: [Option<CharacterBankItem>; 30],
pub items: Vec<BankItemEntity>,
}
@ -333,12 +330,12 @@ impl BankEntity {
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum WrappingPaper {
White_Pink, // 0
Yellow_Blue, // 1
Black_Yellow, // 2
LightBlue_Orange, // 3
Pink_YellowGreen, // 4
Red_Green, // 5
WhitePink, // 0
YellowBlue, // 1
BlackYellow, // 2
LightBlueOrange, // 3
PinkYellowGreen, // 4
RedGreen, // 5
Magenta, // 6
Blue, // 7
Yellow, // 8
@ -353,12 +350,12 @@ impl WrappingPaper {
pub fn from(data: u8) -> Option<WrappingPaper> {
match data {
0 => Some(WrappingPaper::White_Pink),
1 => Some(WrappingPaper::Yellow_Blue),
2 => Some(WrappingPaper::Black_Yellow),
3 => Some(WrappingPaper::LightBlue_Orange),
4 => Some(WrappingPaper::Pink_YellowGreen),
5 => Some(WrappingPaper::Red_Green),
0 => Some(WrappingPaper::WhitePink),
1 => Some(WrappingPaper::YellowBlue),
2 => Some(WrappingPaper::BlackYellow),
3 => Some(WrappingPaper::LightBlueOrange),
4 => Some(WrappingPaper::PinkYellowGreen),
5 => Some(WrappingPaper::RedGreen),
6 => Some(WrappingPaper::Magenta),
7 => Some(WrappingPaper::Blue),
8 => Some(WrappingPaper::Yellow),

3
src/entity/item/shield.rs

@ -572,9 +572,8 @@ impl Shield {
pub fn apply_modifier(&mut self, modifier: &ShieldModifier) {
match modifier {
ShieldModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)},
ShieldModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, // TODO: client always shows shields in default paper colour ?
ShieldModifier::UnwrapPresent => {self.wrapping = None},
_ => {},
}
}
}

15
src/entity/item/tech.rs

@ -76,6 +76,14 @@ impl Technique {
}
}
#[derive(Debug, Serialize)]
pub enum TechModifier {
WrapPresent {
paper: WrappingPaper,
},
UnwrapPresent,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct TechniqueDisk {
pub tech: Technique,
@ -96,4 +104,11 @@ impl TechniqueDisk {
};
result
}
pub fn apply_modifier(&mut self, modifier: &TechModifier) {
match modifier {
TechModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)},
TechModifier::UnwrapPresent => {self.wrapping = None},
}
}
}

14
src/entity/item/tool.rs

@ -648,6 +648,13 @@ impl ToolType {
}
}
#[derive(Debug, Serialize)]
pub enum ToolModifier {
WrapPresent {
paper: WrappingPaper,
},
UnwrapPresent,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Tool {
@ -696,4 +703,11 @@ impl Tool {
pub fn max_stack(&self) -> usize {
self.tool.max_stack()
}
pub fn apply_modifier(&mut self, modifier: &ToolModifier) {
match modifier {
ToolModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)},
ToolModifier::UnwrapPresent => {self.wrapping = None},
}
}
}

60
src/ship/items/inventory.rs

@ -6,9 +6,11 @@ use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, ItemType, ItemLo
use crate::entity::item::tool::Tool;
use crate::entity::item::mag::Mag;
use crate::entity::item::weapon::Weapon;
use crate::entity::item::esweapon::ESWeapon;
use crate::entity::item::armor::Armor; // TODO: cleanup uses
use crate::entity::item::shield::Shield;
use crate::entity::item::unit::Unit;
use crate::entity::item::tech::TechniqueDisk;
use crate::ship::items::{ClientItemId, BankItem, BankItemHandle};
use crate::ship::items::floor::{IndividualFloorItem, StackedFloorItem};
@ -48,10 +50,6 @@ impl IndividualInventoryItem {
}
}
pub fn is_wrapped(self) -> bool {
self.clone().item.is_wrapped()
}
pub fn weapon_mut(&mut self) -> Option<&mut Weapon> {
match self.item {
ItemDetail::Weapon(ref mut weapon) => Some(weapon),
@ -59,6 +57,13 @@ impl IndividualInventoryItem {
}
}
pub fn esweapon_mut(&mut self) -> Option<&mut ESWeapon> {
match self.item {
ItemDetail::ESWeapon(ref mut esweapon) => Some(esweapon),
_ => None
}
}
pub fn armor_mut(&mut self) -> Option<&mut Armor> {
match self.item {
ItemDetail::Armor(ref mut armor) => Some(armor),
@ -80,6 +85,27 @@ impl IndividualInventoryItem {
}
}
pub fn tech_mut(&mut self) -> Option<&mut TechniqueDisk> {
match self.item {
ItemDetail::TechniqueDisk(ref mut tech) => Some(tech),
_ => None
}
}
pub fn tool_mut(&mut self) -> Option<&mut Tool> {
match self.item {
ItemDetail::Tool(ref mut tool) => Some(tool),
_ => None
}
}
pub fn is_wrapped(&mut self) -> bool {
self.item.is_wrapped()
}
pub fn unwrap_present(&mut self) {
self.item.unwrap_present();
}
}
#[derive(Debug, Clone)]
@ -104,8 +130,11 @@ impl StackedInventoryItem {
}
pub fn is_wrapped(&self) -> bool {
// TODO: add wrapping to Tool
false
self.tool.wrapping.is_some()
}
pub fn unwrap_present(&mut self) {
self.tool.wrapping = None;
}
}
@ -281,26 +310,19 @@ impl InventoryItem {
}
}
pub fn is_wrapped(self) -> bool {
// TODO: validate if wrapping stacked items & tools are valid in the client. Gallons shop allows users to wrap tools (eg techs) but then the client may not be able to unwrap it afterwards?
pub fn is_wrapped(&mut self) -> bool {
match self {
InventoryItem::Individual(i) => i.is_wrapped(),
InventoryItem::Stacked(s) => s.is_wrapped(),
}
}
pub fn unwrap_present(self) -> InventoryItem {
pub fn unwrap_present(&mut self) {
match self {
InventoryItem::Individual(i) => InventoryItem::Individual(IndividualInventoryItem {
entity_id: i.entity_id,
item_id: i.item_id,
item: i.item.unwrap_present(),
}),
InventoryItem::Stacked(s) => InventoryItem::Stacked(StackedInventoryItem {
entity_ids: s.entity_ids,
item_id: s.item_id,
tool: s.tool, // s.unwrap_present()
}),
}
InventoryItem::Individual(i) => i.unwrap_present(),
InventoryItem::Stacked(s) => s.unwrap_present(),
};
}
}

290
src/ship/items/manager.rs

@ -6,11 +6,7 @@ use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel};
use crate::entity::item::{ItemDetail, ItemLocation, BankName};
use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, EquippedEntity, InventoryEntity, BankItemEntity, BankEntity, ItemType};
use crate::entity::item::tool::{Tool, ToolType};
use crate::entity::item::unit;
use crate::entity::item::weapon;
use crate::entity::item::armor;
use crate::entity::item::shield;
use crate::entity::item::mag;
use crate::entity::item::{unit, weapon, armor, shield, mag, tech, tool, esweapon};
use crate::ship::map::MapArea;
use crate::ship::ship::ItemDropLocation;
use crate::ship::drops::{ItemDrop, ItemDropType};
@ -506,7 +502,7 @@ impl ItemManager {
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let used_item = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?;
let consumed_item = used_item.consume(amount)?;
println!("consumed some item");
if let ItemDetail::TechniqueDisk(tech_disk) = consumed_item.item() {
// TODO: validate tech level in packet is in bounds [1..30]
character.techs.set_tech(tech_disk.tech, TechLevel(tech_disk.level as u8));
@ -645,164 +641,144 @@ impl ItemManager {
let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?;
let mut used_item_handle = inventory.get_item_handle_by_id(client_item_id).ok_or(ItemManagerError::ItemIdNotInInventory(client_item_id))?;
let used_item = used_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
match used_item.item_type() {
ItemType::Armor(_) => {
let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.armor_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
if actual_used_item.wrapping.is_some() {
actual_used_item.apply_modifier(&armor::ArmorModifier::UnwrapPresent);
entity_gateway.add_armor_modifier(&used_item.entity_ids()[0], armor::ArmorModifier::UnwrapPresent).await?;
} else {
if used_item.is_wrapped() {
used_item.unwrap_present();
} else {
match used_item.item_type() {
ItemType::Armor(_) => {
let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.armor_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
// combining / unsealing?
}
},
ItemType::ESWeapon(_) => {
},
ItemType::Mag(_) => {
let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.mag_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
if actual_used_item.wrapping.is_some() {
actual_used_item.apply_modifier(&mag::MagModifier::UnwrapPresent);
entity_gateway.add_mag_modifier(&used_item.entity_ids()[0], mag::MagModifier::UnwrapPresent).await?;
} else {
},
ItemType::ESWeapon(_) => { // TODO: wrap srank weapons
let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.esweapon_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
// combining / unsealing?
}
},
ItemType::Shield(_) => {
let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.shield_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
if actual_used_item.wrapping.is_some() {
actual_used_item.apply_modifier(&shield::ShieldModifier::UnwrapPresent);
entity_gateway.add_shield_modifier(&used_item.entity_ids()[0], shield::ShieldModifier::UnwrapPresent).await?;
} else {
},
ItemType::Mag(_) => {
let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.mag_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
// combining / unsealing?
}
},
ItemType::TechniqueDisk(_) => {
},
ItemType::Tool(_) => {
let consumed_item = used_item.as_consumed_item();
match &used_item.item_detail() {
ItemDetail::Tool(t) => {
match t.tool {
ToolType::PowerMaterial => {
use_tool::power_material(entity_gateway, character).await;
},
ToolType::MindMaterial => {
use_tool::mind_material(entity_gateway, character).await;
},
ToolType::EvadeMaterial => {
use_tool::evade_material(entity_gateway, character).await;
},
ToolType::DefMaterial => {
use_tool::def_material(entity_gateway, character).await;
},
ToolType::LuckMaterial => {
use_tool::luck_material(entity_gateway, character).await;
},
ToolType::HpMaterial => {
use_tool::hp_material(entity_gateway, character).await;
},
ToolType::TpMaterial => {
use_tool::tp_material(entity_gateway, character).await;
},
ToolType::CellOfMag502 => {
use_tool::cell_of_mag_502(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::CellOfMag213 => {
use_tool::cell_of_mag_213(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::PartsOfRobochao => {
use_tool::parts_of_robochao(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfOpaOpa => {
use_tool::heart_of_opaopa(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfPian => {
use_tool::heart_of_pian(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfChao=> {
use_tool::heart_of_chao(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfAngel => {
use_tool::heart_of_angel(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfHamburger => {
use_tool::kit_of_hamburger(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::PanthersSpirit => {
use_tool::panthers_spirit(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfMark3 => {
use_tool::kit_of_mark3(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfMasterSystem=> {
use_tool::kit_of_master_system(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfGenesis => {
use_tool::kit_of_genesis(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfSegaSaturn => {
use_tool::kit_of_sega_saturn(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfDreamcast => {
use_tool::kit_of_dreamcast(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::Tablet => {
use_tool::tablet(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::DragonScale => {
use_tool::dragon_scale(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeavenStrikerCoat => {
use_tool::heaven_striker_coat(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::PioneerParts => {
use_tool::pioneer_parts(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::AmitiesMemo => {
use_tool::amities_memo(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfMorolian => {
use_tool::heart_of_morolian(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::RappysBeak => {
use_tool::rappys_beak(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::YahoosEngine => {
use_tool::yahoos_engine(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::DPhotonCore => {
use_tool::d_photon_core(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::LibertaKit => {
use_tool::liberta_kit(entity_gateway, &consumed_item, inventory).await?;
},
_ => {}
}
},
ItemType::Shield(_) => {
let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.shield_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
// combining / unsealing?
},
ItemType::TechniqueDisk(_) => {
let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.tech_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
// combining / unsealing?
},
ItemType::Tool(_) => {
let consumed_item = used_item.as_consumed_item();
match &used_item.item_detail() {
ItemDetail::Tool(t) => {
match t.tool {
ToolType::PowerMaterial => {
use_tool::power_material(entity_gateway, character).await;
},
ToolType::MindMaterial => {
use_tool::mind_material(entity_gateway, character).await;
},
ToolType::EvadeMaterial => {
use_tool::evade_material(entity_gateway, character).await;
},
ToolType::DefMaterial => {
use_tool::def_material(entity_gateway, character).await;
},
ToolType::LuckMaterial => {
use_tool::luck_material(entity_gateway, character).await;
},
ToolType::HpMaterial => {
use_tool::hp_material(entity_gateway, character).await;
},
ToolType::TpMaterial => {
use_tool::tp_material(entity_gateway, character).await;
},
ToolType::CellOfMag502 => {
use_tool::cell_of_mag_502(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::CellOfMag213 => {
use_tool::cell_of_mag_213(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::PartsOfRobochao => {
use_tool::parts_of_robochao(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfOpaOpa => {
use_tool::heart_of_opaopa(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfPian => {
use_tool::heart_of_pian(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfChao=> {
use_tool::heart_of_chao(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfAngel => {
use_tool::heart_of_angel(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfHamburger => {
use_tool::kit_of_hamburger(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::PanthersSpirit => {
use_tool::panthers_spirit(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfMark3 => {
use_tool::kit_of_mark3(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfMasterSystem=> {
use_tool::kit_of_master_system(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfGenesis => {
use_tool::kit_of_genesis(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfSegaSaturn => {
use_tool::kit_of_sega_saturn(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::KitOfDreamcast => {
use_tool::kit_of_dreamcast(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::Tablet => {
use_tool::tablet(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::DragonScale => {
use_tool::dragon_scale(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeavenStrikerCoat => {
use_tool::heaven_striker_coat(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::PioneerParts => {
use_tool::pioneer_parts(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::AmitiesMemo => {
use_tool::amities_memo(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::HeartOfMorolian => {
use_tool::heart_of_morolian(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::RappysBeak => {
use_tool::rappys_beak(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::YahoosEngine => {
use_tool::yahoos_engine(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::DPhotonCore => {
use_tool::d_photon_core(entity_gateway, &consumed_item, inventory).await?;
},
ToolType::LibertaKit => {
use_tool::liberta_kit(entity_gateway, &consumed_item, inventory).await?;
},
_ => {}
}
},
_ => {},
}
_ => {}
}
},
ItemType::Unit(_) => {
let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.unit_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
if actual_used_item.wrapping.is_some() {
actual_used_item.apply_modifier(&unit::UnitModifier::UnwrapPresent);
entity_gateway.add_unit_modifier(&used_item.entity_ids()[0], unit::UnitModifier::UnwrapPresent).await?;
} else {
},
ItemType::Unit(_) => {
let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.unit_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
// combining / unsealing?
}
},
ItemType::Weapon(_) => {
let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.weapon_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
if actual_used_item.wrapping.is_some() {
actual_used_item.apply_modifier(&weapon::WeaponModifier::UnwrapPresent);
entity_gateway.add_weapon_modifier(&used_item.entity_ids()[0], weapon::WeaponModifier::UnwrapPresent).await?;
} else {
},
ItemType::Weapon(_) => {
let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.weapon_mut().ok_or(ItemManagerError::CannotGetMutItem)?;
// combining / unsealing?
}
},
},
}
}
entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
Ok(())
}

2
tests/test_item_modifiers.rs

@ -267,7 +267,7 @@ async fn test_unwrap_mag() {
}).unwrap();
}
// TODO: implement wrapping packet (gallons shop quest)
// TODO: implement wrapping packet (message 0xD6) (gallons shop quest)
// wrap presents
#[async_std::test]
async fn test_wrap_weapon() {}

Loading…
Cancel
Save