inital drop test
This commit is contained in:
parent
220d3e7185
commit
58da1f87f6
@ -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::*;
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
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 {
|
||||
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)
|
||||
}).collect();
|
||||
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
Normal file
76
tests/test_item_drop.rs
Normal file
@ -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…
x
Reference in New Issue
Block a user