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.

247 lines
6.6 KiB

5 years ago
4 years ago
4 years ago
5 years ago
  1. use std::collections::HashMap;
  2. use std::convert::{From, Into, TryFrom, TryInto};
  3. use rand::Rng;
  4. use crate::ship::map::Maps;
  5. use crate::ship::drops::DropTable;
  6. use crate::entity::character::SectionID;
  7. use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats};
  8. use crate::ship::map::area::MapAreaLookup;
  9. #[derive(Debug)]
  10. pub enum RoomCreationError {
  11. InvalidMode,
  12. InvalidEpisode(u8),
  13. InvalidDifficulty(u8),
  14. CouldNotLoadMonsterStats(RoomMode),
  15. }
  16. #[derive(Debug, Copy, Clone, derive_more::Display)]
  17. pub enum Episode {
  18. #[display(fmt="ep1")]
  19. One,
  20. #[display(fmt="ep2")]
  21. Two,
  22. #[display(fmt="ep4")]
  23. Four,
  24. }
  25. impl TryFrom<u8> for Episode {
  26. type Error = RoomCreationError;
  27. fn try_from(value: u8) -> Result<Episode, RoomCreationError> {
  28. match value {
  29. 1 => Ok(Episode::One),
  30. 2 => Ok(Episode::Two),
  31. 3 => Ok(Episode::Four),
  32. _ => Err(RoomCreationError::InvalidEpisode(value))
  33. }
  34. }
  35. }
  36. impl Into<u8> for Episode {
  37. fn into(self) -> u8 {
  38. match self {
  39. Episode::One => 1,
  40. Episode::Two => 2,
  41. Episode::Four => 3,
  42. }
  43. }
  44. }
  45. impl Episode {
  46. pub fn from_quest(value: u8) -> Result<Episode, RoomCreationError> {
  47. match value {
  48. 0 => Ok(Episode::One),
  49. 1 => Ok(Episode::Two),
  50. 2 => Ok(Episode::Four),
  51. _ => Err(RoomCreationError::InvalidEpisode(value))
  52. }
  53. }
  54. }
  55. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)]
  56. pub enum Difficulty {
  57. Normal,
  58. Hard,
  59. VeryHard,
  60. Ultimate,
  61. }
  62. impl TryFrom<u8> for Difficulty {
  63. type Error = RoomCreationError;
  64. fn try_from(value: u8) -> Result<Difficulty, RoomCreationError> {
  65. match value {
  66. 0 => Ok(Difficulty::Normal),
  67. 1 => Ok(Difficulty::Hard),
  68. 2 => Ok(Difficulty::VeryHard),
  69. 3 => Ok(Difficulty::Ultimate),
  70. _ => Err(RoomCreationError::InvalidDifficulty(value))
  71. }
  72. }
  73. }
  74. impl Into<u8> for Difficulty {
  75. fn into(self) -> u8 {
  76. match self {
  77. Difficulty::Normal => 0,
  78. Difficulty::Hard => 1,
  79. Difficulty::VeryHard => 2,
  80. Difficulty::Ultimate => 3,
  81. }
  82. }
  83. }
  84. #[derive(Debug, Copy, Clone)]
  85. pub enum RoomMode {
  86. Single {
  87. episode: Episode,
  88. difficulty: Difficulty,
  89. },
  90. Multi {
  91. episode: Episode,
  92. difficulty: Difficulty,
  93. },
  94. Challenge {
  95. episode: Episode,
  96. },
  97. Battle {
  98. episode: Episode,
  99. difficulty: Difficulty,
  100. }
  101. }
  102. impl RoomMode {
  103. pub fn difficulty(&self) -> Difficulty {
  104. match self {
  105. RoomMode::Single {difficulty, ..} => *difficulty,
  106. RoomMode::Multi {difficulty, ..} => *difficulty,
  107. RoomMode::Battle {difficulty, ..} => *difficulty,
  108. RoomMode::Challenge {..} => Difficulty::Normal,
  109. }
  110. }
  111. pub fn episode(&self) -> Episode {
  112. match self {
  113. RoomMode::Single {episode, ..} => *episode,
  114. RoomMode::Multi {episode, ..} => *episode,
  115. RoomMode::Battle {episode, ..} => *episode,
  116. RoomMode::Challenge {episode, ..} => *episode,
  117. }
  118. }
  119. pub fn battle(&self) -> u8 {
  120. match self {
  121. RoomMode::Battle {..} => 1,
  122. _ => 0,
  123. }
  124. }
  125. pub fn challenge(&self) -> u8 {
  126. match self {
  127. RoomMode::Challenge {..} => 1,
  128. _ => 0,
  129. }
  130. }
  131. pub fn single_player(&self) -> u8 {
  132. match self {
  133. RoomMode::Single {..} => 1,
  134. _ => 0,
  135. }
  136. }
  137. }
  138. pub struct RoomState {
  139. pub mode: RoomMode,
  140. pub name: String,
  141. pub password: [u16; 16],
  142. pub maps: Maps,
  143. pub drop_table: Box<DropTable<rand_chacha::ChaCha20Rng>>,
  144. pub section_id: SectionID,
  145. pub random_seed: u32,
  146. pub bursting: bool,
  147. pub monster_stats: Box<HashMap<MonsterType, MonsterStats>>,
  148. pub map_areas: MapAreaLookup,
  149. // items on ground
  150. // enemy info
  151. }
  152. impl RoomState {
  153. pub fn get_flags_for_room_list(&self) -> u8 {
  154. let mut flags = 0u8;
  155. match self.mode {
  156. RoomMode::Single {..} => {flags += 0x04}
  157. RoomMode::Battle {..} => {flags += 0x10},
  158. RoomMode::Challenge {..} => {flags += 0x20},
  159. _ => {flags += 0x40},
  160. };
  161. if self.password[0] > 0 {
  162. flags += 0x02;
  163. }
  164. flags
  165. }
  166. pub fn get_episode_for_room_list(&self) -> u8 {
  167. let episode: u8 = self.mode.episode().into();
  168. match self.mode {
  169. RoomMode::Single {..} => episode + 0x10,
  170. _ => episode + 0x40,
  171. }
  172. }
  173. pub fn get_difficulty_for_room_list(&self) -> u8 {
  174. let difficulty: u8 = self.mode.difficulty().into();
  175. difficulty + 0x22
  176. }
  177. pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, section_id: SectionID) -> Result<RoomState, RoomCreationError> {
  178. if [create_room.battle, create_room.challenge, create_room.single_player].iter().sum::<u8>() > 1 {
  179. return Err(RoomCreationError::InvalidMode)
  180. }
  181. let room_mode = if create_room.battle == 1 {
  182. RoomMode::Battle {
  183. episode: create_room.episode.try_into()?,
  184. difficulty: create_room.difficulty.try_into()?,
  185. }
  186. }
  187. else if create_room.challenge == 1 {
  188. RoomMode::Challenge {
  189. episode: create_room.episode.try_into()?,
  190. }
  191. }
  192. else if create_room.single_player == 1 {
  193. RoomMode::Single {
  194. episode: create_room.episode.try_into()?,
  195. difficulty: create_room.difficulty.try_into()?,
  196. }
  197. }
  198. else { // normal multimode
  199. RoomMode::Multi {
  200. episode: create_room.episode.try_into()?,
  201. difficulty: create_room.difficulty.try_into()?,
  202. }
  203. };
  204. Ok(RoomState {
  205. monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode.clone()))?),
  206. mode: room_mode,
  207. random_seed: rand::thread_rng().gen(),
  208. name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(),
  209. password: create_room.password,
  210. maps: Maps::new(room_mode),
  211. section_id: section_id,
  212. drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)),
  213. bursting: false,
  214. map_areas: MapAreaLookup::new(&room_mode.episode()),
  215. })
  216. }
  217. }