use_item_jackolantern #124
@ -241,6 +241,13 @@ impl InventoryItemEntity {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stacked(&self) -> Option<&Vec<ItemEntity>> {
|
||||||
|
match self {
|
||||||
|
InventoryItemEntity::Stacked(i) => Some(i),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
// TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency
|
// TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency
|
||||||
use crate::ship::items::ClientItemId;
|
use crate::ship::items::ClientItemId;
|
||||||
use crate::entity::item::{Meseta, ItemNote};
|
use crate::entity::item::{Meseta, ItemNote};
|
||||||
|
use async_std::sync::Arc;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use std::iter::IntoIterator;
|
||||||
|
|
||||||
|
use libpso::packet::{ship::Message, messages::GameMessage};
|
||||||
use crate::ship::map::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
|
use crate::ship::ship::SendShipPacket;
|
||||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||||
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||||
use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail};
|
use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail};
|
||||||
@ -17,6 +21,8 @@ use crate::entity::item::tool::Tool;
|
|||||||
use crate::entity::item::ItemModifier;
|
use crate::entity::item::ItemModifier;
|
||||||
use crate::ship::shops::ShopItem;
|
use crate::ship::shops::ShopItem;
|
||||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||||
|
use crate::ship::packet::builder;
|
||||||
|
use crate::ship::location::AreaClient;
|
||||||
|
|
||||||
type BoxFuture<T> = Pin<Box<dyn Future<Output=T> + Send>>;
|
type BoxFuture<T> = Pin<Box<dyn Future<Output=T> + Send>>;
|
||||||
|
|
||||||
@ -462,13 +468,14 @@ where
|
|||||||
|
|
||||||
|
|
||||||
pub(super) fn use_consumed_item<EG, TR>(
|
pub(super) fn use_consumed_item<EG, TR>(
|
||||||
character: CharacterEntity,
|
character: &CharacterEntity,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<ApplyItemAction>), ItemStateError>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<ApplyItemAction>), ItemStateError>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + Clone + 'static,
|
EG: EntityGateway + Clone + 'static,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
|
let character = character.clone();
|
||||||
move |(mut item_state, transaction), inventory_item| {
|
move |(mut item_state, transaction), inventory_item| {
|
||||||
let mut character = character.clone();
|
let mut character = character.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -690,22 +697,22 @@ where
|
|||||||
|
|
||||||
|
|
||||||
#[async_recursion::async_recursion]
|
#[async_recursion::async_recursion]
|
||||||
async fn foreach_inner<'a, EG, TR, O, T, F>(
|
async fn foreach_inner<'a, EG, TR, O, T, F, I>(
|
||||||
state: (ItemStateProxy, TR),
|
state: (ItemStateProxy, TR),
|
||||||
mut input: Vec<T>,
|
mut input: I,
|
||||||
func: F,
|
func: Arc<F>,
|
||||||
) -> Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>
|
) -> Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>
|
||||||
where
|
where
|
||||||
'a: 'async_recursion,
|
'a: 'async_recursion,
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
O: Send,
|
O: Send,
|
||||||
T: Clone + Send,
|
T: Send,
|
||||||
F: Fn((ItemStateProxy, TR), T)
|
F: Fn((ItemStateProxy, TR), T)
|
||||||
-> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync,
|
-> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync,
|
||||||
F: Clone,
|
I: Iterator<Item = T> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let item = match input.pop() {
|
let item = match input.next() {
|
||||||
Some(item) => item,
|
Some(item) => item,
|
||||||
None => return Ok((state, Vec::new()))
|
None => return Ok((state, Vec::new()))
|
||||||
};
|
};
|
||||||
@ -718,9 +725,9 @@ where
|
|||||||
Ok((state, output))
|
Ok((state, output))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn foreach<EG, TR, O, T, F>(
|
pub(super) fn foreach<EG, TR, O, T, F, I>(
|
||||||
func: F
|
func: F
|
||||||
) -> impl Fn((ItemStateProxy, TR), Vec<T>)
|
) -> impl Fn((ItemStateProxy, TR), I)
|
||||||
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
@ -729,11 +736,14 @@ where
|
|||||||
T: Send + Clone + 'static + std::fmt::Debug,
|
T: Send + Clone + 'static + std::fmt::Debug,
|
||||||
F: Fn((ItemStateProxy, TR), T)
|
F: Fn((ItemStateProxy, TR), T)
|
||||||
-> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync + 'static,
|
-> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync + 'static,
|
||||||
F: Clone,
|
T: Send + Sync,
|
||||||
T: Clone + Send + Sync,
|
I: IntoIterator<Item = T> + Send + Sync + 'static,
|
||||||
|
I::IntoIter: Send + Sync,
|
||||||
{
|
{
|
||||||
|
let func = Arc::new(func);
|
||||||
move |(item_state, transaction), items| {
|
move |(item_state, transaction), items| {
|
||||||
let func = func.clone();
|
let func = func.clone();
|
||||||
|
let items = items.into_iter();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let (state, result) = foreach_inner((item_state, transaction), items, func).await?;
|
let (state, result) = foreach_inner((item_state, transaction), items, func).await?;
|
||||||
Ok((state, result))
|
Ok((state, result))
|
||||||
@ -758,6 +768,35 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn fork<EG, TR, F1, F2, T, O1, O2>(
|
||||||
|
func1: F1,
|
||||||
|
func2: F2,
|
||||||
|
) -> impl Fn((ItemStateProxy, TR), T)
|
||||||
|
-> BoxFuture<Result<((ItemStateProxy, TR), (O1, O2)), ItemStateError>>
|
||||||
|
where
|
||||||
|
EG: EntityGateway,
|
||||||
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
|
F1: Fn((ItemStateProxy, TR), T) -> BoxFuture<Result<((ItemStateProxy, TR), O1), ItemStateError>> + Send + Sync + 'static,
|
||||||
|
F2: Fn((ItemStateProxy, TR), T) -> BoxFuture<Result<((ItemStateProxy, TR), O2), ItemStateError>> + Send + Sync + 'static,
|
||||||
|
T: Send + Sync + Clone + 'static,
|
||||||
|
O1: Send,
|
||||||
|
O2: Send,
|
||||||
|
{
|
||||||
|
let func1 = Arc::new(func1);
|
||||||
|
let func2 = Arc::new(func2);
|
||||||
|
move |(item_state, transaction), input| {
|
||||||
|
let input = input.clone();
|
||||||
|
let func1 = func1.clone();
|
||||||
|
let func2 = func2.clone();
|
||||||
|
Box::pin(async move {
|
||||||
|
let ((item_state, transaction), result1) = func1((item_state, transaction), input.clone()).await?;
|
||||||
|
let ((item_state, transaction), result2) = func2((item_state, transaction), input).await?;
|
||||||
|
|
||||||
|
Ok(((item_state, transaction), (result1, result2)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn add_item_to_inventory<EG, TR>(
|
pub(super) fn add_item_to_inventory<EG, TR>(
|
||||||
character: CharacterEntity,
|
character: CharacterEntity,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
@ -994,3 +1033,86 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(super) fn apply_item_action_packets<EG, TR>(
|
||||||
|
character_id: CharacterEntityId,
|
||||||
|
area_client: AreaClient,
|
||||||
|
) -> impl Fn((ItemStateProxy, TR), ApplyItemAction)
|
||||||
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<SendShipPacket>), ItemStateError>>
|
||||||
|
where
|
||||||
|
EG: EntityGateway,
|
||||||
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
|
{
|
||||||
|
move |(mut item_state, mut transaction), apply_item_action| {
|
||||||
|
Box::pin(async move {
|
||||||
|
let pkts = if let ApplyItemAction::CreateItem(item_detail) = apply_item_action {
|
||||||
|
let new_item = transaction.gateway().create_item(NewItemEntity {
|
||||||
|
item: item_detail.clone(),
|
||||||
|
}).await?;
|
||||||
|
|
||||||
|
let item_id = item_state.new_item_id().await?;
|
||||||
|
|
||||||
|
let (inventory_item_detail, create_item) = if item_detail.is_stackable() {
|
||||||
|
let tool = item_detail.as_tool().ok_or_else(|| ItemStateError::NotATool(ClientItemId(0xFFFFFFFF)))?;
|
||||||
|
|
||||||
|
let create_item = builder::message::create_stacked_item(area_client, item_id, &tool, 1).map_err(|_err| ItemStateError::Dummy)?;
|
||||||
|
let item_detail = StackedItemDetail {
|
||||||
|
entity_ids: vec![new_item.id],
|
||||||
|
tool
|
||||||
|
};
|
||||||
|
(InventoryItemDetail::Stacked(item_detail), create_item)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let item_detail = IndividualItemDetail {
|
||||||
|
entity_id: new_item.id,
|
||||||
|
item: item_detail,
|
||||||
|
};
|
||||||
|
let create_item = builder::message::create_individual_item(area_client, item_id, &item_detail).map_err(|_err| ItemStateError::Dummy)?;
|
||||||
|
(InventoryItemDetail::Individual(item_detail), create_item)
|
||||||
|
};
|
||||||
|
|
||||||
|
let inventory_item = InventoryItem {
|
||||||
|
item_id,
|
||||||
|
item: inventory_item_detail,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut inventory = item_state.inventory(&character_id).await?;
|
||||||
|
inventory.add_item(inventory_item)?;
|
||||||
|
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
|
||||||
|
item_state.set_inventory(inventory).await;
|
||||||
|
|
||||||
|
vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(((item_state, transaction), pkts))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn apply_item_action_character<EG, TR>(
|
||||||
|
character: &CharacterEntity
|
||||||
|
) -> impl Fn((ItemStateProxy, TR), Vec<ApplyItemAction>)
|
||||||
|
-> BoxFuture<Result<((ItemStateProxy, TR), CharacterEntity), ItemStateError>>
|
||||||
|
where
|
||||||
|
EG: EntityGateway,
|
||||||
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
|
{
|
||||||
|
let character = character.clone();
|
||||||
|
move |(item_state, transaction), apply_item_actions| {
|
||||||
|
let mut character = character.clone();
|
||||||
|
Box::pin(async move {
|
||||||
|
for action in apply_item_actions {
|
||||||
|
match action {
|
||||||
|
ApplyItemAction::UpdateCharacter(new_character) => character = *new_character,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(((item_state, transaction), character))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,10 +2,12 @@ use std::convert::TryInto;
|
|||||||
use futures::future::{join_all, BoxFuture, LocalBoxFuture};
|
use futures::future::{join_all, BoxFuture, LocalBoxFuture};
|
||||||
use futures::stream::{FuturesOrdered, StreamExt};
|
use futures::stream::{FuturesOrdered, StreamExt};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
|
use rand::distributions::{WeightedIndex, Distribution};
|
||||||
use crate::entity::gateway::{EntityGateway, GatewayError};
|
use crate::entity::gateway::{EntityGateway, GatewayError};
|
||||||
use crate::entity::character::CharacterEntity;
|
use crate::entity::character::CharacterEntity;
|
||||||
use crate::entity::item::mag::{MagCell, MagCellError};
|
use crate::entity::item::mag::{MagType, MagCell, MagCellError};
|
||||||
use crate::entity::item::tool::ToolType;
|
use crate::entity::item::tool::{Tool, ToolType};
|
||||||
use crate::entity::item::{ItemDetail, ItemEntityId};
|
use crate::entity::item::{ItemDetail, ItemEntityId};
|
||||||
use crate::ship::items::state::{ItemStateProxy, ItemStateError};
|
use crate::ship::items::state::{ItemStateProxy, ItemStateError};
|
||||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||||
@ -29,9 +31,12 @@ pub enum ApplyItemError {
|
|||||||
MagCellError(#[from] MagCellError),
|
MagCellError(#[from] MagCellError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum ApplyItemAction {
|
pub enum ApplyItemAction {
|
||||||
UpdateCharacter(CharacterEntity),
|
UpdateCharacter(Box<CharacterEntity>),
|
||||||
CreateItem(()),
|
CreateItem(ItemDetail),
|
||||||
|
//TransformItem,
|
||||||
|
//RemoveItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ItemStateError> for ApplyItemError {
|
impl From<ItemStateError> for ApplyItemError {
|
||||||
@ -43,43 +48,43 @@ impl From<ItemStateError> for ApplyItemError {
|
|||||||
async fn power_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
async fn power_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
||||||
character.materials.power += 1;
|
character.materials.power += 1;
|
||||||
entity_gateway.save_character(character).await?;
|
entity_gateway.save_character(character).await?;
|
||||||
Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())])
|
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn mind_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
async fn mind_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
||||||
character.materials.mind += 1;
|
character.materials.mind += 1;
|
||||||
entity_gateway.save_character(character).await.unwrap();
|
entity_gateway.save_character(character).await.unwrap();
|
||||||
Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())])
|
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn evade_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
async fn evade_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
||||||
character.materials.evade += 1;
|
character.materials.evade += 1;
|
||||||
entity_gateway.save_character(character).await.unwrap();
|
entity_gateway.save_character(character).await.unwrap();
|
||||||
Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())])
|
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn def_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
async fn def_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
||||||
character.materials.def += 1;
|
character.materials.def += 1;
|
||||||
entity_gateway.save_character(character).await.unwrap();
|
entity_gateway.save_character(character).await.unwrap();
|
||||||
Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())])
|
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn luck_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
async fn luck_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
||||||
character.materials.luck += 1;
|
character.materials.luck += 1;
|
||||||
entity_gateway.save_character(character).await.unwrap();
|
entity_gateway.save_character(character).await.unwrap();
|
||||||
Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())])
|
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn hp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
async fn hp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
||||||
character.materials.hp += 1;
|
character.materials.hp += 1;
|
||||||
entity_gateway.save_character(character).await.unwrap();
|
entity_gateway.save_character(character).await.unwrap();
|
||||||
Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())])
|
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn tp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
async fn tp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> {
|
||||||
character.materials.tp += 1;
|
character.materials.tp += 1;
|
||||||
entity_gateway.save_character(character).await.unwrap();
|
entity_gateway.save_character(character).await.unwrap();
|
||||||
Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())])
|
Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -224,13 +229,23 @@ pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async fn jack_o_lantern<'a, EG>(item_state: &mut ItemStateProxy,
|
|
||||||
entity_gateway: &mut EG
|
fn jack_o_lantern() -> Result<Vec<ApplyItemAction>, ApplyItemError>
|
||||||
) -> Result<Vec<ApplyItemAction>, ApplyItemError>
|
|
||||||
where
|
|
||||||
EG: EntityGateway + ?Sized,
|
|
||||||
{
|
{
|
||||||
Ok(Vec::new())
|
let mag_rate = WeightedIndex::new(&[13, 13, 13, 13, 12, 12, 12, 12]).unwrap();
|
||||||
|
let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) {
|
||||||
|
0 => ToolType::CellOfMag502,
|
||||||
|
1 => ToolType::CellOfMag213,
|
||||||
|
2 => ToolType::HeartOfChuChu,
|
||||||
|
3 => ToolType::HeartOfKapuKapu,
|
||||||
|
4 => ToolType::PartsOfRobochao,
|
||||||
|
5 => ToolType::HeartOfOpaOpa,
|
||||||
|
6 => ToolType::HeartOfPian,
|
||||||
|
7 => ToolType::HeartOfChao,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(vec![ApplyItemAction::CreateItem(ItemDetail::Tool(Tool {tool: mag_type}))])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy,
|
async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy,
|
||||||
@ -283,7 +298,7 @@ where
|
|||||||
| ToolType::LibertaKit => {
|
| ToolType::LibertaKit => {
|
||||||
mag_cell(item_state, entity_gateway, character, entity_id, tool.try_into()?).await
|
mag_cell(item_state, entity_gateway, character, entity_id, tool.try_into()?).await
|
||||||
}
|
}
|
||||||
ToolType::JackOLantern => jack_o_lantern(item_state, entity_gateway).await,
|
ToolType::JackOLantern => jack_o_lantern(),
|
||||||
// TODO: rest of these
|
// TODO: rest of these
|
||||||
_ => Err(ApplyItemError::InvalidItem)
|
_ => Err(ApplyItemError::InvalidItem)
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ pub enum InventoryError {
|
|||||||
MesetaFull,
|
MesetaFull,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct InventoryState {
|
pub struct InventoryState {
|
||||||
pub character_id: CharacterEntityId,
|
pub character_id: CharacterEntityId,
|
||||||
pub item_id_counter: u32,
|
pub item_id_counter: u32,
|
||||||
|
@ -124,7 +124,7 @@ pub enum AddItemResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ItemState {
|
pub struct ItemState {
|
||||||
character_inventory: Arc<RwLock<HashMap<CharacterEntityId, RwLock<InventoryState>>>>,
|
character_inventory: Arc<RwLock<HashMap<CharacterEntityId, RwLock<InventoryState>>>>,
|
||||||
character_bank: Arc<RwLock<HashMap<CharacterEntityId, RwLock<BankState>>>>,
|
character_bank: Arc<RwLock<HashMap<CharacterEntityId, RwLock<BankState>>>>,
|
||||||
|
@ -272,22 +272,28 @@ pub async fn use_item<'a, EG> (
|
|||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &mut CharacterEntity,
|
character: &mut CharacterEntity,
|
||||||
|
area_client: AreaClient,
|
||||||
item_id: &ClientItemId,
|
item_id: &ClientItemId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> Result<(), ItemStateError>
|
) -> Result<Vec<SendShipPacket>, ItemStateError>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(|transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), apply_item_actions) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), (pkts, new_character)) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
||||||
.act(actions::use_consumed_item(character.clone()))
|
.act(actions::use_consumed_item(&character))
|
||||||
|
.act(actions::fork(
|
||||||
|
actions::foreach(actions::apply_item_action_packets(character.id, area_client)),
|
||||||
|
actions::apply_item_action_character(character)
|
||||||
|
))
|
||||||
.commit((item_state_proxy, transaction))
|
.commit((item_state_proxy, transaction))
|
||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
|
|
||||||
*character = new_character;
|
*character = new_character;
|
||||||
Ok((transaction, ()))
|
Ok((transaction, pkts.into_iter().flatten().collect()))
|
||||||
}).await
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,20 +330,32 @@ where
|
|||||||
pub async fn player_uses_item<EG>(id: ClientId,
|
pub async fn player_uses_item<EG>(id: ClientId,
|
||||||
player_use_tool: PlayerUseItem,
|
player_use_tool: PlayerUseItem,
|
||||||
entity_gateway: &mut EG,
|
entity_gateway: &mut EG,
|
||||||
_client_location: &ClientLocation,
|
client_location: &ClientLocation,
|
||||||
clients: &Clients,
|
clients: &Clients,
|
||||||
item_state: &mut ItemState)
|
item_state: &mut ItemState)
|
||||||
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError>
|
-> Result<Vec<(ClientId, SendShipPacket)>, ShipError>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + Clone + 'static,
|
EG: EntityGateway + Clone + 'static,
|
||||||
{
|
{
|
||||||
clients.with_mut(id, |client| {
|
let neighbors = client_location.get_all_clients_by_client(id).await?.into_iter();
|
||||||
|
let area_client = client_location.get_local_client(id).await?;
|
||||||
|
|
||||||
|
Ok(clients.with_mut(id, |client| {
|
||||||
let mut entity_gateway = entity_gateway.clone();
|
let mut entity_gateway = entity_gateway.clone();
|
||||||
let mut item_state = item_state.clone();
|
let mut item_state = item_state.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
use_item(&mut item_state, &mut entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await
|
use_item(&mut item_state, &mut entity_gateway, &mut client.character, area_client, &ClientItemId(player_use_tool.item_id), 1).await
|
||||||
})}).await??;
|
})}).await??
|
||||||
Ok(Vec::new())
|
.into_iter()
|
||||||
|
.flat_map(move |pkt| {
|
||||||
|
let player_use_tool = player_use_tool.clone();
|
||||||
|
neighbors.clone().map(move |client| {
|
||||||
|
vec![(client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUseItem(player_use_tool.clone())))), (client.client, pkt.clone())]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn player_used_medical_center<EG>(id: ClientId,
|
pub async fn player_used_medical_center<EG>(id: ClientId,
|
||||||
|
@ -251,6 +251,59 @@ async fn test_use_materials() {
|
|||||||
assert!(char.materials.luck == 2);
|
assert!(char.materials.luck == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_jackolantern() {
|
||||||
|
let mut entity_gateway = InMemoryGateway::default();
|
||||||
|
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
|
||||||
|
|
||||||
|
let p1_inv = vec![
|
||||||
|
item::InventoryItemEntity::Stacked(
|
||||||
|
vec![
|
||||||
|
entity_gateway.create_item(
|
||||||
|
item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: item::tool::ToolType::JackOLantern,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap(),
|
||||||
|
entity_gateway.create_item(item::NewItemEntity {
|
||||||
|
item: item::ItemDetail::Tool(
|
||||||
|
item::tool::Tool {
|
||||||
|
tool: item::tool::ToolType::JackOLantern,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}).await.unwrap(),
|
||||||
|
])];
|
||||||
|
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
|
||||||
|
|
||||||
|
let mut ship = Box::new(ShipServerState::builder()
|
||||||
|
.gateway(entity_gateway.clone())
|
||||||
|
.build());
|
||||||
|
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
|
||||||
|
join_lobby(&mut ship, ClientId(1)).await;
|
||||||
|
create_room(&mut ship, ClientId(1), "room", "").await;
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10000,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem {
|
||||||
|
client: 0,
|
||||||
|
target: 0,
|
||||||
|
item_id: 0x10000,
|
||||||
|
})))).await.unwrap();
|
||||||
|
|
||||||
|
let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
|
||||||
|
for item in inventory_items.items {
|
||||||
|
for sitem in item.stacked().unwrap() {
|
||||||
|
assert!(sitem.item.clone().as_tool().unwrap().tool.is_mag_cell());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: tests for ALL ITEMS WOW
|
// TODO: tests for ALL ITEMS WOW
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1792,7 +1792,7 @@ async fn test_trade_multiple_individual() {
|
|||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 1,
|
client: 1,
|
||||||
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
|
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
|
||||||
item_id: 0x810003,
|
item_id: 0x810004,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -1801,7 +1801,7 @@ async fn test_trade_multiple_individual() {
|
|||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 1,
|
client: 1,
|
||||||
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
|
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
|
||||||
item_id: 0x810003,
|
item_id: 0x810004,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -1810,7 +1810,7 @@ async fn test_trade_multiple_individual() {
|
|||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 1,
|
client: 1,
|
||||||
item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
|
item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
|
||||||
item_id: 0x810004,
|
item_id: 0x810003,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -1819,7 +1819,7 @@ async fn test_trade_multiple_individual() {
|
|||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 1,
|
client: 1,
|
||||||
item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
|
item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
|
||||||
item_id: 0x810004,
|
item_id: 0x810003,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -1828,7 +1828,7 @@ async fn test_trade_multiple_individual() {
|
|||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
|
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
|
||||||
item_id: 0x810001,
|
item_id: 0x810002,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -1837,7 +1837,7 @@ async fn test_trade_multiple_individual() {
|
|||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
|
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
|
||||||
item_id: 0x810001,
|
item_id: 0x810002,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -1846,7 +1846,7 @@ async fn test_trade_multiple_individual() {
|
|||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
|
item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
|
||||||
item_id: 0x810002,
|
item_id: 0x810001,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -1855,7 +1855,7 @@ async fn test_trade_multiple_individual() {
|
|||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
|
item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
|
||||||
item_id: 0x810002,
|
item_id: 0x810001,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -2063,7 +2063,7 @@ async fn test_trade_multiple_stacked() {
|
|||||||
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
|
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
|
||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 1,
|
client: 1,
|
||||||
item_id: 0x810003,
|
item_id: 0x810004,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -2071,7 +2071,7 @@ async fn test_trade_multiple_stacked() {
|
|||||||
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
|
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
|
||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 1,
|
client: 1,
|
||||||
item_id: 0x810003,
|
item_id: 0x810004,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -2079,7 +2079,7 @@ async fn test_trade_multiple_stacked() {
|
|||||||
assert!(matches!(ack[6], (ClientId(1), SendShipPacket::Message(Message {
|
assert!(matches!(ack[6], (ClientId(1), SendShipPacket::Message(Message {
|
||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 1,
|
client: 1,
|
||||||
item_id: 0x810004,
|
item_id: 0x810003,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -2087,7 +2087,7 @@ async fn test_trade_multiple_stacked() {
|
|||||||
assert!(matches!(ack[7], (ClientId(2), SendShipPacket::Message(Message {
|
assert!(matches!(ack[7], (ClientId(2), SendShipPacket::Message(Message {
|
||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 1,
|
client: 1,
|
||||||
item_id: 0x810004,
|
item_id: 0x810003,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -2095,7 +2095,7 @@ async fn test_trade_multiple_stacked() {
|
|||||||
assert!(matches!(ack[8], (ClientId(1), SendShipPacket::Message(Message {
|
assert!(matches!(ack[8], (ClientId(1), SendShipPacket::Message(Message {
|
||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
item_id: 0x810001,
|
item_id: 0x810002,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -2103,7 +2103,7 @@ async fn test_trade_multiple_stacked() {
|
|||||||
assert!(matches!(ack[9], (ClientId(2), SendShipPacket::Message(Message {
|
assert!(matches!(ack[9], (ClientId(2), SendShipPacket::Message(Message {
|
||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
item_id: 0x810001,
|
item_id: 0x810002,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -2111,7 +2111,7 @@ async fn test_trade_multiple_stacked() {
|
|||||||
assert!(matches!(ack[10], (ClientId(1), SendShipPacket::Message(Message {
|
assert!(matches!(ack[10], (ClientId(1), SendShipPacket::Message(Message {
|
||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
item_id: 0x810002,
|
item_id: 0x810001,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
@ -2119,7 +2119,7 @@ async fn test_trade_multiple_stacked() {
|
|||||||
assert!(matches!(ack[11], (ClientId(2), SendShipPacket::Message(Message {
|
assert!(matches!(ack[11], (ClientId(2), SendShipPacket::Message(Message {
|
||||||
msg: GameMessage::CreateItem(CreateItem {
|
msg: GameMessage::CreateItem(CreateItem {
|
||||||
client: 0,
|
client: 0,
|
||||||
item_id: 0x810002,
|
item_id: 0x810001,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
|
Loading…
x
Reference in New Issue
Block a user