Merge pull request 'item drops' (#112) from itemdropsforreal into master
This commit is contained in:
commit
c28adcd7e5
@ -153,29 +153,8 @@ impl CharacterTechniques {
|
|||||||
pub fn as_bytes(&self) -> [u8; 20] {
|
pub fn as_bytes(&self) -> [u8; 20] {
|
||||||
self.techs.iter()
|
self.techs.iter()
|
||||||
.fold([0xFF; 20], |mut techlist, (tech, level)| {
|
.fold([0xFF; 20], |mut techlist, (tech, level)| {
|
||||||
let index = match tech {
|
let index = tech.as_value();
|
||||||
Technique::Foie => 0,
|
techlist[index as usize] = level.0 - 1;
|
||||||
Technique::Gifoie => 1,
|
|
||||||
Technique::Rafoie => 2,
|
|
||||||
Technique::Barta => 3,
|
|
||||||
Technique::Gibarta => 4,
|
|
||||||
Technique::Rabarta => 5,
|
|
||||||
Technique::Zonde => 6,
|
|
||||||
Technique::Gizonde => 7,
|
|
||||||
Technique::Razonde => 8,
|
|
||||||
Technique::Grants => 9,
|
|
||||||
Technique::Deband => 10,
|
|
||||||
Technique::Jellen => 11,
|
|
||||||
Technique::Zalure => 12,
|
|
||||||
Technique::Shifta => 13,
|
|
||||||
Technique::Ryuker => 14,
|
|
||||||
Technique::Resta => 15,
|
|
||||||
Technique::Anti => 16,
|
|
||||||
Technique::Reverser => 17,
|
|
||||||
Technique::Megid => 18,
|
|
||||||
};
|
|
||||||
|
|
||||||
techlist[index] = level.0 - 1;
|
|
||||||
techlist
|
techlist
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ pub mod unit;
|
|||||||
pub mod mag;
|
pub mod mag;
|
||||||
|
|
||||||
use crate::entity::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
|
use crate::ship::map::MapArea;
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone, Debug, Hash, Eq)]
|
#[derive(PartialEq, Copy, Clone, Debug, Hash, Eq)]
|
||||||
pub struct ItemEntityId(pub u32);
|
pub struct ItemEntityId(pub u32);
|
||||||
@ -27,8 +28,10 @@ pub enum ItemLocation {
|
|||||||
slot: BankName,
|
slot: BankName,
|
||||||
},
|
},
|
||||||
Floor {
|
Floor {
|
||||||
// floor: eventually
|
map_area: MapArea,
|
||||||
// x y z: ?????
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
z: f32,
|
||||||
},
|
},
|
||||||
/*Destroyed {
|
/*Destroyed {
|
||||||
// marks an item that has been consumed in some way
|
// marks an item that has been consumed in some way
|
||||||
@ -46,6 +49,7 @@ pub struct Meseta(pub u32);
|
|||||||
impl Meseta {
|
impl Meseta {
|
||||||
pub fn as_bytes(&self) -> [u8; 16] {
|
pub fn as_bytes(&self) -> [u8; 16] {
|
||||||
let mut result = [0; 16];
|
let mut result = [0; 16];
|
||||||
|
result[0] = 4;
|
||||||
result[12..16].copy_from_slice(&u32::to_le_bytes(self.0));
|
result[12..16].copy_from_slice(&u32::to_le_bytes(self.0));
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -96,7 +100,7 @@ impl ItemDetail {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct NewItemEntity {
|
pub struct NewItemEntity {
|
||||||
pub location: ItemLocation,
|
pub location: ItemLocation,
|
||||||
pub item: ItemDetail,
|
pub item: ItemDetail,
|
||||||
|
@ -24,8 +24,33 @@ pub enum Technique {
|
|||||||
Megid,
|
Megid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Technique {
|
||||||
|
pub fn as_value(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
Technique::Foie => 0,
|
||||||
|
Technique::Gifoie => 1,
|
||||||
|
Technique::Rafoie => 2,
|
||||||
|
Technique::Barta => 3,
|
||||||
|
Technique::Gibarta => 4,
|
||||||
|
Technique::Rabarta => 5,
|
||||||
|
Technique::Zonde => 6,
|
||||||
|
Technique::Gizonde => 7,
|
||||||
|
Technique::Razonde => 8,
|
||||||
|
Technique::Grants => 9,
|
||||||
|
Technique::Deband => 10,
|
||||||
|
Technique::Jellen => 11,
|
||||||
|
Technique::Zalure => 12,
|
||||||
|
Technique::Shifta => 13,
|
||||||
|
Technique::Ryuker => 14,
|
||||||
|
Technique::Resta => 15,
|
||||||
|
Technique::Anti => 16,
|
||||||
|
Technique::Reverser => 17,
|
||||||
|
Technique::Megid => 18,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct TechniqueDisk {
|
pub struct TechniqueDisk {
|
||||||
pub tech: Technique,
|
pub tech: Technique,
|
||||||
pub level: u32,
|
pub level: u32,
|
||||||
@ -33,6 +58,11 @@ pub struct TechniqueDisk {
|
|||||||
|
|
||||||
impl TechniqueDisk {
|
impl TechniqueDisk {
|
||||||
pub fn as_bytes(&self) -> [u8; 16] {
|
pub fn as_bytes(&self) -> [u8; 16] {
|
||||||
[0; 16]
|
let mut result = [0; 16];
|
||||||
|
result[0] = 3;
|
||||||
|
result[1] = 2;
|
||||||
|
result[2] = self.level as u8 - 1;
|
||||||
|
result[4] = self.tech.as_value();
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,7 +394,7 @@ impl ToolType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct Tool {
|
pub struct Tool {
|
||||||
pub tool: ToolType,
|
pub tool: ToolType,
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
// TODO: there is some structure duplication that occurs here:
|
||||||
|
// the rare and box tables instantiate their own copies of the
|
||||||
|
// generic drop tables as they need them to apply their modifiers
|
||||||
|
// to their drops
|
||||||
|
|
||||||
|
|
||||||
mod drop_table;
|
mod drop_table;
|
||||||
mod rare_drop_table;
|
mod rare_drop_table;
|
||||||
mod generic_weapon;
|
mod generic_weapon;
|
||||||
@ -78,25 +84,20 @@ pub enum ItemDropType {
|
|||||||
Shield(shield::Shield),
|
Shield(shield::Shield),
|
||||||
Unit(unit::Unit),
|
Unit(unit::Unit),
|
||||||
Tool(tool::Tool),
|
Tool(tool::Tool),
|
||||||
|
//Tools(Vec<tool::Tool>),
|
||||||
TechniqueDisk(tech::TechniqueDisk),
|
TechniqueDisk(tech::TechniqueDisk),
|
||||||
Mag(mag::Mag),
|
Mag(mag::Mag),
|
||||||
Meseta(u32),
|
Meseta(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ItemDrop {
|
pub struct ItemDrop {
|
||||||
x: f32,
|
pub map_area: MapArea,
|
||||||
y: f32,
|
pub x: f32,
|
||||||
z: f32,
|
pub y: f32,
|
||||||
item: ItemDropType,
|
pub z: f32,
|
||||||
|
pub item: ItemDropType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemDrop {
|
|
||||||
pub fn as_client_bytes(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub struct DropTable<R: Rng + SeedableRng> {
|
pub struct DropTable<R: Rng + SeedableRng> {
|
||||||
monster_stats: HashMap<MonsterType, MonsterDropStats>,
|
monster_stats: HashMap<MonsterType, MonsterDropStats>,
|
||||||
@ -110,7 +111,6 @@ pub struct DropTable<R: Rng + SeedableRng> {
|
|||||||
rng: R,
|
rng: R,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<R: Rng + SeedableRng> DropTable<R> {
|
impl<R: Rng + SeedableRng> DropTable<R> {
|
||||||
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable<R> {
|
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable<R> {
|
||||||
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
||||||
|
@ -100,7 +100,7 @@ impl TechniqueTable {
|
|||||||
let tech_weights = WeightedIndex::new(tech_rates.clone().map(|(_, stat)| stat.rate)).unwrap();
|
let tech_weights = WeightedIndex::new(tech_rates.clone().map(|(_, stat)| stat.rate)).unwrap();
|
||||||
|
|
||||||
let (tech, stat) = tech_rates.nth(tech_weights.sample(rng)).unwrap();
|
let (tech, stat) = tech_rates.nth(tech_weights.sample(rng)).unwrap();
|
||||||
let level = rng.gen_range(stat.min, stat.max+1);
|
let level = rng.gen_range(stat.min, stat.max+1) + 1;
|
||||||
|
|
||||||
Some(ItemDropType::TechniqueDisk(TechniqueDisk {
|
Some(ItemDropType::TechniqueDisk(TechniqueDisk {
|
||||||
tech: *tech,
|
tech: *tech,
|
||||||
@ -118,10 +118,10 @@ mod test {
|
|||||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed([23;32]);
|
let mut rng = rand_chacha::ChaCha20Rng::from_seed([23;32]);
|
||||||
let tt = TechniqueTable::new(Episode::One, Difficulty::Ultimate, SectionID::Skyly);
|
let tt = TechniqueTable::new(Episode::One, Difficulty::Ultimate, SectionID::Skyly);
|
||||||
|
|
||||||
let tech_tests = vec![(MapArea::Forest1, Technique::Resta, 13),
|
let tech_tests = vec![(MapArea::Forest1, Technique::Resta, 14),
|
||||||
(MapArea::Caves3, Technique::Foie, 24),
|
(MapArea::Caves3, Technique::Foie, 25),
|
||||||
(MapArea::Mines2, Technique::Gibarta, 20),
|
(MapArea::Mines2, Technique::Gibarta, 21),
|
||||||
(MapArea::DarkFalz, Technique::Razonde, 22)];
|
(MapArea::DarkFalz, Technique::Razonde, 23)];
|
||||||
|
|
||||||
for (area, tech, level) in tech_tests {
|
for (area, tech, level) in tech_tests {
|
||||||
assert!(tt.get_drop(&area, &mut rng) == Some(ItemDropType::TechniqueDisk(
|
assert!(tt.get_drop(&area, &mut rng) == Some(ItemDropType::TechniqueDisk(
|
||||||
|
@ -11,23 +11,26 @@ use crate::entity::item::shield::Shield;
|
|||||||
use crate::entity::item::unit::Unit;
|
use crate::entity::item::unit::Unit;
|
||||||
use crate::entity::item::tool::Tool;
|
use crate::entity::item::tool::Tool;
|
||||||
use crate::entity::item::mag::Mag;
|
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};
|
||||||
|
use crate::ship::ship::ShipError;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum ItemInstance {
|
enum ItemInstance {
|
||||||
Individual(ItemEntity),
|
Individual(ItemEntity),
|
||||||
Stacked(Vec<ItemEntity>),
|
Stacked(Vec<ItemEntity>),
|
||||||
Meseta(Meseta),
|
Meseta(Meseta),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct ActiveItemId(u32);
|
pub struct ActiveItemId(pub u32);
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ActiveItem {
|
pub struct ActiveItem {
|
||||||
id: ActiveItemId,
|
pub id: ActiveItemId,
|
||||||
item: ItemInstance,
|
item: ItemInstance,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +111,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> {
|
fn stack_items(items: Vec<ItemEntity>) -> Vec<ItemInstance> {
|
||||||
let mut stacks = HashMap::new();
|
let mut stacks = HashMap::new();
|
||||||
|
|
||||||
@ -138,8 +149,6 @@ pub struct ActiveItemDatabase {
|
|||||||
id: u32,
|
id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl ActiveItemDatabase {
|
impl ActiveItemDatabase {
|
||||||
pub fn new() -> ActiveItemDatabase {
|
pub fn new() -> ActiveItemDatabase {
|
||||||
ActiveItemDatabase {
|
ActiveItemDatabase {
|
||||||
@ -155,7 +164,7 @@ impl ActiveItemDatabase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// deactivate item
|
// TODO: deactivate item
|
||||||
|
|
||||||
pub fn get_character_inventory<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> ActiveInventory {
|
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);
|
let items = entity_gateway.get_items_by_character(&character);
|
||||||
@ -173,6 +182,49 @@ impl ActiveItemDatabase {
|
|||||||
let activated = stacked.into_iter().map(|i| self.activate_item(i));
|
let activated = stacked.into_iter().map(|i| self.activate_item(i));
|
||||||
ActiveInventory(activated.take(30).collect())
|
ActiveInventory(activated.take(30).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn activate_item_drop<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, item_drop: ItemDrop) -> Result<ActiveItemOnFloor, ShipError> {
|
||||||
|
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().ok_or(ShipError::ItemError)?
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let meseta = match item_drop.item {
|
||||||
|
ItemDropType::Meseta(m) => m,
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
ItemInstance::Meseta(Meseta(meseta))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let active_item = self.activate_item(item_instance);
|
||||||
|
|
||||||
|
Ok(ActiveItemOnFloor {
|
||||||
|
map_area: item_drop.map_area,
|
||||||
|
x: item_drop.x,
|
||||||
|
y: item_drop.y,
|
||||||
|
z: item_drop.z,
|
||||||
|
item: active_item,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -52,6 +52,8 @@ pub enum JoinLobbyError {
|
|||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
#[error("")]
|
#[error("")]
|
||||||
pub enum GetAreaError {
|
pub enum GetAreaError {
|
||||||
|
NotInRoom,
|
||||||
|
NotInLobby,
|
||||||
InvalidClient,
|
InvalidClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +333,24 @@ impl ClientLocation {
|
|||||||
.map(Clone::clone)
|
.map(Clone::clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_room(&self, id: ClientId) -> Result<RoomId, GetAreaError> {
|
||||||
|
if let RoomLobby::Room(room) = self.client_location.get(&id).ok_or(GetAreaError::InvalidClient)? {
|
||||||
|
Ok(*room)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(GetAreaError::NotInRoom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_lobby(&self, id: ClientId) -> Result<LobbyId, GetAreaError> {
|
||||||
|
if let RoomLobby::Lobby(lobby) = self.client_location.get(&id).ok_or(GetAreaError::InvalidClient)? {
|
||||||
|
Ok(*lobby)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(GetAreaError::NotInLobby)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_client_from_area(&mut self, id: ClientId) -> Result<(), ClientRemovalError> {
|
pub fn remove_client_from_area(&mut self, id: ClientId) -> Result<(), ClientRemovalError> {
|
||||||
let area = self.client_location.get_mut(&id).ok_or(ClientRemovalError::ClientNotInArea)?;
|
let area = self.client_location.get_mut(&id).ok_or(ClientRemovalError::ClientNotInArea)?;
|
||||||
let client_list = match area {
|
let client_list = match area {
|
||||||
|
107
src/ship/map.rs
107
src/ship/map.rs
@ -7,6 +7,7 @@ use std::fs::File;
|
|||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::ship::monster::MonsterType;
|
use crate::ship::monster::MonsterType;
|
||||||
use crate::ship::room::Episode;
|
use crate::ship::room::Episode;
|
||||||
@ -16,7 +17,7 @@ struct RawMapEnemy {
|
|||||||
id: u32,
|
id: u32,
|
||||||
_unknown1: u16,
|
_unknown1: u16,
|
||||||
children: u16,
|
children: u16,
|
||||||
_unknown3: u16,
|
map_area: u16,
|
||||||
_unknown4: u16,
|
_unknown4: u16,
|
||||||
section: u16,
|
section: u16,
|
||||||
wave_idd: u16,
|
wave_idd: u16,
|
||||||
@ -42,7 +43,7 @@ impl RawMapEnemy {
|
|||||||
id: cursor.read_u32::<LittleEndian>()?,
|
id: cursor.read_u32::<LittleEndian>()?,
|
||||||
_unknown1: cursor.read_u16::<LittleEndian>()?,
|
_unknown1: cursor.read_u16::<LittleEndian>()?,
|
||||||
children: cursor.read_u16::<LittleEndian>()?,
|
children: cursor.read_u16::<LittleEndian>()?,
|
||||||
_unknown3: cursor.read_u16::<LittleEndian>()?,
|
map_area: cursor.read_u16::<LittleEndian>()?,
|
||||||
_unknown4: cursor.read_u16::<LittleEndian>()?,
|
_unknown4: cursor.read_u16::<LittleEndian>()?,
|
||||||
section: cursor.read_u16::<LittleEndian>()?,
|
section: cursor.read_u16::<LittleEndian>()?,
|
||||||
wave_idd: cursor.read_u16::<LittleEndian>()?,
|
wave_idd: cursor.read_u16::<LittleEndian>()?,
|
||||||
@ -65,18 +66,22 @@ impl RawMapEnemy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
#[error("")]
|
||||||
enum MapEnemyError {
|
enum MapEnemyError {
|
||||||
UnknownEnemyId(u32),
|
UnknownEnemyId(u32),
|
||||||
|
MapAreaError(#[from] MapAreaError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct MapEnemy {
|
pub struct MapEnemy {
|
||||||
pub monster: MonsterType,
|
pub monster: MonsterType,
|
||||||
|
pub map_area: MapArea,
|
||||||
hp: u32,
|
hp: u32,
|
||||||
// other stats from bp.n
|
// TODO: other stats from battleparam
|
||||||
dead: bool,
|
pub dropped_item: bool,
|
||||||
|
pub gave_exp: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapEnemy {
|
impl MapEnemy {
|
||||||
@ -169,16 +174,20 @@ impl MapEnemy {
|
|||||||
|
|
||||||
Ok(MapEnemy {
|
Ok(MapEnemy {
|
||||||
monster: monster,
|
monster: monster,
|
||||||
|
map_area: MapArea::from_value(&episode, enemy.map_area as u32)?,
|
||||||
hp: 0,
|
hp: 0,
|
||||||
dead: false,
|
dropped_item: false,
|
||||||
|
gave_exp: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(monster: MonsterType) -> MapEnemy {
|
fn new(monster: MonsterType, map_area: MapArea) -> MapEnemy {
|
||||||
MapEnemy {
|
MapEnemy {
|
||||||
monster: monster,
|
monster: monster,
|
||||||
|
map_area: map_area,
|
||||||
hp: 0,
|
hp: 0,
|
||||||
dead: false,
|
dropped_item: false,
|
||||||
|
gave_exp: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,7 +349,7 @@ enum MapVariantMode {
|
|||||||
Offline,
|
Offline,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum MapArea {
|
pub enum MapArea {
|
||||||
Pioneer2Ep1,
|
Pioneer2Ep1,
|
||||||
Forest1,
|
Forest1,
|
||||||
@ -359,12 +368,14 @@ pub enum MapArea {
|
|||||||
DarkFalz,
|
DarkFalz,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error("")]
|
||||||
pub enum MapAreaError {
|
pub enum MapAreaError {
|
||||||
UnknownMapArea(u32),
|
UnknownMapArea(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapArea {
|
impl MapArea {
|
||||||
pub fn from_value(episode: Episode, area: u32) -> Result<MapArea, MapAreaError> {
|
pub fn from_value(episode: &Episode, area: u32) -> Result<MapArea, MapAreaError> {
|
||||||
match (episode, area) {
|
match (episode, area) {
|
||||||
(Episode::One, 0) => Ok(MapArea::Pioneer2Ep1),
|
(Episode::One, 0) => Ok(MapArea::Pioneer2Ep1),
|
||||||
(Episode::One, 1) => Ok(MapArea::Forest1),
|
(Episode::One, 1) => Ok(MapArea::Forest1),
|
||||||
@ -404,6 +415,26 @@ impl MapArea {
|
|||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn area_value(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
MapArea::Pioneer2Ep1 => 0,
|
||||||
|
MapArea::Forest1 => 1,
|
||||||
|
MapArea::Forest2 => 2,
|
||||||
|
MapArea::Caves1 => 3,
|
||||||
|
MapArea::Caves2 => 4,
|
||||||
|
MapArea::Caves3 => 5,
|
||||||
|
MapArea::Mines1 => 6,
|
||||||
|
MapArea::Mines2 => 7,
|
||||||
|
MapArea::Ruins1 => 8,
|
||||||
|
MapArea::Ruins2 => 9,
|
||||||
|
MapArea::Ruins3 => 10,
|
||||||
|
MapArea::Dragon => 11,
|
||||||
|
MapArea::DeRolLe => 12,
|
||||||
|
MapArea::VolOpt => 13,
|
||||||
|
MapArea::DarkFalz => 14,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -516,76 +547,76 @@ fn enemy_data_from_map_data(path: PathBuf, episode: &Episode) -> Vec<Option<MapE
|
|||||||
match monster.monster {
|
match monster.monster {
|
||||||
MonsterType::Monest => {
|
MonsterType::Monest => {
|
||||||
for _ in 0..30 {
|
for _ in 0..30 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::Mothmant)));
|
monsters.push(Some(MapEnemy::new(MonsterType::Mothmant, monster.map_area)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MonsterType::PofuillySlime => {
|
MonsterType::PofuillySlime => {
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::PofuillySlime)));
|
monsters.push(Some(MapEnemy::new(MonsterType::PofuillySlime, monster.map_area)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MonsterType::PanArms => {
|
MonsterType::PanArms => {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::Hidoom)));
|
monsters.push(Some(MapEnemy::new(MonsterType::Hidoom, monster.map_area)));
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::Migium)));
|
monsters.push(Some(MapEnemy::new(MonsterType::Migium, monster.map_area)));
|
||||||
},
|
},
|
||||||
MonsterType::SinowBeat => {
|
MonsterType::SinowBeat => {
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::SinowBeat)));
|
monsters.push(Some(MapEnemy::new(MonsterType::SinowBeat, monster.map_area)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MonsterType::SinowGold => {
|
MonsterType::SinowGold => {
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::SinowGold)));
|
monsters.push(Some(MapEnemy::new(MonsterType::SinowGold, monster.map_area)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MonsterType::Canane => {
|
MonsterType::Canane => {
|
||||||
for _ in 0..8 {
|
for _ in 0..8 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::RingCanadine)));
|
monsters.push(Some(MapEnemy::new(MonsterType::RingCanadine, monster.map_area)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MonsterType::ChaosSorcerer => {
|
MonsterType::ChaosSorcerer => {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::BeeR)));
|
monsters.push(Some(MapEnemy::new(MonsterType::BeeR, monster.map_area)));
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::BeeL)));
|
monsters.push(Some(MapEnemy::new(MonsterType::BeeL, monster.map_area)));
|
||||||
},
|
},
|
||||||
MonsterType::Bulclaw => {
|
MonsterType::Bulclaw => {
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::Claw)));
|
monsters.push(Some(MapEnemy::new(MonsterType::Claw, monster.map_area)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MonsterType::DeRolLe => {
|
MonsterType::DeRolLe => {
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeBody)));
|
monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeBody, monster.map_area)));
|
||||||
}
|
}
|
||||||
for _ in 0..9 {
|
for _ in 0..9 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeMine)));
|
monsters.push(Some(MapEnemy::new(MonsterType::DeRolLeMine, monster.map_area)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MonsterType::VolOptPartA => {
|
MonsterType::VolOptPartA => {
|
||||||
for _ in 0..6 {
|
for _ in 0..6 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptPillar)));
|
monsters.push(Some(MapEnemy::new(MonsterType::VolOptPillar, monster.map_area)));
|
||||||
}
|
}
|
||||||
for _ in 0..24 {
|
for _ in 0..24 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptMonitor)));
|
monsters.push(Some(MapEnemy::new(MonsterType::VolOptMonitor, monster.map_area)));
|
||||||
}
|
}
|
||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused)));
|
monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused, monster.map_area)));
|
||||||
}
|
}
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptAmp)));
|
monsters.push(Some(MapEnemy::new(MonsterType::VolOptAmp, monster.map_area)));
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptCore)));
|
monsters.push(Some(MapEnemy::new(MonsterType::VolOptCore, monster.map_area)));
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused)));
|
monsters.push(Some(MapEnemy::new(MonsterType::VolOptUnused, monster.map_area)));
|
||||||
},
|
},
|
||||||
// TOOD: this cares about difficulty (theres an ult-specific darvant?)
|
// TOOD: this cares about difficulty (theres an ult-specific darvant?)
|
||||||
MonsterType::DarkFalz => {
|
MonsterType::DarkFalz => {
|
||||||
for _ in 0..509 {
|
for _ in 0..509 {
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::Darvant)));
|
monsters.push(Some(MapEnemy::new(MonsterType::Darvant, monster.map_area)));
|
||||||
}
|
}
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz3)));
|
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz3, monster.map_area)));
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz2)));
|
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz2, monster.map_area)));
|
||||||
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz1)));
|
monsters.push(Some(MapEnemy::new(MonsterType::DarkFalz1, monster.map_area)));
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
for _ in 0..enemy.children {
|
for _ in 0..enemy.children {
|
||||||
monsters.push(Some(MapEnemy::new(monster.monster)));
|
monsters.push(Some(MapEnemy::new(monster.monster, monster.map_area)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -596,6 +627,12 @@ fn enemy_data_from_map_data(path: PathBuf, episode: &Episode) -> Vec<Option<MapE
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error("")]
|
||||||
|
pub enum MapsError {
|
||||||
|
InvalidMonsterId(usize),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Maps {
|
pub struct Maps {
|
||||||
map_variants: [MapVariant; 15],
|
map_variants: [MapVariant; 15],
|
||||||
@ -641,8 +678,8 @@ impl Maps {
|
|||||||
maps
|
maps
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enemy_by_id(&self, id: usize) -> MapEnemy {
|
pub fn enemy_by_id(&self, id: usize) -> Result<MapEnemy, MapsError> {
|
||||||
self.enemy_data[id].unwrap()
|
self.enemy_data[id].ok_or(MapsError::InvalidMonsterId(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_headers(&self) -> [u32; 0x20] {
|
pub fn map_headers(&self) -> [u32; 0x20] {
|
||||||
|
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 lobby;
|
||||||
|
pub mod message;
|
||||||
pub mod room;
|
pub mod room;
|
||||||
|
|
||||||
use libpso::character::character::Inventory;
|
use libpso::character::character::Inventory;
|
||||||
|
@ -6,10 +6,14 @@ use crate::common::serverstate::ClientId;
|
|||||||
use crate::common::leveltable::CharacterLevelTable;
|
use crate::common::leveltable::CharacterLevelTable;
|
||||||
use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients, Rooms};
|
use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients, Rooms};
|
||||||
use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder};
|
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 libpso::character::character;
|
||||||
use crate::entity::gateway::EntityGateway;
|
use crate::entity::gateway::EntityGateway;
|
||||||
use libpso::{utf8_to_array, utf8_to_utf16_array};
|
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)
|
fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation)
|
||||||
-> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
|
-> 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,
|
pub fn guildcard_send(id: ClientId,
|
||||||
guildcard_send: &GuildcardSend,
|
guildcard_send: &GuildcardSend,
|
||||||
target: u32,
|
target: u32,
|
||||||
@ -46,3 +48,57 @@ pub fn guildcard_send(id: ClientId,
|
|||||||
};
|
};
|
||||||
send_to_client(id, target as u8, msg, &client_location)
|
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() {
|
match client_location.get_area(id).unwrap() {
|
||||||
RoomLobby::Room(room) => {
|
RoomLobby::Room(room) => {
|
||||||
let r = rooms[room.0].as_ref().unwrap();
|
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);
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
@ -25,6 +25,7 @@ use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOM
|
|||||||
use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder};
|
use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder};
|
||||||
use crate::ship::items;
|
use crate::ship::items;
|
||||||
use crate::ship::room;
|
use crate::ship::room;
|
||||||
|
use crate::ship::map::MapsError;
|
||||||
use crate::ship::packet::handler;
|
use crate::ship::packet::handler;
|
||||||
|
|
||||||
pub const SHIP_PORT: u16 = 23423;
|
pub const SHIP_PORT: u16 = 23423;
|
||||||
@ -39,7 +40,11 @@ pub enum ShipError {
|
|||||||
InvalidSlot(ClientId, u32),
|
InvalidSlot(ClientId, u32),
|
||||||
TooManyClients,
|
TooManyClients,
|
||||||
ClientLocationError(#[from] ClientLocationError),
|
ClientLocationError(#[from] ClientLocationError),
|
||||||
|
MapsError(#[from] MapsError),
|
||||||
InvalidRoom(u32),
|
InvalidRoom(u32),
|
||||||
|
MonsterAlreadyDroppedItem(ClientId, u16),
|
||||||
|
SliceError(#[from] std::array::TryFromSliceError),
|
||||||
|
ItemError, // TODO: refine this
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -145,6 +150,7 @@ pub struct ClientState {
|
|||||||
//guildcard: GuildCard,
|
//guildcard: GuildCard,
|
||||||
pub inventory: items::ActiveInventory,
|
pub inventory: items::ActiveInventory,
|
||||||
//bank: Bank,
|
//bank: Bank,
|
||||||
|
pub floor_items: Vec<items::ActiveItemOnFloor>,
|
||||||
pub block: u32,
|
pub block: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +163,7 @@ impl ClientState {
|
|||||||
session: session,
|
session: session,
|
||||||
inventory: inventory,
|
inventory: inventory,
|
||||||
//bank: bank,
|
//bank: bank,
|
||||||
|
floor_items: Vec::new(),
|
||||||
block: 1,
|
block: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,6 +214,9 @@ impl<EG: EntityGateway> ShipServerState<EG> {
|
|||||||
GameMessage::GuildcardSend(guildcard_send) => {
|
GameMessage::GuildcardSend(guildcard_send) => {
|
||||||
handler::direct_message::guildcard_send(id, guildcard_send, target, &self.client_location, &self.clients)
|
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();
|
let cmsg = msg.clone();
|
||||||
Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter()
|
Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user