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.

537 lines
24 KiB

2 years ago
4 years ago
2 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
2 years ago
2 years ago
4 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
4 years ago
4 years ago
2 years ago
2 years ago
4 years ago
4 years ago
4 years ago
3 years ago
2 years ago
2 years ago
3 years ago
2 years ago
3 years ago
2 years ago
  1. use libpso::packet::ship::*;
  2. use libpso::packet::messages::*;
  3. use entity::gateway::EntityGateway;
  4. use entity::item::Meseta;
  5. use networking::serverstate::ClientId;
  6. use stats::leveltable::LEVEL_TABLE;
  7. use crate::ship::ship::{SendShipPacket, ShipError};
  8. use client::{Clients, ItemDropLocation};
  9. use ::room::Rooms;
  10. use location::{ClientLocation, ClientLocationError};
  11. use items::ClientItemId;
  12. use pktbuilder as builder;
  13. use items::state::ItemState;
  14. use items::tasks::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item, take_meseta, floor_item_limit_reached};
  15. pub async fn request_exp<EG>(id: ClientId,
  16. request_exp: RequestExp,
  17. entity_gateway: &mut EG,
  18. client_location: &ClientLocation,
  19. clients: &Clients,
  20. rooms: &Rooms)
  21. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  22. where
  23. EG: EntityGateway + Clone + 'static,
  24. {
  25. let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  26. let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  27. let enemy_id = request_exp.enemy_id as usize;
  28. let enemy_exp = rooms.with(room_id, |room| Box::pin(async move {
  29. let monster = room.maps.enemy_by_id(enemy_id)?;
  30. let monster_stats = room.monster_stats.get(&monster.monster).ok_or_else(|| ShipError::UnknownMonster(monster.monster))?;
  31. Ok::<_, anyhow::Error>(monster_stats.exp)
  32. })).await??;
  33. let exp_gain = if request_exp.last_hitter == 1 {
  34. enemy_exp
  35. }
  36. else {
  37. ((enemy_exp as f32) * 0.8) as u32
  38. };
  39. let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  40. let gain_exp_pkt = builder::message::character_gained_exp(area_client, exp_gain);
  41. let mut exp_pkts: Vec<_> = clients_in_area.clone().into_iter()
  42. .map(move |c| {
  43. (c.client, SendShipPacket::Message(Message::new(GameMessage::GiveCharacterExp(gain_exp_pkt.clone()))))
  44. })
  45. .collect();
  46. let (char_class, exp) = clients.with(id, |client| Box::pin(async move {
  47. (client.character.char_class, client.character.exp)
  48. })).await?;
  49. let before_level = LEVEL_TABLE.get_level_from_exp(char_class, exp);
  50. let after_level = LEVEL_TABLE.get_level_from_exp(char_class, exp + exp_gain);
  51. let level_up = before_level != after_level;
  52. if level_up {
  53. let (_, before_stats) = LEVEL_TABLE.get_stats_from_exp(char_class, exp);
  54. let (after_level, after_stats) = LEVEL_TABLE.get_stats_from_exp(char_class, exp + exp_gain);
  55. let level_up_pkt = builder::message::character_leveled_up(area_client, after_level-1, before_stats, after_stats);
  56. exp_pkts.extend(clients_in_area.into_iter()
  57. .map(move |c| {
  58. (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerLevelUp(level_up_pkt.clone()))))
  59. }));
  60. }
  61. clients.with_mut(id, |client| {
  62. let mut entity_gateway = entity_gateway.clone();
  63. Box::pin(async move {
  64. client.character.exp += exp_gain;
  65. entity_gateway.save_character(&client.character).await
  66. })}).await??;
  67. Ok(exp_pkts)
  68. }
  69. pub async fn player_drop_item<EG>(id: ClientId,
  70. player_drop_item: PlayerDropItem,
  71. entity_gateway: &mut EG,
  72. client_location: &ClientLocation,
  73. clients: &Clients,
  74. rooms: &Rooms,
  75. item_state: &mut ItemState)
  76. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  77. where
  78. EG: EntityGateway + Clone + 'static,
  79. {
  80. let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  81. let map_area = rooms.with(room_id, |room| Box::pin(async move {
  82. room.map_areas.get_area_map(player_drop_item.map_area)
  83. })).await??;
  84. clients.with(id, |client| {
  85. let mut entity_gateway = entity_gateway.clone();
  86. let mut item_state = item_state.clone();
  87. Box::pin(async move {
  88. drop_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(player_drop_item.item_id), map_area, (player_drop_item.x, player_drop_item.y, player_drop_item.z)).await
  89. })}).await??;
  90. let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  91. let pdi = player_drop_item.clone();
  92. Ok(clients_in_area.into_iter()
  93. .map(move |c| {
  94. (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerDropItem(pdi.clone()))))
  95. })
  96. .collect())
  97. }
  98. pub async fn drop_coordinates(id: ClientId,
  99. drop_coordinates: DropCoordinates,
  100. client_location: &ClientLocation,
  101. clients: &Clients,
  102. rooms: &Rooms)
  103. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  104. {
  105. let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  106. let map_area = rooms.with(room_id, |room| Box::pin(async move {
  107. room.map_areas.get_area_map(drop_coordinates.map_area)
  108. })).await??;
  109. clients.with_mut(id, |client| Box::pin(async move {
  110. client.item_drop_location = Some(ItemDropLocation {
  111. map_area,
  112. x: drop_coordinates.x,
  113. z: drop_coordinates.z,
  114. item_id: ClientItemId(drop_coordinates.item_id),
  115. });
  116. })).await?;
  117. Ok(Vec::new()) // TODO: do we need to send a packet here?
  118. }
  119. pub async fn no_longer_has_item<EG>(id: ClientId,
  120. no_longer_has_item: PlayerNoLongerHasItem,
  121. entity_gateway: &mut EG,
  122. client_location: &ClientLocation,
  123. clients: &Clients,
  124. item_state: &mut ItemState)
  125. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  126. where
  127. EG: EntityGateway + Clone + 'static,
  128. {
  129. //let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
  130. let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  131. let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  132. let (drop_location, tek) = clients.with(id, |client| Box::pin(async move {
  133. (client.item_drop_location, client.tek)
  134. })).await?;
  135. if let Some(drop_location) = drop_location {
  136. if drop_location.item_id.0 != no_longer_has_item.item_id {
  137. return Err(ShipError::DropInvalidItemId(no_longer_has_item.item_id).into());
  138. }
  139. if no_longer_has_item.item_id == 0xFFFFFFFF {
  140. let dropped_meseta = clients.with_mut(id, |client| {
  141. let mut entity_gateway = entity_gateway.clone();
  142. let mut item_state = item_state.clone();
  143. Box::pin(async move {
  144. client.item_drop_location = None;
  145. drop_meseta(&mut item_state, &mut entity_gateway, &client.character, drop_location.map_area, (drop_location.x, drop_location.z), no_longer_has_item.amount).await
  146. })}).await??;
  147. let dropped_meseta_pkt = builder::message::drop_split_meseta_stack(area_client, &dropped_meseta);
  148. let no_longer_has_meseta_pkt = builder::message::player_no_longer_has_meseta(area_client, no_longer_has_item.amount);
  149. let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  150. Ok(clients_in_area.into_iter()
  151. .flat_map(move |c| {
  152. std::iter::once((c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_meseta_pkt.clone())))))
  153. .chain(
  154. if c.client != id {
  155. Box::new(std::iter::once(
  156. (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(no_longer_has_meseta_pkt.clone()))))
  157. )) as Box<dyn Iterator<Item = _> + Send>
  158. }
  159. else {
  160. Box::new(std::iter::empty()) as Box<dyn Iterator<Item = _> + Send>
  161. }
  162. )
  163. })
  164. .collect()
  165. )
  166. }
  167. else {
  168. let dropped_item = clients.with_mut(id, |client| {
  169. let mut entity_gateway = entity_gateway.clone();
  170. let mut item_state = item_state.clone();
  171. Box::pin(async move {
  172. client.item_drop_location = None;
  173. drop_partial_item(&mut item_state,
  174. &mut entity_gateway,
  175. &client.character,
  176. &drop_location.item_id,
  177. drop_location.map_area,
  178. (drop_location.x, drop_location.z),
  179. no_longer_has_item.amount)
  180. .await
  181. })}).await??;
  182. let dropped_item_pkt = builder::message::drop_split_stack(area_client, &dropped_item);
  183. let clients_in_area = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  184. Ok(clients_in_area.into_iter()
  185. .map(move |c| {
  186. (c.client, SendShipPacket::Message(Message::new(GameMessage::DropSplitStack(dropped_item_pkt.clone()))))
  187. })
  188. .collect())
  189. }
  190. }
  191. else if let Some(_tek) = tek {
  192. let neighbors = client_location.get_client_neighbors(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  193. let no_longer_has_item = no_longer_has_item.clone();
  194. Ok(neighbors.into_iter()
  195. .map(move |c| {
  196. (c.client, SendShipPacket::Message(Message::new(GameMessage::PlayerNoLongerHasItem(no_longer_has_item.clone()))))
  197. })
  198. .collect())
  199. }
  200. else {
  201. Err(ShipError::InvalidItem(ClientItemId(no_longer_has_item.item_id)).into())
  202. }
  203. }
  204. pub async fn update_player_position(id: ClientId,
  205. message: Message,
  206. clients: &Clients,
  207. client_location: &ClientLocation,
  208. rooms: &Rooms)
  209. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  210. if let Ok(room_id) = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() }) {
  211. let msg = message.msg.clone();
  212. clients.with_mut(id, |client| {
  213. let rooms = rooms.clone();
  214. Box::pin(async move {
  215. match msg {
  216. GameMessage::PlayerChangedMap(p) => {
  217. client.x = p.x;
  218. client.y = p.y;
  219. client.z = p.z;
  220. },
  221. GameMessage::PlayerChangedMap2(p) => {
  222. client.area = rooms.with(room_id, |room| Box::pin(async move {
  223. room.map_areas.get_area_map(p.map_area).ok()
  224. })).await?;
  225. },
  226. GameMessage::TellOtherPlayerMyLocation(p) => {
  227. client.x = p.x;
  228. client.y = p.y;
  229. client.z = p.z;
  230. client.area = rooms.with(room_id, |room| Box::pin(async move {
  231. room.map_areas.get_area_map(p.map_area).ok()
  232. })).await?;
  233. },
  234. GameMessage::PlayerWarpingToFloor(p) => {
  235. client.area = rooms.with(room_id, |room| Box::pin(async move {
  236. room.map_areas.get_area_map(p.area as u16).ok()
  237. })).await?;
  238. },
  239. GameMessage::PlayerTeleported(p) => {
  240. client.x = p.x;
  241. client.y = p.y;
  242. client.z = p.z;
  243. },
  244. GameMessage::PlayerStopped(p) => {
  245. client.x = p.x;
  246. client.y = p.y;
  247. client.z = p.z;
  248. },
  249. GameMessage::PlayerLoadedIn(p) => {
  250. client.x = p.x;
  251. client.y = p.y;
  252. client.z = p.z;
  253. },
  254. GameMessage::PlayerWalking(p) => {
  255. client.x = p.x;
  256. client.z = p.z;
  257. },
  258. GameMessage::PlayerRunning(p) => {
  259. client.x = p.x;
  260. client.z = p.z;
  261. },
  262. GameMessage::PlayerWarped(p) => {
  263. client.x = p.x;
  264. client.y = p.y;
  265. },
  266. // GameMessage::PlayerChangedFloor(p) => {client.area = MapArea::from_value(&room.mode.episode(), p.map).ok();},
  267. GameMessage::InitializeSpeechNpc(p) => {
  268. client.x = p.x;
  269. client.z = p.z;
  270. }
  271. _ => {},
  272. }
  273. Ok::<_, anyhow::Error>(())
  274. })}).await??;
  275. }
  276. Ok(client_location.get_client_neighbors(id).await?.into_iter()
  277. .map(move |client| {
  278. (client.client, SendShipPacket::Message(message.clone()))
  279. })
  280. .collect())
  281. }
  282. pub async fn charge_attack<EG>(id: ClientId,
  283. charge: ChargeAttack,
  284. entity_gateway: &mut EG,
  285. client_location: &ClientLocation,
  286. clients: &Clients,
  287. item_state: &mut ItemState)
  288. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  289. where
  290. EG: EntityGateway + Clone + 'static,
  291. {
  292. let meseta = charge.meseta;
  293. clients.with(id, |client| {
  294. let mut entity_gateway = entity_gateway.clone();
  295. let mut item_state = item_state.clone();
  296. Box::pin(async move {
  297. // TODO: should probably validate this to be a legit number, I'd just hardcode 200 but vjaya
  298. take_meseta(&mut item_state, &mut entity_gateway, &client.character.id, Meseta(meseta)).await
  299. })}).await??;
  300. Ok(client_location.get_client_neighbors(id).await.unwrap().into_iter()
  301. .map(move |client| {
  302. (client.client, SendShipPacket::Message(Message::new(GameMessage::ChargeAttack(charge.clone()))))
  303. })
  304. .collect())
  305. }
  306. pub async fn player_uses_item<EG>(id: ClientId,
  307. player_use_tool: PlayerUseItem,
  308. entity_gateway: &mut EG,
  309. client_location: &ClientLocation,
  310. clients: &Clients,
  311. item_state: &mut ItemState)
  312. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  313. where
  314. EG: EntityGateway + Clone + 'static,
  315. {
  316. let neighbors = client_location.get_all_clients_by_client(id).await?.into_iter();
  317. let area_client = client_location.get_local_client(id).await?;
  318. Ok(clients.with_mut(id, |client| {
  319. let mut entity_gateway = entity_gateway.clone();
  320. let mut item_state = item_state.clone();
  321. Box::pin(async move {
  322. use_item(&mut item_state, &mut entity_gateway, &mut client.character, area_client, &ClientItemId(player_use_tool.item_id), 1).await
  323. })}).await??
  324. .into_iter()
  325. .flat_map(move |pkt| {
  326. let pkt = match pkt {
  327. items::actions::CreateItem::Individual(area_client, item_id, item_detail) => {
  328. builder::message::create_individual_item(area_client, item_id, &item_detail)
  329. },
  330. items::actions::CreateItem::Stacked(area_client, item_id, tool, amount) => {
  331. builder::message::create_stacked_item(area_client, item_id, &tool, amount)
  332. }
  333. };
  334. let pkt = SendShipPacket::Message(Message::new(GameMessage::CreateItem(pkt)));
  335. let player_use_tool = player_use_tool.clone();
  336. neighbors.clone().map(move |client| {
  337. vec![(client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUseItem(player_use_tool.clone())))), (client.client, pkt.clone())]
  338. })
  339. })
  340. .flatten()
  341. .collect::<Vec<_>>()
  342. )
  343. }
  344. pub async fn player_used_medical_center<EG>(id: ClientId,
  345. pumc: PlayerUsedMedicalCenter,
  346. entity_gateway: &mut EG,
  347. client_location: &ClientLocation,
  348. clients: &Clients,
  349. item_state: &mut ItemState)
  350. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  351. where
  352. EG: EntityGateway + Clone + 'static,
  353. {
  354. clients.with(id, |client| {
  355. let mut entity_gateway = entity_gateway.clone();
  356. let mut item_state = item_state.clone();
  357. Box::pin(async move {
  358. take_meseta(&mut item_state, &mut entity_gateway, &client.character.id, Meseta(10)).await
  359. })}).await??;
  360. let pumc = pumc.clone();
  361. Ok(client_location.get_client_neighbors(id).await.unwrap().into_iter()
  362. .map(move |client| {
  363. (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUsedMedicalCenter(pumc.clone()))))
  364. })
  365. .collect())
  366. }
  367. pub async fn player_feed_mag<EG>(id: ClientId,
  368. mag_feed: PlayerFeedMag,
  369. entity_gateway: &mut EG,
  370. client_location: &ClientLocation,
  371. clients: &Clients,
  372. item_state: &mut ItemState)
  373. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  374. where
  375. EG: EntityGateway + Clone + 'static,
  376. {
  377. let cmag_feed = mag_feed.clone();
  378. clients.with(id, |client| {
  379. let mut entity_gateway = entity_gateway.clone();
  380. let mut item_state = item_state.clone();
  381. Box::pin(async move {
  382. feed_mag(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(cmag_feed.mag_id), &ClientItemId(cmag_feed.item_id)).await
  383. })}).await??;
  384. Ok(client_location.get_client_neighbors(id).await.unwrap().into_iter()
  385. .map(move |client| {
  386. (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone()))))
  387. })
  388. .collect())
  389. }
  390. pub async fn player_equips_item<EG>(id: ClientId,
  391. pkt: PlayerEquipItem,
  392. entity_gateway: &mut EG,
  393. clients: &Clients,
  394. item_state: &mut ItemState)
  395. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  396. where
  397. EG: EntityGateway + Clone + 'static,
  398. {
  399. let equip_slot = if pkt.sub_menu > 0 {
  400. ((pkt.sub_menu & 0x7) - 1) % 4
  401. }
  402. else {
  403. 0
  404. };
  405. clients.with(id, |client| {
  406. let mut entity_gateway = entity_gateway.clone();
  407. let mut item_state = item_state.clone();
  408. Box::pin(async move {
  409. equip_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(pkt.item_id), equip_slot).await
  410. })}).await??;
  411. Ok(Vec::new()) // TODO: tell other players you equipped an item
  412. }
  413. pub async fn player_unequips_item<EG>(id: ClientId,
  414. pkt: PlayerUnequipItem,
  415. entity_gateway: &mut EG,
  416. clients: &Clients,
  417. item_state: &mut ItemState)
  418. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  419. where
  420. EG: EntityGateway + Clone + 'static,
  421. {
  422. clients.with(id, |client| {
  423. let mut entity_gateway = entity_gateway.clone();
  424. let mut item_state = item_state.clone();
  425. Box::pin(async move {
  426. unequip_item(&mut item_state, &mut entity_gateway, &client.character, &ClientItemId(pkt.item_id)).await
  427. })}).await??;
  428. Ok(Vec::new()) // TODO: tell other players if you unequip an item
  429. }
  430. pub async fn player_sorts_items<EG>(id: ClientId,
  431. pkt: SortItems,
  432. entity_gateway: &mut EG,
  433. clients: &Clients,
  434. item_state: &mut ItemState)
  435. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  436. where
  437. EG: EntityGateway + Clone + 'static,
  438. {
  439. let item_ids = pkt.item_ids
  440. .iter()
  441. .filter_map(|item_id| {
  442. if *item_id != 0 {
  443. Some(ClientItemId(*item_id))
  444. }
  445. else {
  446. None
  447. }
  448. })
  449. .collect();
  450. clients.with(id, |client| {
  451. let mut entity_gateway = entity_gateway.clone();
  452. let mut item_state = item_state.clone();
  453. Box::pin(async move {
  454. sort_inventory(&mut item_state, &mut entity_gateway, &client.character, item_ids).await
  455. })}).await??;
  456. Ok(Vec::new()) // TODO: clients probably care about each others item orders
  457. }
  458. pub async fn player_sells_item<EG> (id: ClientId,
  459. sold_item: PlayerSoldItem,
  460. entity_gateway: &mut EG,
  461. clients: &Clients,
  462. item_state: &mut ItemState)
  463. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  464. where
  465. EG: EntityGateway + Clone + 'static,
  466. {
  467. clients.with(id, |client| {
  468. let mut entity_gateway = entity_gateway.clone();
  469. let mut item_state = item_state.clone();
  470. Box::pin(async move {
  471. sell_item(&mut item_state, &mut entity_gateway, &client.character, ClientItemId(sold_item.item_id), sold_item.amount as u32).await
  472. })}).await??;
  473. Ok(Vec::new()) // TODO: send the packet to other clients
  474. }
  475. pub async fn floor_item_limit_deletion<EG> (id: ClientId,
  476. floor_item_limit_delete: FloorItemLimitItemDeletion,
  477. entity_gateway: &mut EG,
  478. client_location: &ClientLocation,
  479. clients: &Clients,
  480. rooms: &Rooms,
  481. item_state: &mut ItemState)
  482. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  483. where
  484. EG: EntityGateway + Clone + 'static,
  485. {
  486. let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
  487. let map_area = rooms.with(room_id, |room| Box::pin(async move {
  488. room.map_areas.get_area_map(floor_item_limit_delete.map_area)
  489. })).await??;
  490. clients.with(id, |client| {
  491. let mut entity_gateway = entity_gateway.clone();
  492. let item_state = item_state.clone();
  493. Box::pin(async move {
  494. floor_item_limit_reached(&item_state, &mut entity_gateway, &client.character, &ClientItemId(floor_item_limit_delete.item_id), map_area).await
  495. })}).await??;
  496. Ok(Vec::new())
  497. }