diff --git a/src/ship/packet/handler/quest.rs b/src/ship/packet/handler/quest.rs index a0c621e..c1c3f9f 100644 --- a/src/ship/packet/handler/quest.rs +++ b/src/ship/packet/handler/quest.rs @@ -41,7 +41,7 @@ pub fn send_quest_category_list(id: ClientId, rql: &RequestQuestList, client_loc 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[rql.flag as usize]); + let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]); room.set_quest_group(rql.flag as usize); Ok(Box::new(vec![(id, SendShipPacket::QuestCategoryList(qcl))].into_iter())) } @@ -51,7 +51,7 @@ pub fn select_quest_category(id: ClientId, menuselect: &MenuSelect, client_locat 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[room.quest_group].iter() // TODO: error handling for invalid quest group + let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(menuselect.item as usize) .ok_or(ShipError::InvalidQuestCategory(menuselect.item))?; @@ -68,7 +68,7 @@ pub fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, clien 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[room.quest_group].iter() + let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(questdetailrequest.category as usize) .ok_or(ShipError::InvalidQuestCategory(questdetailrequest.category as u32))?; @@ -88,7 +88,7 @@ pub fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, clien 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[room.quest_group].iter() + let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(questmenuselect.category as usize) .ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))?; @@ -121,7 +121,7 @@ pub fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, c .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?; - let (_, category_quests) = room.quests[room.quest_group].iter() + let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(category_id as usize) .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; @@ -150,7 +150,7 @@ pub fn quest_chunk_ack(id: ClientId, quest_chunk_ack: &QuestChunkAck, client_loc .ok_or(ShipError::InvalidRoom(room_id.0 as u32))?; let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?; - let (_, category_quests) = room.quests[room.quest_group].iter() + let (_, category_quests) = room.quests[room.quest_group.value()].iter() .nth(category_id as usize) .ok_or(ShipError::InvalidQuestCategory(category_id as u32))?; diff --git a/src/ship/room.rs b/src/ship/room.rs index 53ac14f..0ed4421 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -165,7 +165,29 @@ impl RoomMode { } } } +pub enum QuestCategoryType { + Standard, + Government, +} + +impl From for QuestCategoryType { + fn from(f: usize) -> QuestCategoryType { + match f { + 0 => QuestCategoryType::Standard, + 1 => QuestCategoryType::Government, + _ => QuestCategoryType::Standard, // TODO: panic? + } + } +} +impl QuestCategoryType { + pub fn value(&self) -> usize { + match self { + QuestCategoryType::Standard => 0, + QuestCategoryType::Government => 1, + } + } +} pub struct RoomState { pub mode: RoomMode, @@ -179,7 +201,7 @@ pub struct RoomState { pub monster_stats: Box>, pub map_areas: MapAreaLookup, pub rare_monster_table: Box, - pub quest_group: usize, + pub quest_group: QuestCategoryType, pub quests: Vec, // items on ground // enemy info @@ -217,7 +239,7 @@ impl RoomState { } pub fn set_quest_group(&mut self, group: usize) { - self.quest_group = group; + self.quest_group = QuestCategoryType::from(group); } pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, section_id: SectionID) -> Result { @@ -292,7 +314,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()), - quest_group: 0, + quest_group: QuestCategoryType::Standard, quests: room_quests, }) } diff --git a/tests/test_rooms.rs b/tests/test_rooms.rs index 70dbdf4..a03fdd6 100644 --- a/tests/test_rooms.rs +++ b/tests/test_rooms.rs @@ -114,4 +114,46 @@ async fn test_load_rare_monster_default_appear_rates() { for (_monster, rate) in rates.clone().appear_rate { assert_eq!(rate, 0.001953125f32); // 1/512 = 0.001953125 } +} + +#[async_std::test] +async fn test_set_valid_quest_group() { + let mut entity_gateway = InMemoryGateway::default(); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let mut ship = Box::new(ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build()); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + + let packets = ship.handle(ClientId(1), &RecvShipPacket::RequestQuestList(RequestQuestList{flag: 0})).await.unwrap().collect::>(); + match &packets[0].1 { + SendShipPacket::QuestCategoryList(quest_cat) => { + assert!(String::from_utf16_lossy(&quest_cat.quest_categories[0].name).starts_with("Retrieval")); + }, + _ => panic!("Wrong quest category"), + } +} + +#[async_std::test] +async fn test_set_invalid_quest_group() { + let mut entity_gateway = InMemoryGateway::default(); + let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let mut ship = Box::new(ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build()); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + + let packets = ship.handle(ClientId(1), &RecvShipPacket::RequestQuestList(RequestQuestList{flag: 100})).await.unwrap().collect::>(); + match &packets[0].1 { + SendShipPacket::QuestCategoryList(quest_cat) => { + // flag > quest category length should take the highest value allowed for quest category which is 1 in multimode (for govt quests) and 0 in other modes. + // assuming we create an ep1 room in multimode, we should load the government quests in this test case + assert!(String::from_utf16_lossy(&quest_cat.quest_categories[0].name).starts_with("Government")); + }, + _ => panic!("Wrong quest category"), + } } \ No newline at end of file