Browse Source

inital drop test

pull/127/head
jake 2 years ago
parent
commit
58da1f87f6
  1. 76
      src/ship/drops/mod.rs
  2. 90
      src/ship/drops/rare_drop_table.rs
  3. 1
      src/ship/packet/handler/direct_message.rs
  4. 76
      tests/test_item_drop.rs

76
src/ship/drops/mod.rs

@ -6,7 +6,7 @@
mod drop_table;
mod rare_drop_table;
pub mod rare_drop_table;
mod generic_weapon;
mod generic_armor;
mod generic_shield;
@ -141,6 +141,20 @@ impl DropTable {
}
}
pub fn builder() -> DropTableBuilder {
DropTableBuilder {
monster_stats: None,
rare_table: None,
weapon_table: None,
armor_table: None,
shield_table: None,
unit_table: None,
tool_table: None,
box_table: None,
rng: None,
}
}
fn generate_meseta(&mut self, monster: &MonsterDropStats) -> Option<ItemDropType> {
Some(ItemDropType::Meseta(self.rng.gen_range(monster.min_meseta, monster.max_meseta + 1)))
}
@ -189,6 +203,66 @@ impl DropTable {
}
pub struct DropTableBuilder {
monster_stats: Option<HashMap<MonsterType, MonsterDropStats>>,
rare_table: Option<RareDropTable>,
weapon_table: Option<GenericWeaponTable>,
armor_table: Option<GenericArmorTable>,
shield_table: Option<GenericShieldTable>,
unit_table: Option<GenericUnitTable>,
tool_table: Option<ToolTable>,
box_table: Option<BoxDropTable>,
rng: Option<rand_chacha::ChaCha20Rng>,
}
// TODO: add the rest of these later I just need these ones right now
impl DropTableBuilder {
#[must_use]
pub fn monster_stats(mut self, monster_stats: HashMap<MonsterType, MonsterDropStats>) -> DropTableBuilder {
self.monster_stats = Some(monster_stats);
self
}
#[must_use]
pub fn monster_stat(mut self, monster_type: MonsterType, drop_stats: MonsterDropStats) -> DropTableBuilder {
match &mut self.monster_stats {
Some(monster_stats) => {
monster_stats.insert(monster_type, drop_stats);
},
None => {
let mut monster_stats = HashMap::default();
monster_stats.insert(monster_type, drop_stats);
self.monster_stats = Some(monster_stats);
}
}
self
}
#[must_use]
pub fn rare_table(mut self, rare_table: RareDropTable) -> DropTableBuilder {
self.rare_table = Some(rare_table);
self
}
pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable {
DropTable {
monster_stats: self.monster_stats.unwrap_or_else(|| {
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect()
}),
rare_table: self.rare_table.unwrap_or_else(|| RareDropTable::new(episode, difficulty, section_id)),
weapon_table: self.weapon_table.unwrap_or_else(|| GenericWeaponTable::new(episode, difficulty, section_id)),
armor_table: self.armor_table.unwrap_or_else(|| GenericArmorTable::new(episode, difficulty, section_id)),
shield_table: self.shield_table.unwrap_or_else(|| GenericShieldTable::new(episode, difficulty, section_id)),
unit_table: self.unit_table.unwrap_or_else(|| GenericUnitTable::new(episode, difficulty, section_id)),
tool_table: self.tool_table.unwrap_or_else(|| ToolTable::new(episode, difficulty, section_id)),
box_table: self.box_table.unwrap_or_else(|| BoxDropTable::new(episode, difficulty, section_id)),
rng: self.rng.unwrap_or_else(|| rand_chacha::ChaCha20Rng::from_entropy()),
}
}
}
#[cfg(test)]
mod test {
use super::*;

90
src/ship/drops/rare_drop_table.rs

@ -50,9 +50,9 @@ impl RareDropItem {
}
struct RareDropRate {
rate: f32,
item: RareDropItem
pub struct RareDropRate {
pub rate: f32,
pub item: RareDropItem
}
@ -71,30 +71,41 @@ pub struct RareDropTable {
shield_stats: GenericShieldTable,
}
impl RareDropTable {
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> RareDropTable {
let cfg: HashMap<String, Vec<RareDropConfigEntity>> = load_data_file(episode, difficulty, section_id, "rare_rate.toml");
let rates = cfg.into_iter()
.map(|(monster, drops)| {
let monster = monster.parse().unwrap();
let drops = drops.into_iter().map(|drop| {
RareDropRate {
rate: drop.rate,
item: RareDropItem::from_string(drop.item),
}
}).collect();
(monster, drops)
fn load_default_monster_rates(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> HashMap<MonsterType, Vec<RareDropRate>> {
let cfg: HashMap<String, Vec<RareDropConfigEntity>> = load_data_file(episode, difficulty, section_id, "rare_rate.toml");
cfg.into_iter()
.map(|(monster, drops)| {
let monster = monster.parse().unwrap();
let drops = drops.into_iter().map(|drop| {
RareDropRate {
rate: drop.rate,
item: RareDropItem::from_string(drop.item),
}
}).collect();
(monster, drops)
}).collect()
}
impl RareDropTable {
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> RareDropTable {
RareDropTable {
rates,
rates: load_default_monster_rates(episode, difficulty, section_id),
attribute_table: AttributeTable::new(episode, difficulty, section_id),
armor_stats: GenericArmorTable::new(episode, difficulty, section_id),
shield_stats: GenericShieldTable::new(episode, difficulty, section_id),
}
}
pub fn builder() -> RareDropTableBuilder {
RareDropTableBuilder {
rates: None,
attribute_table: None,
armor_stats: None,
shield_stats: None,
}
}
pub fn apply_item_stats<R: Rng>(&self, map_area: &MapArea, item: RareDropItem, rng: &mut R) -> ItemDropType {
match item {
RareDropItem::Weapon(weapon) => {
@ -155,3 +166,46 @@ impl RareDropTable {
})
}
}
pub struct RareDropTableBuilder {
rates: Option<HashMap<MonsterType, Vec<RareDropRate>>>,
attribute_table: Option<AttributeTable>,
armor_stats: Option<GenericArmorTable>,
shield_stats: Option<GenericShieldTable>,
}
// TODO: add the rest of these later I just need these ones right now
impl RareDropTableBuilder {
pub fn rates(mut self, rates: HashMap<MonsterType, Vec<RareDropRate>>) -> RareDropTableBuilder {
self.rates = Some(rates);
self
}
#[must_use]
pub fn rate(mut self, monster_type: MonsterType, drop_rate: RareDropRate) -> RareDropTableBuilder {
match &mut self.rates {
Some(rates) => {
rates.entry(monster_type)
.or_insert(Vec::new())
.push(drop_rate);
},
None => {
let mut rates = HashMap::default();
rates.insert(monster_type, vec![drop_rate]);
self.rates = Some(rates);
}
}
self
}
pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> RareDropTable {
RareDropTable {
rates: self.rates.unwrap_or_else(|| load_default_monster_rates(episode, difficulty, section_id)),
attribute_table: self.attribute_table.unwrap_or_else(|| AttributeTable::new(episode, difficulty, section_id)),
armor_stats: self.armor_stats.unwrap_or_else(|| GenericArmorTable::new(episode, difficulty, section_id)),
shield_stats: self.shield_stats.unwrap_or_else(|| GenericShieldTable::new(episode, difficulty, section_id)),
}
}
}

1
src/ship/packet/handler/direct_message.rs

@ -209,7 +209,6 @@ where
}
let clients_in_area = client_location.get_clients_in_room(room_id).await?;
let client_and_drop = rooms.with_mut(room_id, |room| Box::pin(async move {
clients_in_area.into_iter()
.filter_map(move |area_client| {

76
tests/test_item_drop.rs

@ -0,0 +1,76 @@
use elseware::common::serverstate::{ClientId, ServerState};
use elseware::entity::gateway::{EntityGateway, InMemoryGateway};
use elseware::entity::character::SectionID;
use elseware::common::leveltable::CharacterLevelTable;
use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket};
use elseware::ship::room::{Episode, Difficulty};
use elseware::ship::monster::MonsterType;
use elseware::ship::location::RoomId;
use elseware::ship::drops::{DropTable, MonsterDropStats, MonsterDropType};
use elseware::ship::drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem};
use elseware::ship::map::{Maps, MapVariant, MapArea, MapVariantMode, MapEnemy};
use elseware::entity::item::weapon::WeaponType;
use libpso::packet::ship::*;
use libpso::packet::messages::*;
#[path = "common.rs"]
mod common;
use common::*;
#[async_std::test]
async fn test_enemy_drops_item() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.map_builder(Box::new(|_room_mode, _event| {
Maps::new(
vec![MapVariant::new(MapArea::Forest2, MapVariantMode::Online)],
vec![Some(MapEnemy::new(MonsterType::Hildebear, MapArea::Forest2))],
Vec::new(),
)
}))
.drop_table_builder(Box::new(|episode, difficulty, section_id| {
DropTable::builder()
.monster_stat(MonsterType::Hildebear, MonsterDropStats {
dar: 100,
drop_type: MonsterDropType::Weapon,
min_meseta: 0,
max_meseta: 0,
})
.rare_table(RareDropTable::builder()
.rate(MonsterType::Hildebear, RareDropRate {
rate: 1.0,
item: RareDropItem::Weapon(WeaponType::DarkFlow)
})
.build(episode, difficulty, section_id))
.build(episode, difficulty, section_id)
}))
.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 pkt = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::RequestItem(RequestItem {
client: 0,
target: 0,
map_area: 2,
pt_index: 0,
enemy_id: 0,
x: 0.0,
z: 0.0,
y: 0.0,
})))).await.unwrap();
match &pkt[0].1 {
SendShipPacket::Message(Message{msg: GameMessage::ItemDrop(item_drop)}) => {
assert_eq!(item_drop.item_id, 0x810001);
assert_eq!(item_drop.item_bytes[1], 0x9D);
},
_ => panic!(),
}
}
Loading…
Cancel
Save