basic item drop logic
This commit is contained in:
parent
663797e55b
commit
4a526e7673
@ -7,6 +7,7 @@ pub mod unit;
|
||||
pub mod mag;
|
||||
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::ship::map::MapArea;
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug, Hash, Eq)]
|
||||
pub struct ItemEntityId(pub u32);
|
||||
@ -27,8 +28,10 @@ pub enum ItemLocation {
|
||||
slot: BankName,
|
||||
},
|
||||
Floor {
|
||||
// floor: eventually
|
||||
// x y z: ?????
|
||||
map_area: MapArea,
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
},
|
||||
/*Destroyed {
|
||||
// marks an item that has been consumed in some way
|
||||
|
@ -11,7 +11,9 @@ use crate::entity::item::shield::Shield;
|
||||
use crate::entity::item::unit::Unit;
|
||||
use crate::entity::item::tool::Tool;
|
||||
use crate::entity::item::mag::Mag;
|
||||
use crate::entity::item::Meseta;
|
||||
use crate::entity::item::{Meseta, NewItemEntity};
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -22,12 +24,12 @@ enum ItemInstance {
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ActiveItemId(u32);
|
||||
pub struct ActiveItemId(pub u32);
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ActiveItem {
|
||||
id: ActiveItemId,
|
||||
pub id: ActiveItemId,
|
||||
item: ItemInstance,
|
||||
}
|
||||
|
||||
@ -108,6 +110,14 @@ fn inventory_item_index(item: &ItemInstance) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ActiveItemOnFloor {
|
||||
pub map_area: MapArea,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
pub item: ActiveItem,
|
||||
}
|
||||
|
||||
fn stack_items(items: Vec<ItemEntity>) -> Vec<ItemInstance> {
|
||||
let mut stacks = HashMap::new();
|
||||
|
||||
@ -138,8 +148,6 @@ pub struct ActiveItemDatabase {
|
||||
id: u32,
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl ActiveItemDatabase {
|
||||
pub fn new() -> ActiveItemDatabase {
|
||||
ActiveItemDatabase {
|
||||
@ -155,7 +163,7 @@ impl ActiveItemDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
// deactivate item
|
||||
// TODO: deactivate item
|
||||
|
||||
pub fn get_character_inventory<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> ActiveInventory {
|
||||
let items = entity_gateway.get_items_by_character(&character);
|
||||
@ -173,6 +181,50 @@ impl ActiveItemDatabase {
|
||||
let activated = stacked.into_iter().map(|i| self.activate_item(i));
|
||||
ActiveInventory(activated.take(30).collect())
|
||||
}
|
||||
|
||||
// TODO: Result
|
||||
pub fn activate_item_drop<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, item_drop: ItemDrop) -> ActiveItemOnFloor {
|
||||
let item_detail = match item_drop.item {
|
||||
ItemDropType::Weapon(w) => Some(ItemDetail::Weapon(w)),
|
||||
ItemDropType::Armor(w) => Some(ItemDetail::Armor(w)),
|
||||
ItemDropType::Shield(w) => Some(ItemDetail::Shield(w)),
|
||||
ItemDropType::Unit(w) => Some(ItemDetail::Unit(w)),
|
||||
ItemDropType::Tool(w) => Some(ItemDetail::Tool(w)),
|
||||
ItemDropType::TechniqueDisk(w) => Some(ItemDetail::TechniqueDisk(w)),
|
||||
ItemDropType::Mag(w) => Some(ItemDetail::Mag(w)),
|
||||
ItemDropType::Meseta(_) => None
|
||||
};
|
||||
let item_instance = match item_detail {
|
||||
Some(item) => {
|
||||
let item_entity = entity_gateway.create_item(NewItemEntity {
|
||||
item: item,
|
||||
location: ItemLocation::Floor {
|
||||
map_area: item_drop.map_area,
|
||||
x: item_drop.x,
|
||||
y: item_drop.y,
|
||||
z: item_drop.z,
|
||||
}
|
||||
}).unwrap();
|
||||
stack_items(vec![item_entity]).pop().unwrap()
|
||||
},
|
||||
None => {
|
||||
let meseta = match item_drop.item {
|
||||
ItemDropType::Meseta(m) => m,
|
||||
_ => panic!(),
|
||||
};
|
||||
ItemInstance::Meseta(Meseta(meseta))
|
||||
}
|
||||
};
|
||||
let active_item = self.activate_item(item_instance);
|
||||
|
||||
ActiveItemOnFloor {
|
||||
map_area: item_drop.map_area,
|
||||
x: item_drop.x,
|
||||
y: item_drop.y,
|
||||
z: item_drop.z,
|
||||
item: active_item,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
33
src/ship/packet/builder/message.rs
Normal file
33
src/ship/packet/builder/message.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use std::collections::HashMap;
|
||||
use libpso::packet::ship::*;
|
||||
use libpso::packet::messages::*;
|
||||
use crate::common::serverstate::ClientId;
|
||||
use crate::common::leveltable::CharacterLevelTable;
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients};
|
||||
use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder};
|
||||
use crate::ship::location::{ClientLocation, LobbyId, AreaClient, ClientLocationError};
|
||||
use crate::entity::character::CharacterEntity;
|
||||
use crate::ship::items::{ActiveInventory, ActiveItemOnFloor};
|
||||
use crate::ship::packet::builder::{player_header, player_info};
|
||||
use std::convert::TryInto;
|
||||
use libpso::character::character::{Inventory, InventoryItem};
|
||||
use libpso::utf8_to_utf16_array;
|
||||
|
||||
|
||||
pub fn item_drop(client: u8, target: u8, item_drop: &ActiveItemOnFloor) -> Result<ItemDrop, ShipError> {
|
||||
let item_bytes = item_drop.item.as_client_bytes();
|
||||
Ok(ItemDrop {
|
||||
client: client,
|
||||
target: target,
|
||||
area: item_drop.map_area.area_value(),
|
||||
variety: 0,
|
||||
unknown: 0,
|
||||
x: item_drop.x,
|
||||
z: item_drop.z,
|
||||
y: item_drop.y,
|
||||
item_bytes: item_bytes[0..12].try_into()?,
|
||||
item_id: item_drop.item.id.0,
|
||||
item_bytes2: item_bytes[12..16].try_into()?,
|
||||
unknown2: 0,
|
||||
})
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
pub mod lobby;
|
||||
pub mod message;
|
||||
pub mod room;
|
||||
|
||||
use libpso::character::character::Inventory;
|
||||
|
@ -6,10 +6,14 @@ use crate::common::serverstate::ClientId;
|
||||
use crate::common::leveltable::CharacterLevelTable;
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients, Rooms};
|
||||
use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder};
|
||||
use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS};
|
||||
use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS, ClientLocationError};
|
||||
use crate::ship::room::RoomState;
|
||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||
use crate::ship::items::ActiveItemDatabase;
|
||||
use libpso::character::character;
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use libpso::{utf8_to_array, utf8_to_utf16_array};
|
||||
use crate::ship::packet::builder;
|
||||
|
||||
fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation)
|
||||
-> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
|
||||
@ -20,8 +24,6 @@ fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location:
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn guildcard_send(id: ClientId,
|
||||
guildcard_send: &GuildcardSend,
|
||||
target: u32,
|
||||
@ -46,3 +48,57 @@ pub fn guildcard_send(id: ClientId,
|
||||
};
|
||||
send_to_client(id, target as u8, msg, &client_location)
|
||||
}
|
||||
|
||||
pub fn request_item<EG>(id: ClientId,
|
||||
request_item: &RequestItem,
|
||||
entity_gateway: &mut EG,
|
||||
client_location: &ClientLocation,
|
||||
clients: &mut Clients,
|
||||
rooms: &mut Rooms,
|
||||
active_items: &mut ActiveItemDatabase)
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError>
|
||||
where EG: EntityGateway {
|
||||
let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
let mut 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 monster = room.maps.enemy_by_id(request_item.enemy_id as usize)?;
|
||||
if monster.dropped_item {
|
||||
return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id))
|
||||
}
|
||||
|
||||
let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
|
||||
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_drop(&monster.map_area, &monster.monster).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: monster.map_area,
|
||||
x: request_item.x,
|
||||
y: request_item.y,
|
||||
z: request_item.z,
|
||||
item: item_drop_type,
|
||||
};
|
||||
|
||||
let activated_item = active_items.activate_item_drop(entity_gateway, item_drop);
|
||||
let mut client = clients.get_mut(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client))?;
|
||||
let item_drop_msg = builder::message::item_drop(request_item.client, request_item.target, &activated_item)?;
|
||||
client.floor_items.push(activated_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::<Vec<_>>(); // TODO: can EntityGateway be Sync?
|
||||
|
||||
Ok(Box::new(item_drop_packets.into_iter()))
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ pub fn request_exp(id: ClientId,
|
||||
match client_location.get_area(id).unwrap() {
|
||||
RoomLobby::Room(room) => {
|
||||
let r = rooms[room.0].as_ref().unwrap();
|
||||
warn!("killed a {:?}", r.maps.enemy_by_id(request_exp.enemy_id as usize).monster);
|
||||
warn!("killed a {:?}", r.maps.enemy_by_id(request_exp.enemy_id as usize).unwrap().monster);
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
|
@ -42,6 +42,8 @@ pub enum ShipError {
|
||||
ClientLocationError(#[from] ClientLocationError),
|
||||
MapsError(#[from] MapsError),
|
||||
InvalidRoom(u32),
|
||||
MonsterAlreadyDroppedItem(ClientId, u16),
|
||||
SliceError(#[from] std::array::TryFromSliceError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -147,6 +149,7 @@ pub struct ClientState {
|
||||
//guildcard: GuildCard,
|
||||
pub inventory: items::ActiveInventory,
|
||||
//bank: Bank,
|
||||
pub floor_items: Vec<items::ActiveItemOnFloor>,
|
||||
pub block: u32,
|
||||
}
|
||||
|
||||
@ -159,6 +162,7 @@ impl ClientState {
|
||||
session: session,
|
||||
inventory: inventory,
|
||||
//bank: bank,
|
||||
floor_items: Vec::new(),
|
||||
block: 1,
|
||||
}
|
||||
}
|
||||
@ -209,6 +213,9 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
||||
GameMessage::GuildcardSend(guildcard_send) => {
|
||||
handler::direct_message::guildcard_send(id, guildcard_send, target, &self.client_location, &self.clients)
|
||||
},
|
||||
GameMessage::RequestItem(request_item) => {
|
||||
handler::direct_message::request_item(id, request_item, &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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user