Browse Source

bare minimum item usage stuff

pull/112/head
jake 3 years ago
committed by andy
parent
commit
4e88f684c5
  1. 52
      src/ship/items/actions.rs
  2. 219
      src/ship/items/apply_item.rs
  3. 1
      src/ship/items/mod.rs
  4. 6
      src/ship/items/state.rs
  5. 10
      src/ship/packet/handler/message.rs
  6. 2
      src/ship/ship.rs
  7. 6
      tests/test_item_use.rs

52
src/ship/items/actions.rs

@ -7,7 +7,10 @@ use crate::ship::map::MapArea;
use crate::entity::character::{CharacterEntity, CharacterEntityId};
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, ItemAction, ItemStateError, FloorItem, InventoryItem, AddItemResult, FloorItemDetail,
StackedItemDetail, BankItem, BankItemDetail, InventoryItemDetail};
StackedItemDetail, BankItem, BankItemDetail, InventoryItemDetail, IndividualItemDetail};
use crate::ship::items::apply_item::apply_item;
use crate::entity::item::ItemDetail;
use crate::entity::item::tool::Tool;
@ -597,3 +600,50 @@ where
Ok((transaction, result))
}).await
}
fn use_consumed_item(character: CharacterEntity)
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), CharacterEntity), ItemStateError>> + Send + 'a>>
{
move |(mut item_state, mut transaction), inventory_item| {
let mut character = character.clone();
Box::pin(async move {
let mut transaction = inventory_item.with_entity_id(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id| {
async move {
if let Ok(transaction) = &mut transaction {
transaction.gateway().add_item_note(&entity_id, ItemNote::Consumed).await?;
}
transaction
}}).await?;
apply_item(&mut item_state, transaction.gateway(), &mut character, inventory_item).await?;
Ok(((item_state, transaction), character))
})
}
}
pub async fn use_item<'a, EG> (
item_state: &'a mut ItemState,
entity_gateway: &mut EG,
character: &mut CharacterEntity,
item_id: &ClientItemId,
amount: u32,
) -> Result<(), ItemStateError>
where
EG: EntityGateway,
{
entity_gateway.with_transaction(|transaction| async move {
let item_state_proxy = ItemStateProxy::new(item_state);
let ((item_state_proxy, transaction), new_character) = ItemStateAction::default()
//.act(consume_inventory_tool(character.id, *item_id, 1))
.act(take_item_from_inventory(character.id, *item_id, amount))
.act(use_consumed_item(character.clone()))
.commit((item_state_proxy, transaction))
.await?;
item_state_proxy.commit();
*character = new_character;
Ok((transaction, ()))
}).await
}

219
src/ship/items/apply_item.rs

@ -0,0 +1,219 @@
use thiserror::Error;
use crate::entity::gateway::{EntityGateway, GatewayError};
use crate::entity::character::CharacterEntity;
use crate::entity::item::mag::MagCell;
use crate::entity::item::tool::ToolType;
use crate::entity::item::ItemDetail;
use crate::ship::items::state::{ItemStateProxy, InventoryState, InventoryItem, InventoryItemDetail};
#[derive(Error, Debug)]
pub enum ApplyItemError {
#[error("no character")]
NoCharacter,
#[error("item not equipped")]
ItemNotEquipped,
#[error("invalid item")]
InvalidItem,
#[error("gateway error {0}")]
GatewayError(#[from] GatewayError),
}
// TODO: make all these functions not-pub
pub async fn power_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.power += 1;
entity_gateway.save_character(character).await?;
Ok(())
}
pub async fn mind_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.mind += 1;
entity_gateway.save_character(character).await.unwrap();
Ok(())
}
pub async fn evade_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.evade += 1;
entity_gateway.save_character(character).await.unwrap();
Ok(())
}
pub async fn def_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.def += 1;
entity_gateway.save_character(character).await.unwrap();
Ok(())
}
pub async fn luck_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.luck += 1;
entity_gateway.save_character(character).await.unwrap();
Ok(())
}
pub async fn hp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.hp += 1;
entity_gateway.save_character(character).await.unwrap();
Ok(())
}
pub async fn tp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> {
character.materials.tp += 1;
entity_gateway.save_character(character).await.unwrap();
Ok(())
}
/*
async fn mag_cell<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory, mag_cell_type: MagCell) -> Result<(), ApplyItemError> {
let mut mag_handle = inventory.get_equipped_mag_handle().ok_or(ApplyItemError::ItemNotEquipped)?;
let mag_item = mag_handle.item_mut()
.ok_or(ApplyItemError::InvalidItem)?;
let actual_mag = mag_item
.individual_mut()
.ok_or(ApplyItemError::InvalidItem)?
.mag_mut()
.ok_or(ApplyItemError::InvalidItem)?;
actual_mag.apply_mag_cell(mag_cell_type);
for mag_entity_id in mag_item.entity_ids() {
for cell_entity_id in used_cell.entity_ids() {
entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await.unwrap();
}
}
Ok(())
}
pub async fn cell_of_mag_502<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag502).await
}
pub async fn cell_of_mag_213<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag213).await
}
pub async fn parts_of_robochao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::PartsOfRobochao).await
}
pub async fn heart_of_opaopa<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfOpaOpa).await
}
pub async fn heart_of_pian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfPian).await
}
pub async fn heart_of_chao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfChao).await
}
pub async fn heart_of_angel<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfAngel).await
}
pub async fn kit_of_hamburger<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfHamburger).await
}
pub async fn panthers_spirit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::PanthersSpirit).await
}
pub async fn kit_of_mark3<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMark3).await
}
pub async fn kit_of_master_system<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMasterSystem).await
}
pub async fn kit_of_genesis<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfGenesis).await
}
pub async fn kit_of_sega_saturn<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfSegaSaturn).await
}
pub async fn kit_of_dreamcast<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfDreamcast).await
}
pub async fn tablet<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::Tablet).await
}
pub async fn dragon_scale<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::DragonScale).await
}
pub async fn heaven_striker_coat<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeavenStrikerCoat).await
}
pub async fn pioneer_parts<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::PioneerParts).await
}
pub async fn amities_memo<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::AmitiesMemo).await
}
pub async fn heart_of_morolian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfMorolian).await
}
pub async fn rappys_beak<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::RappysBeak).await
}
pub async fn yahoos_engine<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::YahoosEngine).await
}
pub async fn d_photon_core<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::DPhotonCore).await
}
pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
mag_cell(entity_gateway, used_cell, inventory, MagCell::LibertaKit).await
}
*/
async fn apply_tool<'a, EG: EntityGateway + ?Sized>(item_state: &mut ItemStateProxy<'a>, entity_gateway: &mut EG, character: &mut CharacterEntity, tool: ToolType) -> Result<(), ApplyItemError> {
match tool {
ToolType::PowerMaterial => power_material(entity_gateway, character).await,
ToolType::MindMaterial => mind_material(entity_gateway, character).await,
ToolType::EvadeMaterial => evade_material(entity_gateway, character).await,
ToolType::DefMaterial => def_material(entity_gateway, character).await,
ToolType::LuckMaterial => luck_material(entity_gateway, character).await,
ToolType::HpMaterial => hp_material(entity_gateway, character).await,
ToolType::TpMaterial => tp_material(entity_gateway, character).await,
ToolType::Monomate => Ok(()),
ToolType::Dimate => Ok(()),
ToolType::Trimate => Ok(()),
ToolType::Monofluid => Ok(()),
ToolType::Difluid => Ok(()),
ToolType::Trifluid => Ok(()),
ToolType::HuntersReport => Ok(()),
// TODO: rest of these
_ => Err(ApplyItemError::InvalidItem)
}
}
pub async fn apply_item<'a, EG: EntityGateway + ?Sized>(item_state: &mut ItemStateProxy<'a>, entity_gateway: &mut EG, character: &mut CharacterEntity, item: InventoryItem) -> Result<(), ApplyItemError> {
let item_detail = match item.item {
InventoryItemDetail::Individual(individual_item) => {
individual_item.item
},
InventoryItemDetail::Stacked(stacked_item) => {
ItemDetail::Tool(stacked_item.tool)
},
};
match item_detail {
ItemDetail::Tool(tool) => apply_tool(item_state, entity_gateway, character, tool.tool).await,
_ => Err(ApplyItemError::InvalidItem)
}
}

1
src/ship/items/mod.rs

@ -6,6 +6,7 @@ pub mod transaction;
pub mod use_tool;
pub mod state;
pub mod actions;
pub mod apply_item;
use serde::{Serialize, Deserialize};
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)]

6
src/ship/items/state.rs

@ -24,6 +24,9 @@ pub enum ItemStateError {
#[error("floor item {0} not found")]
NoFloorItem(ClientItemId),
#[error("expected {0} to be a tool")]
NotATool(ClientItemId),
#[error("bank item {0} not found")]
NoBankItem(ClientItemId),
@ -50,6 +53,9 @@ pub enum ItemStateError {
#[error("stacked item")]
StackedItemError(Vec<ItemEntity>),
#[error("apply item {0}")]
ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError),
}
pub enum FloorType {

10
src/ship/packet/handler/message.rs

@ -8,7 +8,7 @@ use crate::ship::location::{ClientLocation, ClientLocationError};
use crate::ship::items::{ItemManager, ClientItemId};
use crate::ship::packet::builder;
use crate::ship::items::state::ItemState;
use crate::ship::items::actions::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory};
use crate::ship::items::actions::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item};
pub async fn request_exp<EG: EntityGateway>(id: ClientId,
request_exp: &RequestExp,
@ -278,20 +278,18 @@ where
}
}
pub async fn use_item<EG>(id: ClientId,
pub async fn player_uses_item<EG>(id: ClientId,
player_use_tool: &PlayerUseItem,
entity_gateway: &mut EG,
_client_location: &ClientLocation,
clients: &mut Clients,
item_manager: &mut ItemManager)
item_state: &mut ItemState)
-> 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 item_used_type = item_manager.player_consumes_tool(entity_gateway, &mut client.character, ClientItemId(player_use_tool.item_id), 1).await?;
item_manager.use_item(item_used_type, entity_gateway, &mut client.character).await?;
use_item(item_state, entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await?;
Ok(Box::new(None.into_iter())) // TODO: should probably tell other players we used an item
}

2
src/ship/ship.rs

@ -504,7 +504,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
},
GameMessage::PlayerUseItem(player_use_item) => {
let block = self.blocks.with_client(id, &self.clients)?;
handler::message::use_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
},
GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => {
handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await?

6
tests/test_item_use.rs

@ -164,7 +164,7 @@ async fn test_use_nonstackable_tool() {
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::MagicStoneIritista,
tool: item::tool::ToolType::HuntersReport,
}
),
}).await.unwrap());
@ -251,6 +251,9 @@ async fn test_use_materials() {
assert!(char.materials.luck == 2);
}
// TODO: tests for ALL ITEMS WOW
/*
#[async_std::test]
pub async fn test_learn_new_tech() {}
@ -268,3 +271,4 @@ pub async fn test_char_cannot_learn_high_level_tech() {}
#[async_std::test]
pub async fn test_android_cannot_learn_tech() {}
*/
Loading…
Cancel
Save