|
|
@ -11,6 +11,7 @@ use rand::Rng; |
|
|
|
use crate::ship::map::Maps;
|
|
|
|
use crate::ship::drops::DropTable;
|
|
|
|
use crate::entity::character::SectionID;
|
|
|
|
use crate::entity::room::{RoomEntityId, RoomEntityMode};
|
|
|
|
use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats};
|
|
|
|
use crate::ship::map::area::MapAreaLookup;
|
|
|
|
use crate::ship::quests;
|
|
|
@ -55,7 +56,7 @@ impl Rooms { |
|
|
|
None => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result<T, anyhow::Error>
|
|
|
|
where
|
|
|
|
T: Send,
|
|
|
@ -92,7 +93,7 @@ impl Rooms { |
|
|
|
Err(ShipError::InvalidRoom(room_id.0 as u32).into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard<Option<RoomState>> {
|
|
|
|
self.0
|
|
|
|
.get(room_id.0)
|
|
|
@ -282,8 +283,15 @@ impl From<usize> for QuestCategoryType { |
|
|
|
fn from(f: usize) -> QuestCategoryType {
|
|
|
|
match f {
|
|
|
|
0 => QuestCategoryType::Standard,
|
|
|
|
1 => QuestCategoryType::Government,
|
|
|
|
_ => QuestCategoryType::Standard, // TODO: panic?
|
|
|
|
_ => QuestCategoryType::Government,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl From<u32> for QuestCategoryType {
|
|
|
|
fn from(f: u32) -> QuestCategoryType {
|
|
|
|
match f {
|
|
|
|
0 => QuestCategoryType::Standard,
|
|
|
|
_ => QuestCategoryType::Government,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -298,6 +306,7 @@ impl QuestCategoryType { |
|
|
|
}
|
|
|
|
|
|
|
|
pub struct RoomState {
|
|
|
|
pub room_id: RoomEntityId,
|
|
|
|
pub mode: RoomMode,
|
|
|
|
pub name: String,
|
|
|
|
pub password: [u16; 16],
|
|
|
@ -309,22 +318,22 @@ pub struct RoomState { |
|
|
|
pub monster_stats: Box<HashMap<MonsterType, MonsterStats>>,
|
|
|
|
pub map_areas: MapAreaLookup,
|
|
|
|
pub quest_group: QuestCategoryType,
|
|
|
|
pub quests: Vec<quests::QuestList>,
|
|
|
|
// items on ground
|
|
|
|
pub standard_quests: quests::QuestList,
|
|
|
|
pub government_quests: quests::QuestList,
|
|
|
|
// enemy info
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RoomState {
|
|
|
|
pub fn get_flags_for_room_list(&self) -> u8 {
|
|
|
|
let mut flags = 0u8;
|
|
|
|
|
|
|
|
|
|
|
|
match self.mode {
|
|
|
|
RoomMode::Single {..} => {flags += 0x04}
|
|
|
|
RoomMode::Battle {..} => {flags += 0x10},
|
|
|
|
RoomMode::Challenge {..} => {flags += 0x20},
|
|
|
|
_ => {flags += 0x40},
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if self.password[0] > 0 {
|
|
|
|
flags += 0x02;
|
|
|
|
}
|
|
|
@ -345,85 +354,58 @@ impl RoomState { |
|
|
|
difficulty + 0x22
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_quest_group(&mut self, group: usize) {
|
|
|
|
self.quest_group = QuestCategoryType::from(group);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom,
|
|
|
|
map_builder: Arc<Box<dyn Fn(RoomMode, ShipEvent) -> Maps + Send + Sync>>,
|
|
|
|
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
|
|
|
|
section_id: SectionID,
|
|
|
|
event: ShipEvent)
|
|
|
|
-> Result<RoomState, RoomCreationError> {
|
|
|
|
if [create_room.battle, create_room.challenge, create_room.single_player].iter().sum::<u8>() > 1 {
|
|
|
|
return Err(RoomCreationError::InvalidMode)
|
|
|
|
}
|
|
|
|
|
|
|
|
let room_mode = if create_room.battle == 1 {
|
|
|
|
RoomMode::Battle {
|
|
|
|
episode: create_room.episode.try_into()?,
|
|
|
|
difficulty: create_room.difficulty.try_into()?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if create_room.challenge == 1 {
|
|
|
|
RoomMode::Challenge {
|
|
|
|
episode: create_room.episode.try_into()?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if create_room.single_player == 1 {
|
|
|
|
RoomMode::Single {
|
|
|
|
episode: create_room.episode.try_into()?,
|
|
|
|
difficulty: create_room.difficulty.try_into()?,
|
|
|
|
}
|
|
|
|
pub fn quests(&self) -> &quests::QuestList {
|
|
|
|
match self.quest_group {
|
|
|
|
QuestCategoryType::Standard => &self.standard_quests,
|
|
|
|
QuestCategoryType::Government => &self.government_quests,
|
|
|
|
}
|
|
|
|
else { // normal multimode
|
|
|
|
RoomMode::Multi {
|
|
|
|
episode: create_room.episode.try_into()?,
|
|
|
|
difficulty: create_room.difficulty.try_into()?,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// push the usual set of quests for the selected mode
|
|
|
|
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 mut room_quests = Vec::new();
|
|
|
|
let quest_list = match quests::load_quests(qpath) {
|
|
|
|
Ok(qlist) => qlist,
|
|
|
|
Err(_) => return Err(RoomCreationError::CouldNotLoadQuests),
|
|
|
|
pub fn new (room_id: RoomEntityId,
|
|
|
|
mode: RoomEntityMode,
|
|
|
|
episode: Episode,
|
|
|
|
difficulty: Difficulty,
|
|
|
|
section_id: SectionID,
|
|
|
|
name: String,
|
|
|
|
password: [u16; 16],
|
|
|
|
event: ShipEvent,
|
|
|
|
map_builder: Arc<Box<dyn Fn(RoomMode, ShipEvent) -> Maps + Send + Sync>>,
|
|
|
|
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
|
|
|
|
) -> Result<RoomState, anyhow::Error> {
|
|
|
|
let mode = match mode {
|
|
|
|
RoomEntityMode::Single => RoomMode::Single {
|
|
|
|
episode,
|
|
|
|
difficulty,
|
|
|
|
},
|
|
|
|
RoomEntityMode::Multi => RoomMode::Multi {
|
|
|
|
episode,
|
|
|
|
difficulty,
|
|
|
|
},
|
|
|
|
RoomEntityMode::Challenge => RoomMode::Challenge {
|
|
|
|
episode,
|
|
|
|
},
|
|
|
|
RoomEntityMode::Battle => RoomMode::Battle {
|
|
|
|
episode,
|
|
|
|
difficulty,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
room_quests.push(quest_list);
|
|
|
|
|
|
|
|
// if multiplayer also push the government quests
|
|
|
|
if let RoomMode::Multi {..} = room_mode {
|
|
|
|
qpath = PathBuf::from("data/quests/bb/");
|
|
|
|
qpath.push(room_mode.episode().to_string());
|
|
|
|
qpath.push("government/quests.toml");
|
|
|
|
|
|
|
|
let quest_list = match quests::load_quests(qpath) {
|
|
|
|
Ok(qlist) => qlist,
|
|
|
|
Err(_) => return Err(RoomCreationError::CouldNotLoadQuests),
|
|
|
|
};
|
|
|
|
|
|
|
|
room_quests.push(quest_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(RoomState {
|
|
|
|
monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode))?),
|
|
|
|
mode: room_mode,
|
|
|
|
room_id,
|
|
|
|
monster_stats: Box::new(load_monster_stats_table(&mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(mode))?),
|
|
|
|
mode,
|
|
|
|
random_seed: rand::thread_rng().gen(),
|
|
|
|
name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(),
|
|
|
|
password: create_room.password,
|
|
|
|
maps: map_builder(room_mode, event),
|
|
|
|
name,
|
|
|
|
password,
|
|
|
|
maps: map_builder(mode, event),
|
|
|
|
section_id,
|
|
|
|
drop_table: Box::new(drop_table_builder(room_mode.episode(), room_mode.difficulty(), section_id)),
|
|
|
|
drop_table: Box::new(drop_table_builder(episode, difficulty, section_id)),
|
|
|
|
bursting: false,
|
|
|
|
map_areas: MapAreaLookup::new(&room_mode.episode()),
|
|
|
|
map_areas: MapAreaLookup::new(&episode),
|
|
|
|
quest_group: QuestCategoryType::Standard,
|
|
|
|
quests: room_quests,
|
|
|
|
standard_quests: quests::load_standard_quests(mode)?,
|
|
|
|
government_quests: quests::load_government_quests(mode)?,
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|