diff --git a/data/quests.toml b/data/quests.toml deleted file mode 100644 index d1d3298..0000000 --- a/data/quests.toml +++ /dev/null @@ -1,39 +0,0 @@ -[Extermination] -list_order = 1 -description = "I am a description" - -[[Extermination.quests]] -bin = "q058-ret-bb.bin" -dat = "q058-ret-bb.dat" - -[[Extermination.quests]] -bin = "q059-ret-bb.bin" -dat = "q059-ret-bb.dat" - - -[Retrieval] -list_order = 2 -description = "find some shit" - -[[Retrieval.quests]] -bin = "q101-ext-bb.bin" -dat = "q101-ext-bb.dat" - -[[Retrieval.quests]] -bin = "q102-ext-bb.bin" -dat = "q102-ext-bb.dat" -#drop_table = "q102-drops" - -[[Retrieval.quests]] -bin = "q233-ext-bb.bin" -dat = "q233-ext-bb.dat" -#drop_table = "q102-drops" - -[[Retrieval.quests]] -bin = "q236-ext-bb.bin" -dat = "q236-ext-bb.dat" -#drop_table = "q102-drops" - -[[Retrieval.quests]] -bin = "q118-vr-bb.bin" -dat = "q118-vr-bb.dat" diff --git a/src/ship/packet/handler/quest.rs b/src/ship/packet/handler/quest.rs index 550df18..e2b659c 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/quest.rs @@ -2,7 +2,6 @@ use std::io::{Cursor, Read, Seek, SeekFrom}; use libpso::packet::ship::*; use crate::common::serverstate::ClientId; use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms}; -use crate::ship::quests::QuestList; use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::packet::builder::quest; use libpso::util::array_to_utf8; @@ -37,24 +36,38 @@ fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType) } -pub fn send_quest_category_list(id: ClientId, quests: &QuestList) -> Result + Send>, ShipError> { - let qcl = quest::quest_category_list(quests); +pub fn send_quest_category_list(id: ClientId, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get_mut(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let qcl = quest::quest_category_list(&room.quests); Ok(Box::new(vec![(id, SendShipPacket::QuestCategoryList(qcl))].into_iter())) } -pub fn select_quest_category(id: ClientId, menuselect: &MenuSelect, quests: &QuestList) -> Result + Send>, ShipError> { - let (_, category_quests) = quests.iter() +pub fn select_quest_category(id: ClientId, menuselect: &MenuSelect, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get_mut(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let (_, category_quests) = room.quests.iter() .nth(menuselect.item as usize) .ok_or(ShipError::InvalidQuestCategory(menuselect.item))?; let ql = quest::quest_list(menuselect.item, category_quests); - + for q in ql.quests.clone() { + println!("name: {:?} quest_id: {}", q.name, q.quest_id); + } Ok(Box::new(vec![(id, SendShipPacket::QuestOptionList(ql))].into_iter())) } -pub fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, quests: &QuestList) -> Result + Send>, ShipError> { - let (_, category_quests) = quests.iter() +pub fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get_mut(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let (_, category_quests) = room.quests.iter() .nth(questdetailrequest.category as usize) .ok_or(ShipError::InvalidQuestCategory(questdetailrequest.category as u32))?; @@ -68,9 +81,13 @@ pub fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, quest Ok(Box::new(vec![(id, SendShipPacket::QuestDetail(qd))].into_iter())) } -pub fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, quests: &QuestList, clients: &mut Clients, client_location: &ClientLocation, rooms: &mut Rooms) +pub fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, clients: &mut Clients, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { - let (_, category_quests) = quests.iter() + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get_mut(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let (_, category_quests) = room.quests.iter() .nth(questmenuselect.category as usize) .ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))?; @@ -79,10 +96,6 @@ pub fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, quest q.id == questmenuselect.quest as u16 }).ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))?; - let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; - let room = rooms.get_mut(room_id.0) - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() - .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &room.rare_monster_table); room.map_areas = quest.map_areas.clone(); @@ -100,9 +113,14 @@ pub fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, quest }))) } -pub fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, quests: &QuestList) -> Result + Send>, ShipError> { +pub fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get_mut(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?; - let (_, category_quests) = quests.iter() + let (_, category_quests) = room.quests.iter() .nth(category_id as usize) .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; @@ -124,9 +142,14 @@ pub fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, q Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter())) } -pub fn quest_chunk_ack(id: ClientId, quest_chunk_ack: &QuestChunkAck, quests: &QuestList) -> Result + Send>, ShipError> { +pub fn quest_chunk_ack(id: ClientId, quest_chunk_ack: &QuestChunkAck, client_location: &ClientLocation, rooms: &mut Rooms) -> Result + Send>, ShipError> { + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get_mut(room_id.0) + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut() + .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; + let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; - let (_, category_quests) = quests.iter() + let (_, category_quests) = room.quests.iter() .nth(category_id as usize) .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; diff --git a/src/ship/quests.rs b/src/ship/quests.rs index 3b430ba..b326890 100644 --- a/src/ship/quests.rs +++ b/src/ship/quests.rs @@ -208,13 +208,12 @@ impl Quest { // QuestCollection pub type QuestList = BTreeMap>; -pub fn load_quest(bin_path: PathBuf, dat_path: PathBuf) -> Option { - let dat_file = File::open(PathBuf::from("data/quests/").join(dat_path.clone())) +pub fn load_quest(bin_path: PathBuf, dat_path: PathBuf, quest_path: PathBuf) -> Option { + let dat_file = File::open(quest_path.join(dat_path.clone())) .map_err(|err| { warn!("could not load quest file {:?}: {:?}", dat_path, err) }).ok()?; - //let bin_file = File::open(format!("data/quests/{}", bin_path)) - let bin_file = File::open(PathBuf::from("data/quests/").join(bin_path.clone())) + let bin_file = File::open(quest_path.join(bin_path.clone())) .map_err(|err| { warn!("could not load quest file {:?}: {:?}", bin_path, err) }).ok()?; @@ -233,11 +232,11 @@ pub fn load_quest(bin_path: PathBuf, dat_path: PathBuf) -> Option { } -pub fn load_quests(quest_path: PathBuf) -> Result { - let mut f = File::open(quest_path).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; +pub fn load_quests(quest_path: &mut PathBuf) -> Result { + let mut f = File::open(quest_path.clone()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; let mut s = String::new(); f.read_to_string(&mut s)?; - + quest_path.pop(); // remove quests.toml from the path let mut used_quest_ids = BTreeSet::new(); let ql: BTreeMap = toml::from_str(s.as_str()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?; @@ -245,7 +244,7 @@ pub fn load_quests(quest_path: PathBuf) -> Result { let quests = category_details.quests .into_iter() .filter_map(|quest| { - load_quest(quest.bin.into(), quest.dat.into()) + load_quest(quest.bin.into(), quest.dat.into(), quest_path.to_path_buf()) .and_then(|quest | { if used_quest_ids.contains(&quest.id) { warn!("quest id already exists: {}", quest.id); @@ -278,7 +277,7 @@ mod test { // one of the other maps to be a second tower #[test] fn test_quest_with_remapped_floors() { - let pw4 = load_quest("q236-ext-bb.bin".into(), "q236-ext-bb.dat".into()).unwrap(); + let pw4 = load_quest("q236-ext-bb.bin".into(), "q236-ext-bb.dat".into(), "data/quests/bb/ep2/multi".into()).unwrap(); let enemies_not_in_tower = pw4.enemies.iter() .filter(|enemy| { enemy.is_some() diff --git a/src/ship/room.rs b/src/ship/room.rs index bd142b7..588870d 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -10,6 +10,9 @@ use crate::entity::character::SectionID; use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats}; use crate::ship::map::area::MapAreaLookup; use crate::ship::map::enemy::RareMonsterAppearTable; +use crate::ship::quests; +use std::path::PathBuf; + #[derive(Debug, Error)] #[error("")] @@ -18,6 +21,7 @@ pub enum RoomCreationError { InvalidEpisode(u8), InvalidDifficulty(u8), CouldNotLoadMonsterStats(RoomMode), + CouldNotLoadQuests, } #[derive(Debug, Copy, Clone, derive_more::Display)] @@ -97,19 +101,23 @@ impl From for u8 { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, derive_more::Display)] pub enum RoomMode { + #[display(fmt="single")] Single { episode: Episode, difficulty: Difficulty, }, + #[display(fmt="multi")] Multi { episode: Episode, difficulty: Difficulty, }, + #[display(fmt="challenge")] Challenge { episode: Episode, }, + #[display(fmt="battle")] Battle { episode: Episode, difficulty: Difficulty, @@ -171,6 +179,7 @@ pub struct RoomState { pub monster_stats: Box>, pub map_areas: MapAreaLookup, pub rare_monster_table: Box, + pub quests: quests::QuestList, // items on ground // enemy info } @@ -236,6 +245,14 @@ impl RoomState { }; let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode()); + let mut qpath = PathBuf::from("data/quests/bb"); + qpath.push(room_mode.episode().to_string()); + qpath.push(room_mode.to_string()); + qpath.push("quests.toml"); + let room_quests = match quests::load_quests(&mut qpath) { + Ok(qlist) => qlist, + Err(_) => return Err(RoomCreationError::CouldNotLoadQuests), + }; Ok(RoomState { monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode))?), @@ -249,6 +266,7 @@ impl RoomState { drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)), bursting: false, map_areas: MapAreaLookup::new(&room_mode.episode()), + quests: room_quests, }) } } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index d784677..2774266 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -401,7 +401,6 @@ impl ShipServerStateBuilder { level_table: CharacterLevelTable::default(), name: self.name.unwrap_or_else(|| "NAMENOTSET".into()), item_manager: items::ItemManager::default(), - quests: quests::load_quests("data/quests.toml".into()).unwrap(), ip: self.ip.unwrap_or_else(|| Ipv4Addr::new(127,0,0,1)), port: self.port.unwrap_or(SHIP_PORT), shops: Box::new(ItemShops::default()), @@ -446,7 +445,6 @@ pub struct ShipServerState { level_table: CharacterLevelTable, name: String, item_manager: items::ItemManager, - quests: quests::QuestList, shops: Box, pub blocks: Blocks, @@ -607,8 +605,9 @@ impl ServerState for ShipServerState { .await?.into_iter().map(move |pkt| (id, pkt))) }, RecvShipPacket::QuestDetailRequest(questdetailrequest) => { + let block = self.blocks.with_client(id, &self.clients)?; match questdetailrequest.menu { - QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &self.quests)?, + QUEST_SELECT_MENU_ID => handler::quest::quest_detail(id, questdetailrequest, &block.client_location, &mut block.rooms)?, _ => unreachable!(), } }, @@ -626,13 +625,13 @@ impl ServerState for ShipServerState { Box::new(leave_lobby.chain(select_block)) } ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &mut self.clients, &mut self.item_manager, &self.level_table, &mut block.rooms)?, - QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &self.quests)?, + QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &mut block.rooms)?, _ => unreachable!(), } }, RecvShipPacket::QuestMenuSelect(questmenuselect) => { let block = self.blocks.with_client(id, &self.clients)?; - handler::quest::player_chose_quest(id, questmenuselect, &self.quests, &mut self.clients, &block.client_location, &mut block.rooms)? + handler::quest::player_chose_quest(id, questmenuselect, &mut self.clients, &block.client_location, &mut block.rooms)? }, RecvShipPacket::MenuDetail(_menudetail) => { //unreachable!(); @@ -710,13 +709,16 @@ impl ServerState for ShipServerState { Box::new(handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_manager, &self.level_table, &mut block.rooms, &mut self.entity_gateway).await?.into_iter()) }, RecvShipPacket::RequestQuestList(_) => { - handler::quest::send_quest_category_list(id, &self.quests)? + let block = self.blocks.with_client(id, &self.clients)?; + handler::quest::send_quest_category_list(id, &block.client_location, &mut block.rooms)? }, RecvShipPacket::QuestFileRequest(quest_file_request) => { - handler::quest::quest_file_request(id, quest_file_request, &self.quests)? + let block = self.blocks.with_client(id, &self.clients)?; + handler::quest::quest_file_request(id, quest_file_request, &block.client_location, &mut block.rooms)? }, RecvShipPacket::QuestChunkAck(quest_chunk_ack) => { - handler::quest::quest_chunk_ack(id, quest_chunk_ack, &self.quests)? + let block = self.blocks.with_client(id, &self.clients)?; + handler::quest::quest_chunk_ack(id, quest_chunk_ack, &block.client_location, &mut block.rooms)? }, RecvShipPacket::DoneLoadingQuest(_) => { let block = self.blocks.with_client(id, &self.clients)?;