You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

395 lines
18 KiB

2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
1 year ago
1 year ago
1 year ago
2 years ago
1 year ago
2 years ago
  1. use std::convert::TryInto;
  2. use futures::future::join_all;
  3. use thiserror::Error;
  4. use anyhow::Context;
  5. use rand::SeedableRng;
  6. use rand::distributions::{WeightedIndex, Distribution};
  7. use entity::gateway::{EntityGateway, GatewayError};
  8. use entity::character::{CharacterEntity, TechLevel};
  9. use entity::item::mag::{MagCell, MagCellError};
  10. use entity::item::tool::{Tool, ToolType};
  11. use entity::item::tech::TechniqueDisk;
  12. use entity::item::{ItemDetail, ItemEntityId};
  13. use entity::item::weapon::WeaponModifier;
  14. use crate::state::ItemStateProxy;
  15. use crate::inventory::InventoryItemDetail;
  16. #[derive(Error, Debug)]
  17. pub enum ApplyItemError {
  18. #[error("no character")]
  19. NoCharacter,
  20. #[error("item not equipped")]
  21. ItemNotEquipped,
  22. #[error("could not use item invalid item")]
  23. InvalidItem,
  24. #[error("invalid tool")]
  25. InvalidTool,
  26. #[error("gateway error {0}")]
  27. GatewayError(#[from] GatewayError),
  28. #[error("magcell error {0}")]
  29. MagCellError(#[from] MagCellError),
  30. }
  31. #[derive(Debug, Clone)]
  32. pub enum ApplyItemAction {
  33. UpdateCharacter(Box<CharacterEntity>),
  34. CreateItem(ItemDetail),
  35. //TransformItem(ItemDetail),
  36. //RemoveItem,
  37. }
  38. async fn power_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, anyhow::Error> {
  39. character.materials.power += 1;
  40. entity_gateway.save_character(character).await?;
  41. Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
  42. }
  43. async fn mind_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, anyhow::Error> {
  44. character.materials.mind += 1;
  45. entity_gateway.save_character(character).await.unwrap();
  46. Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
  47. }
  48. async fn evade_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, anyhow::Error> {
  49. character.materials.evade += 1;
  50. entity_gateway.save_character(character).await.unwrap();
  51. Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
  52. }
  53. async fn def_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, anyhow::Error> {
  54. character.materials.def += 1;
  55. entity_gateway.save_character(character).await.unwrap();
  56. Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
  57. }
  58. async fn luck_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, anyhow::Error> {
  59. character.materials.luck += 1;
  60. entity_gateway.save_character(character).await.unwrap();
  61. Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
  62. }
  63. async fn hp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, anyhow::Error> {
  64. character.materials.hp += 1;
  65. entity_gateway.save_character(character).await.unwrap();
  66. Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
  67. }
  68. async fn tp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, anyhow::Error> {
  69. character.materials.tp += 1;
  70. entity_gateway.save_character(character).await.unwrap();
  71. Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
  72. }
  73. /*
  74. async fn mag_cell<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory, mag_cell_type: MagCell) -> Result<(), ApplyItemError> {
  75. let mut mag_handle = inventory.get_equipped_mag_handle().ok_or(ApplyItemError::ItemNotEquipped)?;
  76. let mag_item = mag_handle.item_mut()
  77. .ok_or(ApplyItemError::InvalidItem)?;
  78. let actual_mag = mag_item
  79. .individual_mut()
  80. .ok_or(ApplyItemError::InvalidItem)?
  81. .mag_mut()
  82. .ok_or(ApplyItemError::InvalidItem)?;
  83. actual_mag.apply_mag_cell(mag_cell_type);
  84. for mag_entity_id in mag_item.entity_ids() {
  85. for cell_entity_id in used_cell.entity_ids() {
  86. entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await.unwrap();
  87. }
  88. }
  89. Ok(())
  90. }
  91. */
  92. async fn mag_cell<'a, EG>(item_state: &mut ItemStateProxy,
  93. entity_gateway: &mut EG,
  94. character: &CharacterEntity,
  95. cell_entity_id: ItemEntityId,
  96. mag_cell_type: MagCell)
  97. -> Result<Vec<ApplyItemAction>, anyhow::Error>
  98. where
  99. EG: EntityGateway + ?Sized,
  100. {
  101. let mut inventory = item_state.inventory(&character.id).await?;
  102. let (mag_entity_id, mag) = inventory.equipped_mag_mut()
  103. .ok_or(ApplyItemError::ItemNotEquipped)?;
  104. mag.apply_mag_cell(mag_cell_type)?;
  105. entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await?;
  106. entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?;
  107. item_state.set_inventory(inventory).await;
  108. Ok(Vec::new())
  109. }
  110. /*
  111. pub async fn cell_of_mag_502<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  112. mag_cell(entity_gateway, inventory, MagCell::CellOfMag502).await
  113. }
  114. pub async fn cell_of_mag_213<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  115. mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag213).await
  116. }
  117. pub async fn parts_of_robochao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  118. mag_cell(entity_gateway, used_cell, inventory, MagCell::PartsOfRobochao).await
  119. }
  120. pub async fn heart_of_opaopa<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  121. mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfOpaOpa).await
  122. }
  123. pub async fn heart_of_pian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  124. mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfPian).await
  125. }
  126. pub async fn heart_of_chao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  127. mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfChao).await
  128. }
  129. pub async fn heart_of_angel<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  130. mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfAngel).await
  131. }
  132. pub async fn kit_of_hamburger<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  133. mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfHamburger).await
  134. }
  135. pub async fn panthers_spirit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  136. mag_cell(entity_gateway, used_cell, inventory, MagCell::PanthersSpirit).await
  137. }
  138. pub async fn kit_of_mark3<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  139. mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMark3).await
  140. }
  141. pub async fn kit_of_master_system<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  142. mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMasterSystem).await
  143. }
  144. pub async fn kit_of_genesis<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  145. mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfGenesis).await
  146. }
  147. pub async fn kit_of_sega_saturn<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  148. mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfSegaSaturn).await
  149. }
  150. pub async fn kit_of_dreamcast<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  151. mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfDreamcast).await
  152. }
  153. pub async fn tablet<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  154. mag_cell(entity_gateway, used_cell, inventory, MagCell::Tablet).await
  155. }
  156. pub async fn dragon_scale<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  157. mag_cell(entity_gateway, used_cell, inventory, MagCell::DragonScale).await
  158. }
  159. pub async fn heaven_striker_coat<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  160. mag_cell(entity_gateway, used_cell, inventory, MagCell::HeavenStrikerCoat).await
  161. }
  162. pub async fn pioneer_parts<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  163. mag_cell(entity_gateway, used_cell, inventory, MagCell::PioneerParts).await
  164. }
  165. pub async fn amities_memo<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  166. mag_cell(entity_gateway, used_cell, inventory, MagCell::AmitiesMemo).await
  167. }
  168. pub async fn heart_of_morolian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  169. mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfMorolian).await
  170. }
  171. pub async fn rappys_beak<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  172. mag_cell(entity_gateway, used_cell, inventory, MagCell::RappysBeak).await
  173. }
  174. pub async fn yahoos_engine<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  175. mag_cell(entity_gateway, used_cell, inventory, MagCell::YahoosEngine).await
  176. }
  177. pub async fn d_photon_core<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  178. mag_cell(entity_gateway, used_cell, inventory, MagCell::DPhotonCore).await
  179. }
  180. pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> {
  181. mag_cell(entity_gateway, used_cell, inventory, MagCell::LibertaKit).await
  182. }
  183. */
  184. fn jack_o_lantern() -> Result<Vec<ApplyItemAction>, anyhow::Error>
  185. {
  186. let mag_rate = WeightedIndex::new([13, 13, 13, 13, 12, 12, 12, 12]).unwrap();
  187. let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) {
  188. 0 => ToolType::CellOfMag502,
  189. 1 => ToolType::CellOfMag213,
  190. 2 => ToolType::HeartOfChuChu,
  191. 3 => ToolType::HeartOfKapuKapu,
  192. 4 => ToolType::PartsOfRobochao,
  193. 5 => ToolType::HeartOfOpaOpa,
  194. 6 => ToolType::HeartOfPian,
  195. 7 => ToolType::HeartOfChao,
  196. _ => unreachable!(),
  197. };
  198. Ok(vec![ApplyItemAction::CreateItem(ItemDetail::Tool(Tool {tool: mag_type}))])
  199. }
  200. async fn weapon_grind<'a, EG>(item_state: &mut ItemStateProxy,
  201. entity_gateway: &mut EG,
  202. character: &mut CharacterEntity,
  203. entity_id: ItemEntityId,
  204. grind: u32,)
  205. -> Result<Vec<ApplyItemAction>, anyhow::Error>
  206. where
  207. EG: EntityGateway + ?Sized,
  208. {
  209. let modifier = WeaponModifier::AddGrind {
  210. amount: grind,
  211. grinder: entity_id,
  212. };
  213. let mut inventory = item_state.inventory(&character.id).await?;
  214. let (weapon_entity_id, weapon) = inventory.equipped_weapon_mut()
  215. .ok_or(ApplyItemError::ItemNotEquipped)?;
  216. weapon.apply_modifier(&modifier);
  217. entity_gateway.add_weapon_modifier(&weapon_entity_id, &modifier).await?;
  218. item_state.set_inventory(inventory).await;
  219. Ok(Vec::new())
  220. }
  221. async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy,
  222. entity_gateway: &mut EG,
  223. character: &mut CharacterEntity,
  224. entity_id: ItemEntityId,
  225. tool: ToolType)
  226. -> Result<Vec<ApplyItemAction>, anyhow::Error>
  227. where
  228. EG: EntityGateway + ?Sized,
  229. {
  230. match tool {
  231. ToolType::PowerMaterial => power_material(entity_gateway, character).await,
  232. ToolType::MindMaterial => mind_material(entity_gateway, character).await,
  233. ToolType::EvadeMaterial => evade_material(entity_gateway, character).await,
  234. ToolType::DefMaterial => def_material(entity_gateway, character).await,
  235. ToolType::LuckMaterial => luck_material(entity_gateway, character).await,
  236. ToolType::HpMaterial => hp_material(entity_gateway, character).await,
  237. ToolType::TpMaterial => tp_material(entity_gateway, character).await,
  238. ToolType::Monomate => Ok(Vec::new()),
  239. ToolType::Dimate => Ok(Vec::new()),
  240. ToolType::Trimate => Ok(Vec::new()),
  241. ToolType::Monofluid => Ok(Vec::new()),
  242. ToolType::Difluid => Ok(Vec::new()),
  243. ToolType::Trifluid => Ok(Vec::new()),
  244. ToolType::SolAtomizer => Ok(Vec::new()),
  245. ToolType::MoonAtomizer => Ok(Vec::new()),
  246. ToolType::StarAtomizer => Ok(Vec::new()),
  247. ToolType::Telepipe => Ok(Vec::new()),
  248. ToolType::Antidote => Ok(Vec::new()),
  249. ToolType::Antiparalysis => Ok(Vec::new()),
  250. ToolType::TrapVision => Ok(Vec::new()),
  251. ToolType::ScapeDoll => Ok(Vec::new()),
  252. ToolType::Monogrinder => weapon_grind(item_state, entity_gateway, character, entity_id, 1).await,
  253. ToolType::Digrinder => weapon_grind(item_state, entity_gateway, character, entity_id, 2).await,
  254. ToolType::Trigrinder => weapon_grind(item_state, entity_gateway, character, entity_id, 3).await,
  255. ToolType::HuntersReport => Ok(Vec::new()),
  256. ToolType::CellOfMag502
  257. | ToolType::CellOfMag213
  258. | ToolType::PartsOfRobochao
  259. | ToolType::HeartOfOpaOpa
  260. | ToolType::HeartOfPian
  261. | ToolType::HeartOfChao
  262. | ToolType::HeartOfAngel
  263. | ToolType::KitOfHamburger
  264. | ToolType::PanthersSpirit
  265. | ToolType::KitOfMark3
  266. | ToolType::KitOfMasterSystem
  267. | ToolType::KitOfGenesis
  268. | ToolType::KitOfSegaSaturn
  269. | ToolType::KitOfDreamcast
  270. | ToolType::Tablet
  271. | ToolType::DragonScale
  272. | ToolType::HeavenStrikerCoat
  273. | ToolType::PioneerParts
  274. | ToolType::AmitiesMemo
  275. | ToolType::HeartOfMorolian
  276. | ToolType::RappysBeak
  277. | ToolType::YahoosEngine
  278. | ToolType::DPhotonCore
  279. | ToolType::LibertaKit => {
  280. mag_cell(item_state, entity_gateway, character, entity_id, tool.try_into()?).await
  281. }
  282. ToolType::JackOLantern => jack_o_lantern(),
  283. // TODO: rest of these
  284. _ => Err(anyhow::Error::from(ApplyItemError::InvalidTool))
  285. .with_context(|| {
  286. format!("invalid tool {tool:?}")
  287. })
  288. }
  289. }
  290. async fn apply_tech<'a, EG>(_item_state: &mut ItemStateProxy,
  291. entity_gateway: &mut EG,
  292. character: &mut CharacterEntity,
  293. _entity_id: ItemEntityId,
  294. tech: TechniqueDisk)
  295. -> Result<Vec<ApplyItemAction>, anyhow::Error>
  296. where
  297. EG: EntityGateway + ?Sized,
  298. {
  299. // TODO: make sure the class can learn that specific tech
  300. character.techs.set_tech(tech.tech, TechLevel(tech.level as u8));
  301. entity_gateway.save_character(character).await.unwrap();
  302. Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))])
  303. }
  304. pub async fn apply_item<'a, EG>(item_state: &'a mut ItemStateProxy,
  305. entity_gateway: &'a mut EG,
  306. character: &'a mut CharacterEntity,
  307. item: InventoryItemDetail
  308. ) -> Result<Vec<ApplyItemAction>, anyhow::Error>
  309. where
  310. EG: EntityGateway + ?Sized + Clone + 'a
  311. {
  312. match item {
  313. InventoryItemDetail::Individual(individual_item) => {
  314. match individual_item.item {
  315. ItemDetail::Tool(tool) => apply_tool(item_state, entity_gateway, character, individual_item.entity_id, tool.tool).await,
  316. ItemDetail::TechniqueDisk(tech) => apply_tech(item_state, entity_gateway, character, individual_item.entity_id, tech).await,
  317. _ => Err(anyhow::Error::from(ApplyItemError::InvalidItem))
  318. .with_context(|| {
  319. format!("item {individual_item:?}")
  320. })
  321. }
  322. },
  323. InventoryItemDetail::Stacked(stacked_item) => {
  324. Ok(join_all(stacked_item.entity_ids.iter()
  325. .map(|entity_id| {
  326. let mut entity_gateway = entity_gateway.clone();
  327. let mut character = character.clone();
  328. let mut item_state = item_state.clone();
  329. async move {
  330. apply_tool(&mut item_state, &mut entity_gateway, &mut character, *entity_id, stacked_item.tool.tool).await
  331. }
  332. })
  333. .collect::<Vec<_>>())
  334. .await
  335. .into_iter()
  336. .collect::<Result<Vec<Vec<_>>, _>>()?
  337. .into_iter()
  338. .flatten()
  339. .collect())
  340. },
  341. }
  342. }