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.

227 lines
7.0 KiB

4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. use libpso::packet::messages::*;
  2. use libpso::packet::ship::*;
  3. use entity::item;
  4. use crate::common::leveltable::CharacterStats;
  5. use crate::ship::ship::{ShipError};
  6. use crate::ship::items::ClientItemId;
  7. use crate::ship::items::inventory::InventoryItem;
  8. use crate::ship::items::state::IndividualItemDetail;
  9. use crate::ship::items::bank::BankState;
  10. use crate::ship::items::floor::FloorItem;
  11. use crate::ship::location::AreaClient;
  12. use std::convert::TryInto;
  13. use shops::ShopItem;
  14. pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDrop, ShipError> {
  15. let item_bytes = item_drop.as_client_bytes();
  16. Ok(ItemDrop {
  17. client,
  18. target,
  19. map_area: item_drop.map_area.area_value(),
  20. variety: 0,
  21. unknown: 0,
  22. x: item_drop.x,
  23. z: item_drop.z,
  24. y: item_drop.y,
  25. item_bytes: item_bytes[0..12].try_into()?,
  26. item_id: item_drop.item_id.0,
  27. item_bytes2: item_bytes[12..16].try_into()?,
  28. unknown2: 0,
  29. })
  30. }
  31. // TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
  32. pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &IndividualItemDetail) -> Result<CreateItem, ShipError> {
  33. let bytes = item.as_client_bytes();
  34. Ok(CreateItem {
  35. client: area_client.local_client.id(),
  36. target: 0,
  37. item_data: bytes[0..12].try_into()?,
  38. item_id: item_id.0,
  39. item_data2: bytes[12..16].try_into()?,
  40. unknown: 0,
  41. })
  42. }
  43. // TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
  44. pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> Result<CreateItem, ShipError> {
  45. let bytes = tool.as_stacked_bytes(amount);
  46. Ok(CreateItem {
  47. client: area_client.local_client.id(),
  48. target: 0,
  49. item_data: bytes[0..12].try_into()?,
  50. item_id: item_id.0,
  51. item_data2: bytes[12..16].try_into()?,
  52. unknown: 0,
  53. })
  54. }
  55. pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem {
  56. let bytes: [u8; 12] = [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  57. CreateItem {
  58. client: area_client.local_client.id(),
  59. target: 0,
  60. item_data: bytes,
  61. item_id: 0xFFFFFFFF,
  62. item_data2: u32::to_le_bytes(amount as u32),
  63. unknown: 0,
  64. }
  65. }
  66. pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> Result<CreateItem, ShipError> {
  67. let bytes = item.item.as_client_bytes();
  68. Ok(CreateItem {
  69. client: area_client.local_client.id(),
  70. target: 0,
  71. item_data: bytes[0..12].try_into()?,
  72. item_id: item.item_id.0,
  73. item_data2: bytes[12..16].try_into()?,
  74. unknown: 0,
  75. })
  76. }
  77. pub fn create_withdrawn_inventory_item2(area_client: AreaClient, item: &InventoryItem) -> Result<CreateItem, ShipError> {
  78. let bytes = item.item.as_client_bytes();
  79. Ok(CreateItem {
  80. client: area_client.local_client.id(),
  81. target: 0,
  82. item_data: bytes[0..12].try_into()?,
  83. item_id: item.item_id.0,
  84. item_data2: bytes[12..16].try_into()?,
  85. unknown: 0,
  86. })
  87. }
  88. pub fn remove_item_from_floor(area_client: AreaClient, item: &FloorItem) -> Result<RemoveItemFromFloor, ShipError> {
  89. Ok(RemoveItemFromFloor {
  90. client: area_client.local_client.id(),
  91. target: 0,
  92. client_id: area_client.local_client.id(),
  93. unknown: 0,
  94. map_area: item.map_area.area_value(),
  95. unknown2: 0,
  96. item_id: item.item_id.0,
  97. })
  98. }
  99. pub fn drop_split_stack(area_client: AreaClient, item: &FloorItem) -> Result<DropSplitStack, ShipError> {
  100. let item_bytes = item.as_client_bytes();
  101. Ok(DropSplitStack {
  102. client: area_client.local_client.id(),
  103. target: 0,
  104. variety: 0,
  105. unknown1: 0,
  106. map_area: item.map_area.area_value(),
  107. x: item.x,
  108. z: item.z,
  109. item_bytes: item_bytes[0..12].try_into()?,
  110. item_id: item.item_id.0,
  111. item_bytes2: item_bytes[12..16].try_into()?,
  112. unknown2: 0,
  113. })
  114. }
  115. pub fn drop_split_meseta_stack(area_client: AreaClient, item: &FloorItem) -> Result<DropSplitStack, ShipError> {
  116. let item_bytes = item.as_client_bytes();
  117. Ok(DropSplitStack {
  118. client: area_client.local_client.id(),
  119. target: 0,
  120. variety: 0,
  121. unknown1: 0,
  122. map_area: item.map_area.area_value(),
  123. x: item.x,
  124. z: item.z,
  125. item_bytes: item_bytes[0..12].try_into()?,
  126. item_id: item.item_id.0,
  127. item_bytes2: item_bytes[12..16].try_into()?,
  128. unknown2: 0,
  129. })
  130. }
  131. pub fn character_gained_exp(area_client: AreaClient, exp: u32) -> GiveCharacterExp {
  132. GiveCharacterExp {
  133. client: area_client.local_client.id(),
  134. target: 0,
  135. exp,
  136. }
  137. }
  138. pub fn character_leveled_up(area_client: AreaClient, level: u32, before_stats: CharacterStats, after_stats: CharacterStats) -> PlayerLevelUp {
  139. PlayerLevelUp {
  140. client: area_client.local_client.id(),
  141. target: 0,
  142. atp: after_stats.atp - before_stats.atp,
  143. mst: after_stats.mst - before_stats.mst,
  144. evp: after_stats.evp - before_stats.evp,
  145. hp: after_stats. hp - before_stats. hp,
  146. dfp: after_stats.dfp - before_stats.dfp,
  147. ata: after_stats.ata - before_stats.ata,
  148. lvl: level,
  149. }
  150. }
  151. // TOOD: checksum?
  152. pub fn bank_item_list(bank: &BankState) -> BankItemList {
  153. BankItemList {
  154. aflag: 0,
  155. cmd: 0xBC,
  156. unknown: [0; 3],
  157. size: bank.count() as u32 * 0x18 + 0x14,
  158. checksum: 0x123434,
  159. item_count: bank.count() as u32,
  160. meseta: bank.meseta.0,
  161. items: bank.as_client_bank_request()
  162. }
  163. }
  164. pub fn player_no_longer_has_item(area_client: AreaClient, item_id: ClientItemId, amount: u32) -> PlayerNoLongerHasItem {
  165. PlayerNoLongerHasItem {
  166. client: area_client.local_client.id(),
  167. target: 0,
  168. item_id: item_id.0,
  169. amount,
  170. }
  171. }
  172. pub fn player_no_longer_has_meseta(area_client: AreaClient, amount: u32) -> PlayerNoLongerHasItem {
  173. PlayerNoLongerHasItem {
  174. client: area_client.local_client.id(),
  175. target: 0,
  176. item_id: 0xFFFFFFFF,
  177. amount,
  178. }
  179. }
  180. pub fn shop_list<I: ShopItem>(shop_type: u8, items: &[I]) -> ShopList {
  181. let items = items.iter()
  182. .enumerate()
  183. .map(|(i, item)| {
  184. ShopListItem {
  185. item_bytes: item.as_bytes(),
  186. unknown: i as u32 + 23,
  187. price: item.price() as u32,
  188. }
  189. })
  190. .collect();
  191. ShopList {
  192. client: 0,
  193. target: 0,
  194. shop_type,
  195. num_items: 0,
  196. unused: 0,
  197. items,
  198. }
  199. }
  200. pub fn tek_preview(id: ClientItemId, weapon: &item::weapon::Weapon) -> Result<TekPreview, ShipError> {
  201. let bytes = weapon.as_bytes();
  202. Ok(TekPreview {
  203. client: 0x79,
  204. target: 0,
  205. item_bytes: bytes[0..12].try_into()?,
  206. item_id: id.0,
  207. item_bytes2: bytes[12..16].try_into()?,
  208. })
  209. }