diff --git a/src/ship/map.rs b/src/ship/map.rs index c4c8ac2..63e5a1b 100644 --- a/src/ship/map.rs +++ b/src/ship/map.rs @@ -217,7 +217,7 @@ struct RawMapObject { impl RawMapObject { fn from_byte_stream(cursor: &mut R) -> Result { - Ok(RawMapObject { + let o = RawMapObject { otype: cursor.read_u16::()?, unknown1: cursor.read_u16::()?, unknown2: cursor.read_u32::()?, @@ -238,7 +238,11 @@ impl RawMapObject { field5: cursor.read_u32::()?, field6: cursor.read_u32::()?, field7: cursor.read_u32::()?, - }) + }; + + println!("{:?}", o); + + Ok(o) } } @@ -310,6 +314,8 @@ pub enum MapObjectType { #[derive(Debug, Copy, Clone)] pub struct MapObject { pub object: MapObjectType, + pub map: MapArea, + pub dropped_item: bool, //id: u32, } @@ -320,7 +326,7 @@ enum MapObjectError { impl MapObject { - fn from_raw(raw: RawMapObject, episode: Episode) -> Result { + fn from_raw(raw: RawMapObject, episode: Episode, map_area: &MapArea) -> Result { let object = match (raw, episode) { (RawMapObject {otype: 136, ..}, _) => MapObjectType::Box, (RawMapObject {otype: 145, ..}, _) => MapObjectType::EnemyBox, @@ -335,8 +341,11 @@ impl MapObject { _ => return Err(MapObjectError::UnknownObjectType(raw.otype, raw)) }; + println!("{:#?}", object); Ok(MapObject { object: object, + map: map_area.clone(), + dropped_item: false, }) } } @@ -496,7 +505,7 @@ impl MapVariant { fn obj_file(&self) -> String { match self.map { - MapArea::Pioneer2Ep1 => "data/maps/map_city00_00e.dat".into(), + MapArea::Pioneer2Ep1 => "data/maps/map_city00_00o.dat".into(), MapArea::Forest1 => format!("data/maps/map_forest01_0{}o.dat", self.minor), MapArea::Forest2 => format!("data/maps/map_forest02_0{}o.dat", self.minor), MapArea::Caves1 => format!("data/maps/map_cave01_0{}_0{}o.dat", self.major, self.minor), @@ -520,12 +529,12 @@ impl MapVariant { } -fn objects_from_map_data(path: PathBuf, episode: &Episode) -> Vec> { +fn objects_from_map_data(path: PathBuf, episode: &Episode, map_variant: &MapVariant) -> Vec> { let mut cursor = File::open(path.clone()).unwrap(); let mut object_data = Vec::new(); while let Ok(raw_object) = RawMapObject::from_byte_stream(&mut cursor) { - let object = MapObject::from_raw(raw_object.clone(), *episode); + let object = MapObject::from_raw(raw_object.clone(), *episode, &map_variant.map); object_data.push(object.ok()); } @@ -631,6 +640,7 @@ fn enemy_data_from_map_data(map_variant: &MapVariant, episode: &Episode) -> Vec< #[error("")] pub enum MapsError { InvalidMonsterId(usize), + InvalidObjectId(usize), } #[derive(Debug)] @@ -670,7 +680,7 @@ impl Maps { enemy_data }), object_data: map_variants.iter().map(|map_variant| { - objects_from_map_data(map_variant.obj_file().into(), &episode) + objects_from_map_data(map_variant.obj_file().into(), &episode, &map_variant) }).flatten().collect(), map_variants: map_variants, }; @@ -682,6 +692,10 @@ impl Maps { self.enemy_data[id].ok_or(MapsError::InvalidMonsterId(id)) } + pub fn object_by_id(&self, id: usize) -> Result { + self.object_data[id].ok_or(MapsError::InvalidObjectId(id)) + } + pub fn map_headers(&self) -> [u32; 0x20] { self.map_variants.iter() .enumerate() diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs index 8edb708..f2c4e5f 100644 --- a/src/ship/packet/handler/direct_message.rs +++ b/src/ship/packet/handler/direct_message.rs @@ -139,3 +139,56 @@ where } } +pub fn request_box_item(id: ClientId, + box_drop_request: &BoxDropRequest, + entity_gateway: &mut EG, + client_location: &ClientLocation, + clients: &mut Clients, + rooms: &mut Rooms, + item_manager: &mut ItemManager) + -> Result + Send>, ShipError> +where +EG: EntityGateway +{ + let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?; + let room = rooms.get_mut(room_id.0) + .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))? + .as_mut() + .ok_or_else(|| ShipError::InvalidRoom(room_id.0 as u32))?; + + let box_object = room.maps.object_by_id(box_drop_request.object_id as usize)?; + if box_object.dropped_item { + return Err(ShipError::BoxAlreadyDroppedItem(id, box_drop_request.object_id)) + } + + let clients_in_area = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; + + let item_drop_packets = clients_in_area.into_iter() + .filter_map(|area_client| { + room.drop_table.get_box_drop(&box_object.map, &box_object).map(|item_drop_type| { + warn!("drop is? {:?}", item_drop_type); + (area_client, item_drop_type) + }) + }) + .map(|(area_client, item_drop_type)| -> Result<_, ShipError> { + let item_drop = ItemDrop { + map_area: box_object.map, + x: box_drop_request.x, + y: 0.0, + z: box_drop_request.z, + item: item_drop_type, + }; + let client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?; + let floor_item = item_manager.drop_item_on_local_floor(entity_gateway, &client.character, item_drop).unwrap(); // TODO: unwrap + let item_drop_msg = builder::message::item_drop(box_drop_request.client, box_drop_request.target, &floor_item)?; + client.floor_items.push(floor_item); + Ok((area_client.client, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(item_drop_msg))))) + }) + .filter_map(|item_drop_pkt| { + // TODO: log errors here + item_drop_pkt.ok() + }) + .collect::>(); // TODO: can EntityGateway be Sync? + + Ok(Box::new(item_drop_packets.into_iter())) +} \ No newline at end of file diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 05a2c28..52f537d 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -50,6 +50,7 @@ pub enum ShipError { DropInvalidItemId(u32), ItemManagerError(#[from] items::ItemManagerError), ItemDropLocationNotSet, + BoxAlreadyDroppedItem(ClientId, u16), } #[derive(Debug)] @@ -247,6 +248,10 @@ impl ShipServerState { GameMessage::PickupItem(pickup_item) => { handler::direct_message::pickup_item(id, pickup_item, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).unwrap() }, + GameMessage::BoxDropRequest(box_drop_request) => { + println!("box drop requested!"); + handler::direct_message::request_box_item(id, box_drop_request, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.rooms, &mut self.item_database).unwrap() + } _ => { let cmsg = msg.clone(); Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter()