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.

411 lines
11 KiB

1 year ago
4 years ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
3 years ago
4 years ago
4 years ago
3 years ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. use std::collections::HashMap;
  2. use std::convert::{From, Into, TryFrom};
  3. use async_std::sync::{Arc, RwLock, RwLockReadGuard};
  4. use futures::future::BoxFuture;
  5. use futures::stream::{FuturesOrdered, Stream};
  6. use thiserror::Error;
  7. use rand::Rng;
  8. use crate::ship::map::Maps;
  9. use crate::ship::drops::DropTable;
  10. use crate::entity::character::SectionID;
  11. use crate::entity::room::{RoomEntityId, RoomEntityMode};
  12. use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats};
  13. use crate::ship::map::area::MapAreaLookup;
  14. use crate::ship::quests;
  15. use crate::ship::ship::{ShipError, ShipEvent};
  16. use crate::ship::location::{MAX_ROOMS, RoomId};
  17. #[derive(Clone)]
  18. pub struct Rooms([Arc<RwLock<Option<RoomState>>>; MAX_ROOMS]);
  19. impl Default for Rooms {
  20. fn default() -> Rooms {
  21. Rooms(core::array::from_fn(|_| Arc::new(RwLock::new(None))))
  22. }
  23. }
  24. impl Rooms {
  25. pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), anyhow::Error> {
  26. *self.0
  27. .get(room_id.0)
  28. .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
  29. .write()
  30. .await = Some(room);
  31. Ok(())
  32. }
  33. pub async fn remove(&self, room_id: RoomId) {
  34. if let Some(room) = self.0.get(room_id.0) {
  35. *room
  36. .write()
  37. .await = None;
  38. }
  39. }
  40. pub async fn exists(&self, room_id: RoomId) -> bool {
  41. match self.0.get(room_id.0) {
  42. Some(room) => {
  43. room
  44. .read()
  45. .await
  46. .is_some()
  47. },
  48. None => false,
  49. }
  50. }
  51. pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result<T, anyhow::Error>
  52. where
  53. T: Send,
  54. F: for<'b> FnOnce(&'b RoomState) -> BoxFuture<'b, T> + Send + 'a
  55. {
  56. let room = self.0
  57. .get(room_id.0)
  58. .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
  59. .read()
  60. .await;
  61. if let Some(room) = room.as_ref() {
  62. Ok(func(room).await)
  63. }
  64. else {
  65. Err(ShipError::InvalidRoom(room_id.0 as u32).into())
  66. }
  67. }
  68. pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result<T, anyhow::Error>
  69. where
  70. T: Send,
  71. F: for<'b> FnOnce(&'b mut RoomState) -> BoxFuture<'b, T> + Send + 'a
  72. {
  73. let mut room = self.0
  74. .get(room_id.0)
  75. .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?
  76. .write()
  77. .await;
  78. if let Some(room) = room.as_mut() {
  79. Ok(func(room).await)
  80. }
  81. else {
  82. Err(ShipError::InvalidRoom(room_id.0 as u32).into())
  83. }
  84. }
  85. pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard<Option<RoomState>> {
  86. self.0
  87. .get(room_id.0)
  88. .unwrap()
  89. .read()
  90. .await
  91. }
  92. pub fn stream(&self) -> impl Stream<Item = RwLockReadGuard<Option<RoomState>>> {
  93. self.0
  94. .iter()
  95. .map(|room| async move {
  96. room
  97. .read()
  98. .await
  99. })
  100. .collect::<FuturesOrdered<_>>()
  101. }
  102. }
  103. #[derive(Debug, Error)]
  104. #[error("")]
  105. pub enum RoomCreationError {
  106. InvalidMode,
  107. InvalidEpisode(u8),
  108. InvalidDifficulty(u8),
  109. CouldNotLoadMonsterStats(RoomMode),
  110. CouldNotLoadQuests,
  111. }
  112. #[derive(Debug, Copy, Clone, derive_more::Display)]
  113. pub enum Episode {
  114. #[display(fmt="ep1")]
  115. One,
  116. #[display(fmt="ep2")]
  117. Two,
  118. #[display(fmt="ep4")]
  119. Four,
  120. }
  121. #[derive(Debug, Copy, Clone)]
  122. pub enum PlayerMode{
  123. Single,
  124. Multi,
  125. }
  126. impl PlayerMode {
  127. pub fn value(&self) -> u8 {
  128. match self {
  129. PlayerMode::Single => 1,
  130. PlayerMode::Multi => 0,
  131. }
  132. }
  133. }
  134. impl TryFrom<u8> for Episode {
  135. type Error = RoomCreationError;
  136. fn try_from(value: u8) -> Result<Episode, RoomCreationError> {
  137. match value {
  138. 1 => Ok(Episode::One),
  139. 2 => Ok(Episode::Two),
  140. 3 => Ok(Episode::Four),
  141. _ => Err(RoomCreationError::InvalidEpisode(value))
  142. }
  143. }
  144. }
  145. impl From<Episode> for u8 {
  146. fn from(other: Episode) -> u8 {
  147. match other {
  148. Episode::One => 1,
  149. Episode::Two => 2,
  150. Episode::Four => 3,
  151. }
  152. }
  153. }
  154. impl Episode {
  155. pub fn from_quest(value: u8) -> Result<Episode, RoomCreationError> {
  156. match value {
  157. 0 => Ok(Episode::One),
  158. 1 => Ok(Episode::Two),
  159. 2 => Ok(Episode::Four),
  160. _ => Err(RoomCreationError::InvalidEpisode(value))
  161. }
  162. }
  163. }
  164. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)]
  165. pub enum Difficulty {
  166. Normal,
  167. Hard,
  168. VeryHard,
  169. Ultimate,
  170. }
  171. impl TryFrom<u8> for Difficulty {
  172. type Error = RoomCreationError;
  173. fn try_from(value: u8) -> Result<Difficulty, RoomCreationError> {
  174. match value {
  175. 0 => Ok(Difficulty::Normal),
  176. 1 => Ok(Difficulty::Hard),
  177. 2 => Ok(Difficulty::VeryHard),
  178. 3 => Ok(Difficulty::Ultimate),
  179. _ => Err(RoomCreationError::InvalidDifficulty(value))
  180. }
  181. }
  182. }
  183. impl From<Difficulty> for u8 {
  184. fn from(other: Difficulty) -> u8 {
  185. match other {
  186. Difficulty::Normal => 0,
  187. Difficulty::Hard => 1,
  188. Difficulty::VeryHard => 2,
  189. Difficulty::Ultimate => 3,
  190. }
  191. }
  192. }
  193. #[derive(Debug, Copy, Clone, derive_more::Display)]
  194. pub enum RoomMode {
  195. #[display(fmt="single")]
  196. Single {
  197. episode: Episode,
  198. difficulty: Difficulty,
  199. },
  200. #[display(fmt="multi")]
  201. Multi {
  202. episode: Episode,
  203. difficulty: Difficulty,
  204. },
  205. #[display(fmt="challenge")]
  206. Challenge {
  207. episode: Episode,
  208. },
  209. #[display(fmt="battle")]
  210. Battle {
  211. episode: Episode,
  212. difficulty: Difficulty,
  213. }
  214. }
  215. impl RoomMode {
  216. pub fn difficulty(&self) -> Difficulty {
  217. match self {
  218. RoomMode::Single {difficulty, ..} => *difficulty,
  219. RoomMode::Multi {difficulty, ..} => *difficulty,
  220. RoomMode::Battle {difficulty, ..} => *difficulty,
  221. RoomMode::Challenge {..} => Difficulty::Normal,
  222. }
  223. }
  224. pub fn episode(&self) -> Episode {
  225. match self {
  226. RoomMode::Single {episode, ..} => *episode,
  227. RoomMode::Multi {episode, ..} => *episode,
  228. RoomMode::Battle {episode, ..} => *episode,
  229. RoomMode::Challenge {episode, ..} => *episode,
  230. }
  231. }
  232. pub fn battle(&self) -> bool {
  233. matches!(self, RoomMode::Battle {..})
  234. }
  235. pub fn challenge(&self) -> bool {
  236. matches!(self, RoomMode::Challenge {..})
  237. }
  238. pub fn player_mode(&self) -> PlayerMode {
  239. match self {
  240. RoomMode::Single {..} => PlayerMode::Single,
  241. _ => PlayerMode::Multi,
  242. }
  243. }
  244. }
  245. pub enum QuestCategoryType {
  246. Standard,
  247. Government,
  248. }
  249. impl From<usize> for QuestCategoryType {
  250. fn from(f: usize) -> QuestCategoryType {
  251. match f {
  252. 0 => QuestCategoryType::Standard,
  253. _ => QuestCategoryType::Government,
  254. }
  255. }
  256. }
  257. impl From<u32> for QuestCategoryType {
  258. fn from(f: u32) -> QuestCategoryType {
  259. match f {
  260. 0 => QuestCategoryType::Standard,
  261. _ => QuestCategoryType::Government,
  262. }
  263. }
  264. }
  265. impl QuestCategoryType {
  266. pub fn value(&self) -> usize {
  267. match self {
  268. QuestCategoryType::Standard => 0,
  269. QuestCategoryType::Government => 1,
  270. }
  271. }
  272. }
  273. pub struct RoomState {
  274. pub room_id: RoomEntityId,
  275. pub mode: RoomMode,
  276. pub name: String,
  277. pub password: [u16; 16],
  278. pub maps: Maps,
  279. pub drop_table: Box<DropTable>,
  280. pub section_id: SectionID,
  281. pub random_seed: u32,
  282. pub bursting: bool,
  283. pub monster_stats: Box<HashMap<MonsterType, MonsterStats>>,
  284. pub map_areas: MapAreaLookup,
  285. pub quest_group: QuestCategoryType,
  286. pub standard_quests: quests::QuestList,
  287. pub government_quests: quests::QuestList,
  288. // enemy info
  289. }
  290. impl RoomState {
  291. pub fn get_flags_for_room_list(&self) -> u8 {
  292. let mut flags = 0u8;
  293. match self.mode {
  294. RoomMode::Single {..} => {flags += 0x04}
  295. RoomMode::Battle {..} => {flags += 0x10},
  296. RoomMode::Challenge {..} => {flags += 0x20},
  297. _ => {flags += 0x40},
  298. };
  299. if self.password[0] > 0 {
  300. flags += 0x02;
  301. }
  302. flags
  303. }
  304. pub fn get_episode_for_room_list(&self) -> u8 {
  305. let episode: u8 = self.mode.episode().into();
  306. match self.mode {
  307. RoomMode::Single {..} => episode + 0x10,
  308. _ => episode + 0x40,
  309. }
  310. }
  311. pub fn get_difficulty_for_room_list(&self) -> u8 {
  312. let difficulty: u8 = self.mode.difficulty().into();
  313. difficulty + 0x22
  314. }
  315. pub fn quests(&self) -> &quests::QuestList {
  316. match self.quest_group {
  317. QuestCategoryType::Standard => &self.standard_quests,
  318. QuestCategoryType::Government => &self.government_quests,
  319. }
  320. }
  321. #[allow(clippy::too_many_arguments)]
  322. pub fn new (room_id: RoomEntityId,
  323. mode: RoomEntityMode,
  324. episode: Episode,
  325. difficulty: Difficulty,
  326. section_id: SectionID,
  327. name: String,
  328. password: [u16; 16],
  329. event: ShipEvent,
  330. map_builder: Arc<Box<dyn Fn(RoomMode, ShipEvent) -> Maps + Send + Sync>>,
  331. drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
  332. ) -> Result<RoomState, anyhow::Error> {
  333. let mode = match mode {
  334. RoomEntityMode::Single => RoomMode::Single {
  335. episode,
  336. difficulty,
  337. },
  338. RoomEntityMode::Multi => RoomMode::Multi {
  339. episode,
  340. difficulty,
  341. },
  342. RoomEntityMode::Challenge => RoomMode::Challenge {
  343. episode,
  344. },
  345. RoomEntityMode::Battle => RoomMode::Battle {
  346. episode,
  347. difficulty,
  348. },
  349. };
  350. Ok(RoomState {
  351. room_id,
  352. monster_stats: Box::new(load_monster_stats_table(&mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(mode))?),
  353. mode,
  354. random_seed: rand::thread_rng().gen(),
  355. name,
  356. password,
  357. maps: map_builder(mode, event),
  358. section_id,
  359. drop_table: Box::new(drop_table_builder(episode, difficulty, section_id)),
  360. bursting: false,
  361. map_areas: MapAreaLookup::new(&episode),
  362. quest_group: QuestCategoryType::Standard,
  363. standard_quests: quests::load_standard_quests(mode)?,
  364. government_quests: quests::load_government_quests(mode)?,
  365. })
  366. }
  367. }