Browse Source

further speed up tests by not loading drop charts by default

jake 1 year ago
parent
commit
0a4a3f6911
  1. 17
      .drone.yml
  2. 47
      drops/src/lib.rs
  3. 6
      room/src/lib.rs
  4. 4
      src/bin/main.rs
  5. 2
      src/bin/ship.rs
  6. 2
      src/ship/packet/handler/room.rs
  7. 10
      src/ship/ship.rs
  8. 8
      tests/common.rs
  9. 8
      tests/test_item_drop.rs

17
.drone.yml

@ -9,16 +9,31 @@ concurrency:
steps: steps:
- name: build - name: build
image: rustlang/rust:nightly image: rustlang/rust:nightly
volumes:
- name: cache
path: /usr/local/cargo
- name: target-cache
path: /drone/src/target
commands: commands:
- cargo build - cargo build
- name: clippy! - name: clippy!
image: rustlang/rust:nightly image: rustlang/rust:nightly
volumes:
- name: cache
path: /usr/local/cargo
- name: target-cache
path: /drone/src/target
commands: commands:
- cargo clippy -- --deny warnings - cargo clippy -- --deny warnings
- name: test - name: test
image: rustlang/rust:nightly image: rustlang/rust:nightly
volumes:
- name: cache
path: /usr/local/cargo
- name: target-cache
path: /drone/src/target
commands: commands:
- cargo test --jobs 1
- cargo test
volumes: volumes:
- name: cache - name: cache

47
drops/src/lib.rs

@ -98,7 +98,7 @@ impl ItemDropType {
.or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag)) .or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag))
.or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool)) .or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool))
.or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?; .or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?;
match item_type { match item_type {
ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)), ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)),
ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)), ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)),
@ -121,7 +121,12 @@ pub struct ItemDrop {
} }
pub struct DropTable {
pub trait DropTable {
fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType>;
fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType>;
}
pub struct StandardDropTable {
monster_stats: HashMap<MonsterType, MonsterDropStats>, monster_stats: HashMap<MonsterType, MonsterDropStats>,
rare_table: RareDropTable, rare_table: RareDropTable,
weapon_table: GenericWeaponTable, weapon_table: GenericWeaponTable,
@ -133,11 +138,11 @@ pub struct DropTable {
rng: rand_chacha::ChaCha20Rng, rng: rand_chacha::ChaCha20Rng,
} }
impl DropTable {
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable {
impl StandardDropTable {
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box<dyn DropTable + Send + Sync> {
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");
DropTable {
Box::new(StandardDropTable {
monster_stats: monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect(), monster_stats: monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect(),
rare_table: RareDropTable::new(episode, difficulty, section_id), rare_table: RareDropTable::new(episode, difficulty, section_id),
weapon_table: GenericWeaponTable::new(episode, difficulty, section_id), weapon_table: GenericWeaponTable::new(episode, difficulty, section_id),
@ -147,7 +152,7 @@ impl DropTable {
tool_table: ToolTable::new(episode, difficulty, section_id), tool_table: ToolTable::new(episode, difficulty, section_id),
box_table: BoxDropTable::new(episode, difficulty, section_id), box_table: BoxDropTable::new(episode, difficulty, section_id),
rng: rand_chacha::ChaCha20Rng::from_entropy(), rng: rand_chacha::ChaCha20Rng::from_entropy(),
}
})
} }
pub fn builder() -> DropTableBuilder { pub fn builder() -> DropTableBuilder {
@ -177,8 +182,10 @@ impl DropTable {
MonsterDropType::None => None, MonsterDropType::None => None,
} }
} }
}
pub fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType> {
impl DropTable for StandardDropTable {
fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType> {
let monster_stat = *self.monster_stats.get(monster)?; let monster_stat = *self.monster_stats.get(monster)?;
let drop_anything = self.rng.gen_range(0, 100); let drop_anything = self.rng.gen_range(0, 100);
@ -191,7 +198,7 @@ impl DropTable {
} }
let drop_type = self.rng.gen_range(0, 3); let drop_type = self.rng.gen_range(0, 3);
match drop_type { match drop_type {
0 => { 0 => {
self.generate_meseta(&monster_stat) self.generate_meseta(&monster_stat)
@ -206,7 +213,7 @@ impl DropTable {
} }
} }
pub fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType> {
fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType> {
self.box_table.get_drop(map_area, object, &mut self.rng) self.box_table.get_drop(map_area, object, &mut self.rng)
} }
} }
@ -253,8 +260,8 @@ impl DropTableBuilder {
self self
} }
pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable {
DropTable {
pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box<dyn DropTable + Send + Sync> {
Box::new(StandardDropTable {
monster_stats: self.monster_stats.unwrap_or_else(|| { monster_stats: self.monster_stats.unwrap_or_else(|| {
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");
monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect() monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect()
@ -267,10 +274,24 @@ impl DropTableBuilder {
tool_table: self.tool_table.unwrap_or_else(|| ToolTable::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)), 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), rng: self.rng.unwrap_or_else(rand_chacha::ChaCha20Rng::from_entropy),
}
})
} }
} }
struct NullDropTable;
impl DropTable for NullDropTable {
fn get_drop(&mut self, _map_area: &MapArea, _monster: &MonsterType) -> Option<ItemDropType> {
None
}
fn get_box_drop(&mut self, _map_area: &MapArea, _object: &MapObject) -> Option<ItemDropType> {
None
}
}
pub fn null_drop_table(_episode: Episode, _difficult: Difficulty, _section_id: SectionID) -> Box<dyn DropTable + Send + Sync> {
Box::new(NullDropTable)
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {

6
room/src/lib.rs

@ -171,7 +171,7 @@ pub struct RoomState {
pub name: String, pub name: String,
pub password: [u16; 16], pub password: [u16; 16],
pub maps: Maps, pub maps: Maps,
pub drop_table: Box<DropTable>,
pub drop_table: Box<dyn DropTable + Send + Sync>,
pub section_id: SectionID, pub section_id: SectionID,
pub random_seed: u32, pub random_seed: u32,
pub bursting: bool, pub bursting: bool,
@ -231,7 +231,7 @@ impl RoomState {
password: [u16; 16], password: [u16; 16],
event: Holiday, event: Holiday,
map_builder: Arc<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>, map_builder: Arc<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>,
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> Box<dyn DropTable + Send + Sync> + Send + Sync>>,
standard_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>, standard_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
government_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>, government_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
) -> Result<RoomState, anyhow::Error> { ) -> Result<RoomState, anyhow::Error> {
@ -262,7 +262,7 @@ impl RoomState {
password, password,
maps: map_builder(mode, event), maps: map_builder(mode, event),
section_id, section_id,
drop_table: Box::new(drop_table_builder(episode, difficulty, section_id)),
drop_table: drop_table_builder(episode, difficulty, section_id),
bursting: false, bursting: false,
map_areas: MapAreaLookup::new(&episode), map_areas: MapAreaLookup::new(&episode),
quest_group: QuestCategoryType::Standard, quest_group: QuestCategoryType::Standard,

4
src/bin/main.rs

@ -13,6 +13,7 @@ use entity::account::{NewUserAccountEntity, NewUserSettingsEntity};
use entity::character::NewCharacterEntity; use entity::character::NewCharacterEntity;
use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity}; use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity};
use entity::item; use entity::item;
use drops::{DropTable, StandardDropTable};
fn setup_logger() { fn setup_logger() {
let colors = fern::colors::ColoredLevelConfig::new() let colors = fern::colors::ColoredLevelConfig::new()
@ -367,6 +368,7 @@ fn main() {
.event(Holiday::Halloween) .event(Holiday::Halloween)
.standard_quest_builder(Box::new(quests::load_standard_quests)) .standard_quest_builder(Box::new(quests::load_standard_quests))
.government_quest_builder(Box::new(quests::load_government_quests)) .government_quest_builder(Box::new(quests::load_government_quests))
.drop_table_builder(Box::new(StandardDropTable::new))
.gateway(entity_gateway.clone()) .gateway(entity_gateway.clone())
.build(); .build();
let sub_ship_state = ship_state.clone(); let sub_ship_state = ship_state.clone();
@ -385,6 +387,7 @@ fn main() {
.event(Holiday::Christmas) .event(Holiday::Christmas)
.standard_quest_builder(Box::new(quests::load_standard_quests)) .standard_quest_builder(Box::new(quests::load_standard_quests))
.government_quest_builder(Box::new(quests::load_government_quests)) .government_quest_builder(Box::new(quests::load_government_quests))
.drop_table_builder(Box::new(StandardDropTable::new))
.gateway(entity_gateway.clone()) .gateway(entity_gateway.clone())
.build(); .build();
let sub_ship_state = ship_state.clone(); let sub_ship_state = ship_state.clone();
@ -402,6 +405,7 @@ fn main() {
.port(elseware::ship::ship::SHIP_PORT+3000) .port(elseware::ship::ship::SHIP_PORT+3000)
.standard_quest_builder(Box::new(quests::load_standard_quests)) .standard_quest_builder(Box::new(quests::load_standard_quests))
.government_quest_builder(Box::new(quests::load_government_quests)) .government_quest_builder(Box::new(quests::load_government_quests))
.drop_table_builder(Box::new(StandardDropTable::new))
.gateway(entity_gateway.clone()) .gateway(entity_gateway.clone())
.build(); .build();
let sub_ship_state = ship_state.clone(); let sub_ship_state = ship_state.clone();

2
src/bin/ship.rs

@ -2,6 +2,7 @@ use log::info;
use entity::gateway::postgres::PostgresGateway; use entity::gateway::postgres::PostgresGateway;
use elseware::ship::ship::ShipServerStateBuilder; use elseware::ship::ship::ShipServerStateBuilder;
use networking::interserver::AuthToken; use networking::interserver::AuthToken;
use drops::{DropTable, StandardDropTable};
fn main() { fn main() {
let colors = fern::colors::ColoredLevelConfig::new() let colors = fern::colors::ColoredLevelConfig::new()
@ -45,6 +46,7 @@ fn main() {
.auth_token(AuthToken(shipgate_token)) .auth_token(AuthToken(shipgate_token))
.standard_quest_builder(Box::new(quests::load_standard_quests)) .standard_quest_builder(Box::new(quests::load_standard_quests))
.government_quest_builder(Box::new(quests::load_government_quests)) .government_quest_builder(Box::new(quests::load_government_quests))
.drop_table_builder(Box::new(StandardDropTable::new))
.build(); .build();
let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap(); let shipgate_ip = std::env::var("SHIPGATE_IP").unwrap().parse().unwrap();

2
src/ship/packet/handler/room.rs

@ -31,7 +31,7 @@ pub async fn create_room<EG>(id: ClientId,
item_state: &mut ItemState, item_state: &mut ItemState,
rooms: &Rooms, rooms: &Rooms,
map_builder: Arc<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>, map_builder: Arc<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>,
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> Box<dyn DropTable + Send + Sync> + Send + Sync>>,
standard_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>, standard_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
government_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>, government_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
event: Holiday) event: Holiday)

10
src/ship/ship.rs

@ -22,7 +22,7 @@ use entity::gateway::{EntityGateway, GatewayError};
use entity::character::SectionID; use entity::character::SectionID;
use entity::room::RoomNote; use entity::room::RoomNote;
use location::{ClientLocation, RoomLobby, ClientLocationError, RoomId}; use location::{ClientLocation, RoomLobby, ClientLocationError, RoomId};
use drops::DropTable;
use drops::{DropTable, null_drop_table};
use items; use items;
use room; use room;
use maps::room::{RoomMode, Episode, Difficulty}; use maps::room::{RoomMode, Episode, Difficulty};
@ -331,7 +331,7 @@ pub struct ShipServerStateBuilder<EG: EntityGateway + Clone + 'static> {
auth_token: Option<AuthToken>, auth_token: Option<AuthToken>,
event: Option<Holiday>, event: Option<Holiday>,
map_builder: Option<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>, map_builder: Option<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>,
drop_table_builder: Option<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
drop_table_builder: Option<Box<dyn Fn(Episode, Difficulty, SectionID) -> Box<dyn DropTable + Send + Sync> + Send + Sync>>,
standard_quest_builder: Option<Box<dyn Fn(RoomMode) -> Result<quests::QuestList, QuestLoadError> + Send + Sync>>, standard_quest_builder: Option<Box<dyn Fn(RoomMode) -> Result<quests::QuestList, QuestLoadError> + Send + Sync>>,
government_quest_builder: Option<Box<dyn Fn(RoomMode) -> Result<quests::QuestList, QuestLoadError> + Send + Sync>>, government_quest_builder: Option<Box<dyn Fn(RoomMode) -> Result<quests::QuestList, QuestLoadError> + Send + Sync>>,
num_blocks: usize, num_blocks: usize,
@ -399,7 +399,7 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerStateBuilder<EG> {
} }
#[must_use] #[must_use]
pub fn drop_table_builder(mut self, drop_table_builder: Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>) -> ShipServerStateBuilder<EG> {
pub fn drop_table_builder(mut self, drop_table_builder: Box<dyn Fn(Episode, Difficulty, SectionID) -> Box<dyn DropTable + Send + Sync> + Send + Sync>) -> ShipServerStateBuilder<EG> {
self.drop_table_builder = Some(drop_table_builder); self.drop_table_builder = Some(drop_table_builder);
self self
} }
@ -435,7 +435,7 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerStateBuilder<EG> {
blocks: Blocks(blocks), blocks: Blocks(blocks),
event: self.event.unwrap_or(Holiday::None), event: self.event.unwrap_or(Holiday::None),
map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(generate_free_roam_maps))), map_builder: Arc::new(self.map_builder.unwrap_or(Box::new(generate_free_roam_maps))),
drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(DropTable::new))),
drop_table_builder: Arc::new(self.drop_table_builder.unwrap_or(Box::new(null_drop_table))),
standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), standard_quest_builder: Arc::new(self.standard_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))),
government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))), government_quest_builder: Arc::new(self.government_quest_builder.unwrap_or(Box::new(|_| Ok(QuestList::new())))),
@ -486,7 +486,7 @@ pub struct ShipServerState<EG: EntityGateway + Clone + 'static> {
shipgate_sender: Option<channel::Sender<ShipMessage>>, shipgate_sender: Option<channel::Sender<ShipMessage>>,
trades: TradeState, trades: TradeState,
map_builder: Arc<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>, map_builder: Arc<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>,
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> Box<dyn DropTable + Send + Sync> + Send + Sync>>,
standard_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>, standard_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
government_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>, government_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
} }

8
tests/common.rs

@ -3,10 +3,14 @@
use networking::serverstate::{ClientId, ServerState}; use networking::serverstate::{ClientId, ServerState};
use entity::gateway::EntityGateway; use entity::gateway::EntityGateway;
use entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity}; use entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity};
use entity::character::{CharacterEntity, NewCharacterEntity};
use entity::character::{CharacterEntity, NewCharacterEntity, SectionID};
use entity::item::{Meseta, BankIdentifier}; use entity::item::{Meseta, BankIdentifier};
use elseware::ship::ship::{ShipServerState, RecvShipPacket}; use elseware::ship::ship::{ShipServerState, RecvShipPacket};
use maps::room::Difficulty;
use maps::room::{Difficulty, Episode};
use drops::{DropTable, ItemDropType};
use maps::area::MapArea;
use maps::monster::MonsterType;
use maps::object::MapObject;
use entity::item; use entity::item;

8
tests/test_item_drop.rs

@ -2,7 +2,7 @@ use networking::serverstate::{ClientId, ServerState};
use entity::gateway::InMemoryGateway; use entity::gateway::InMemoryGateway;
use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket}; use elseware::ship::ship::{ShipServerState, SendShipPacket, RecvShipPacket};
use maps::monster::MonsterType; use maps::monster::MonsterType;
use drops::{DropTable, MonsterDropStats, MonsterDropType};
use drops::{StandardDropTable, MonsterDropStats, MonsterDropType};
use drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem}; use drops::rare_drop_table::{RareDropTable, RareDropRate, RareDropItem};
use maps::maps::Maps; use maps::maps::Maps;
use maps::area::MapArea; use maps::area::MapArea;
@ -32,7 +32,7 @@ async fn test_enemy_drops_item() {
) )
})) }))
.drop_table_builder(Box::new(|episode, difficulty, section_id| { .drop_table_builder(Box::new(|episode, difficulty, section_id| {
DropTable::builder()
StandardDropTable::builder()
.monster_stat(MonsterType::Hildebear, MonsterDropStats { .monster_stat(MonsterType::Hildebear, MonsterDropStats {
dar: 100, dar: 100,
drop_type: MonsterDropType::Weapon, drop_type: MonsterDropType::Weapon,
@ -88,7 +88,7 @@ async fn test_enemy_drops_item_for_two_players() {
) )
})) }))
.drop_table_builder(Box::new(|episode, difficulty, section_id| { .drop_table_builder(Box::new(|episode, difficulty, section_id| {
DropTable::builder()
StandardDropTable::builder()
.monster_stat(MonsterType::Hildebear, MonsterDropStats { .monster_stat(MonsterType::Hildebear, MonsterDropStats {
dar: 100, dar: 100,
drop_type: MonsterDropType::Weapon, drop_type: MonsterDropType::Weapon,
@ -156,7 +156,7 @@ async fn test_enemy_drops_item_for_two_players_and_pick_up() {
) )
})) }))
.drop_table_builder(Box::new(|episode, difficulty, section_id| { .drop_table_builder(Box::new(|episode, difficulty, section_id| {
DropTable::builder()
StandardDropTable::builder()
.monster_stat(MonsterType::Hildebear, MonsterDropStats { .monster_stat(MonsterType::Hildebear, MonsterDropStats {
dar: 100, dar: 100,
drop_type: MonsterDropType::Weapon, drop_type: MonsterDropType::Weapon,

Loading…
Cancel
Save