diff --git a/data/battle_param/ep1_rare_monster.toml b/data/battle_param/ep1_rare_monster.toml index b806f9a..1e1f3e0 100644 --- a/data/battle_param/ep1_rare_monster.toml +++ b/data/battle_param/ep1_rare_monster.toml @@ -1,15 +1,9 @@ +# 1/10 = 0.1 # 1/100 = 0.01 # 1/256 = 0.00390625 # 1/512 = 0.001953125 -[[Hildebear]] -appear_rate = 0.01 - -[[RagRappy]] -appear_rate = 0.01 - -[[PoisonLily]] -appear_rate = 0.01 - -[[PofuillySlime]] -appear_rate = 0.01 \ No newline at end of file +Hildebear = 1.0 +RagRappy = 0.1 +PoisonLily = 0.1 +PofuillySlime = 0.1 \ No newline at end of file diff --git a/data/battle_param/ep2_rare_monster.toml b/data/battle_param/ep2_rare_monster.toml index 948b189..290f727 100644 --- a/data/battle_param/ep2_rare_monster.toml +++ b/data/battle_param/ep2_rare_monster.toml @@ -1,13 +1,9 @@ +# 1/10 = 0.1 # 1/100 = 0.01 # 1/256 = 0.00390625 # 1/512 = 0.001953125 -[[Hildebear]] -appear_rate = 0.01 - -[[RagRappy]] -appear_rate = 0.01 - -[[PoisonLily]] -appear_rate = 0.01 +Hildebear = 0.01 +RagRappy = 0.01 +PoisonLily = 0.01 diff --git a/data/battle_param/ep4_rare_monster.toml b/data/battle_param/ep4_rare_monster.toml index 9f807c2..0ddddbf 100644 --- a/data/battle_param/ep4_rare_monster.toml +++ b/data/battle_param/ep4_rare_monster.toml @@ -1,27 +1,13 @@ +# 1/10 = 0.1 # 1/100 = 0.01 # 1/256 = 0.00390625 # 1/512 = 0.001953125 -[[SandRappyCrater]] -appear_rate = 0.01 - -[[ZuCrater]] -appear_rate = 0.01 - -[[Dorphon]] -appear_rate = 0.01 - -[[SandRappyDesert]] -appear_rate = 0.01 - -[[ZuDesert]] -appear_rate = 0.01 - -[[MerissaA]] -appear_rate = 0.01 - -[[Shambertin]] -appear_rate = 0.1 - -[[SaintMillion]] -appear_rate = 0.1 \ No newline at end of file +SandRappyCrater = 0.01 +ZuCrater = 0.01 +Dorphon = 0.01 +SandRappyDesert = 0.01 +ZuDesert = 0.01 +MerissaA = 0.01 +Shambertin = 0.1 +SaintMillion = 0.1 \ No newline at end of file diff --git a/src/ship/drops/mod.rs b/src/ship/drops/mod.rs index 4ada11e..427da74 100644 --- a/src/ship/drops/mod.rs +++ b/src/ship/drops/mod.rs @@ -58,8 +58,8 @@ pub fn load_data_file(episode: Episode, difficul // this is just copypaste pub fn load_rare_monster_file(episode: Episode) -> T { let mut path = PathBuf::from("data/battle_param/"); - path.push(episode.to_string().to_lowercase()); - path.push("_rare_monster.toml"); + path.push(episode.to_string().to_lowercase() + "_rare_monster.toml"); + println!("rare monster file path: {:?}", path); let mut f = File::open(path).unwrap(); let mut s = String::new(); diff --git a/src/ship/map/area.rs b/src/ship/map/area.rs index a26aa19..9da3374 100644 --- a/src/ship/map/area.rs +++ b/src/ship/map/area.rs @@ -208,6 +208,54 @@ impl MapArea { // MapArea::TestMapEp4 => 10, } } + + pub fn to_episode(self) -> Episode { + match self { + Pioneer2Ep1 => Episode::One, + Forest1 => Episode::One, + Forest2 => Episode::One, + Caves1 => Episode::One, + Caves2 => Episode::One, + Caves3 => Episode::One, + Mines1 => Episode::One, + Mines2 => Episode::One, + Ruins1 => Episode::One, + Ruins2 => Episode::One, + Ruins3 => Episode::One, + Dragon => Episode::One, + DeRolLe => Episode::One, + VolOpt => Episode::One, + DarkFalz => Episode::One, + Pioneer2Ep2 => Episode::Two, + VrTempleAlpha => Episode::Two, + VrTempleBeta => Episode::Two, + VrSpaceshipAlpha => Episode::Two, + VrSpaceshipBeta => Episode::Two, + Cca => Episode::Two, + JungleAreaNorth => Episode::Two, + JungleAreaEast => Episode::Two, + Mountain => Episode::Two, + Seaside => Episode::Two, + SeabedUpper => Episode::Two, + SeabedLower => Episode::Two, + GalGryphon => Episode::Two, + OlgaFlow => Episode::Two, + BarbaRay => Episode::Two, + GolDragon => Episode::Two, + SeasideNight => Episode::Two, + Tower => Episode::Two, + Pioneer2Ep4 => Episode::Four, + CraterEast => Episode::Four, + CraterWest => Episode::Four, + CraterSouth => Episode::Four, + CraterNorth => Episode::Four, + CraterInterior => Episode::Four, + SubDesert1 => Episode::Four, + SubDesert2 => Episode::Four, + SubDesert3 => Episode::Four, + SaintMillion => Episode::Four, + } + } } diff --git a/src/ship/map/enemy.rs b/src/ship/map/enemy.rs index 62c2155..6d4d7c7 100644 --- a/src/ship/map/enemy.rs +++ b/src/ship/map/enemy.rs @@ -75,25 +75,27 @@ pub enum MapEnemyError { MapAreaError(#[from] MapAreaError), } -#[derive(Debug, Serialize, Deserialize)] -pub struct RareMonsterAppearRate(pub f32); +// TODO: is this even needed/used? +// #[derive(Clone, Debug, Serialize, Deserialize)] +// pub type RareMonsterAppearRate: HashMap, // making this `pub type` doesn't allow `impl`s to be defined? -#[derive(Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct RareMonsterAppearTable { - appear_rate: HashMap, - seed: u32, + appear_rate: HashMap, + seed: u32 } impl RareMonsterAppearTable { pub fn new(episode: Episode, room_seed: u32) -> RareMonsterAppearTable { let cfg: HashMap = load_rare_monster_file(episode); + println!("got cfg: {:?}", cfg); - let appear_rates: HashMap = cfg + let appear_rates: HashMap = cfg .into_iter() - .map(|(monster, appear_rate)| { - let monster: MonsterType = monster.parse().unwrap(); - let appear_rate = RareMonsterAppearRate(appear_rate); + .map(|(monster, rate)| { + let monster: MonsterType = monster.parse().unwrap(); // TODO: don't unwrap! + let appear_rate = rate; (monster, appear_rate) }) .collect(); @@ -105,11 +107,14 @@ impl RareMonsterAppearTable { } pub fn roll_appearance(&self, monster: &MonsterType) -> bool { - let mut rng = rand_chacha::ChaChaRng::seed_from_u64(self.seed as u64); - if rng.gen::() < self.appear_rate.get(monster).unwrap_or(&RareMonsterAppearRate(0.0f32)).0 { + let mut rng = rand_chacha::ChaChaRng::seed_from_u64(self.seed as u64); // TODO: figure out how to seed with a u32 + println!("rolling for {:?} appearance", monster); + if rng.gen::() < *self.appear_rate.get(monster).unwrap_or(&0.0f32) { + println!("its a rare!"); true } else { + println!("lol sucker"); false } } @@ -331,5 +336,59 @@ impl MapEnemy { ..self } } + + // TODO: does this actually do anything useful? + pub fn has_rare_appearance(self) -> bool { + match self.monster { + MonsterType::RagRappy | MonsterType::Hildebear | + MonsterType::PoisonLily | MonsterType::PofuillySlime | + MonsterType::SandRappyCrater | MonsterType::ZuCrater | MonsterType::Dorphon | + MonsterType::SandRappyDesert | MonsterType::ZuDesert | MonsterType::MerissaA | + MonsterType::SaintMillion | MonsterType::Shambertin => true, + _ => false + } + } + + // TODO: does `shiny` need to be set here? + // TODO: distinguish between a `random` rare monster and a `set/guaranteed` rare monster? (does any acceptable quest even have this?) + pub fn set_rare_appearance(self) -> MapEnemy { + match self.monster { + MonsterType::RagRappy | MonsterType::Hildebear | + MonsterType::PoisonLily | MonsterType::PofuillySlime | + MonsterType::SandRappyCrater | MonsterType::ZuCrater | MonsterType::Dorphon | + MonsterType::SandRappyDesert | MonsterType::ZuDesert | MonsterType::MerissaA | + MonsterType::SaintMillion | MonsterType::Shambertin => self.set_shiny(), + _ => self, + } + } + + // // TODO: does `shiny` need to be set here? + // // TODO: distinguish between a `random` rare monster and a `set/guaranteed` rare monster? (does any acceptable quest even have this?) + // pub fn set_rare_appearance(self) -> MapEnemy { + // match (self.monster, self.map_area.to_episode()) { + // (MonsterType::RagRappy, Episode::One) => {MapEnemy {monster: MonsterType::AlRappy, ..self}}, + // (MonsterType::RagRappy, Episode::Two) => {MapEnemy {monster: MonsterType::EventRappy, ..self}}, + // (MonsterType::Hildebear, _) => {MapEnemy {monster: MonsterType::Hildeblue, ..self}}, + // (MonsterType::PoisonLily, _) => {MapEnemy {monster: MonsterType::NarLily, ..self}}, + // (MonsterType::PofuillySlime, _) => {MapEnemy {monster: MonsterType::PouillySlime, ..self}}, + // (MonsterType::SandRappyCrater, _) => {MapEnemy {monster: MonsterType::DelRappyCrater, ..self}}, + // (MonsterType::ZuCrater, _) => {MapEnemy {monster: MonsterType::PazuzuCrater, ..self}}, + // (MonsterType::Dorphon, _) => {MapEnemy {monster: MonsterType::DorphonEclair, ..self}}, + // (MonsterType::SandRappyDesert, _) => {MapEnemy {monster: MonsterType::DelRappyDesert, ..self}}, + // (MonsterType::ZuDesert, _) => {MapEnemy {monster: MonsterType::PazuzuDesert, ..self}}, + // (MonsterType::MerissaA, _) => {MapEnemy {monster: MonsterType::MerissaAA, ..self}}, + // (MonsterType::SaintMillion, _) => {MapEnemy {monster: MonsterType::Kondrieu, ..self}}, + // (MonsterType::Shambertin, _) => {MapEnemy {monster: MonsterType::Kondrieu, ..self}}, + // _ => {self}, + // } + // } + + // in theory this should only be called on monsters we know can have rare types + pub fn roll_appearance_for_quest(self, rare_monster_table: &RareMonsterAppearTable) -> MapEnemy { + if rare_monster_table.roll_appearance(&self.monster) { + return self.set_rare_appearance() + } + self + } } diff --git a/src/ship/map/maps.rs b/src/ship/map/maps.rs index 866ae12..71ef38d 100644 --- a/src/ship/map/maps.rs +++ b/src/ship/map/maps.rs @@ -12,7 +12,7 @@ use crate::ship::room::{Episode, RoomMode}; // TODO: don't use * use crate::ship::map::*; -use rand::{Rng}; +// use rand::{Rng}; pub fn objects_from_stream(cursor: &mut impl Read, episode: &Episode, map_area: &MapArea) -> Vec> { @@ -31,10 +31,10 @@ fn objects_from_map_data(path: PathBuf, episode: &Episode, map_area: &MapArea) - } fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> Vec> { +// fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy, rare_monster_table: RareMonsterAppearTable) -> Vec> { let enemy = MapEnemy::from_raw(raw_enemy, episode, map_area); - /* - TODO: load rare monster rates config - */ + + // TODO: load rare monster rates config enemy .map_or(vec![None], |monster| { let mut monsters = Vec::new(); @@ -43,7 +43,8 @@ fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> match monster.monster { // TODO: make real spawn rates // TODO: specific ep 2 event rappies - MonsterType::RagRappy => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::RagRappy => {if rand::thread_rng().gen_range(0, 100) < 11 { +/* MonsterType::RagRappy => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); match episode { Episode::One => {monsters.push(Some(MapEnemy::new(MonsterType::AlRappy, monster.map_area).set_shiny()))}, @@ -52,11 +53,13 @@ fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> } }}, - MonsterType::Hildebear => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::Hildebear => {if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::Hildebear => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::Hildeblue, monster.map_area).set_shiny())) }}, - MonsterType::PoisonLily => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::PoisonLily => {if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::PoisonLily => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::NarLily, monster.map_area).set_shiny())) }}, @@ -64,7 +67,8 @@ fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> MonsterType::PofuillySlime => { monsters.pop(); for _ in 0..5 { - if rand::thread_rng().gen_range(0, 100) < 11 { + // if rand::thread_rng().gen_range(0, 100) < 11 { + if rare_monster_table.roll_appearance(&monster.monster) { monsters.push(Some(MapEnemy::new(MonsterType::PouillySlime, monster.map_area).set_shiny())) } else { monsters.push(Some(MapEnemy::new(MonsterType::PofuillySlime, monster.map_area))) @@ -75,42 +79,50 @@ fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> // guaranteed rare slime already pushed // roll for the other 3 (4?) copies for _ in 0..4 { - if rand::thread_rng().gen_range(0, 100) < 11 { + // if rand::thread_rng().gen_range(0, 100) < 11 { + if rare_monster_table.roll_appearance(&monster.monster) { monsters.push(Some(MapEnemy::new(MonsterType::PouillySlime, monster.map_area).set_shiny())) } else { monsters.push(Some(MapEnemy::new(MonsterType::PofuillySlime, monster.map_area))) } } }, - MonsterType::SandRappyCrater => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::SandRappyCrater => {if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::SandRappyCrater => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::DelRappyCrater, monster.map_area).set_shiny())) }}, - MonsterType::ZuCrater => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::ZuCrater => {if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::ZuCrater => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::PazuzuCrater, monster.map_area).set_shiny())) }}, - MonsterType::Dorphon => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::Dorphon => {if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::Dorphon => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::DorphonEclair, monster.map_area).set_shiny())) }}, - MonsterType::SandRappyDesert => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::SandRappyDesert => {if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::SandRappyDesert => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::DelRappyDesert, monster.map_area).set_shiny())) }}, - MonsterType::ZuDesert => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::ZuDesert => {if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::ZuDesert => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::PazuzuDesert, monster.map_area).set_shiny())) }}, - MonsterType::MerissaA => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::MerissaA => {if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::MerissaA => {if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::MerissaAA, monster.map_area).set_shiny())) }}, - MonsterType::SaintMillion | MonsterType::Shambertin => {if rand::thread_rng().gen_range(0, 100) < 11 { + // MonsterType::SaintMillion | MonsterType::Shambertin => { if rand::thread_rng().gen_range(0, 100) < 11 { + MonsterType::SaintMillion | MonsterType::Shambertin => { if rare_monster_table.roll_appearance(&monster.monster) { monsters.pop(); monsters.push(Some(MapEnemy::new(MonsterType::Kondrieu, monster.map_area).set_shiny())) }}, - +*/ MonsterType::Monest => { for _ in 0..30 { @@ -223,17 +235,21 @@ fn parse_enemy(episode: &Episode, map_area: &MapArea, raw_enemy: RawMapEnemy) -> pub fn enemy_data_from_stream(cursor: &mut impl Read, map_area: &MapArea, episode: &Episode) -> Vec> { +// pub fn enemy_data_from_stream(cursor: &mut impl Read, map_area: &MapArea, episode: &Episode, rare_monster_table: enemy::RareMonsterAppearTable) -> Vec> { let mut enemy_data = Vec::new(); while let Ok(enemy) = RawMapEnemy::from_byte_stream(cursor) { enemy_data.append(&mut parse_enemy(episode, map_area, enemy)); + // enemy_data.append(&mut parse_enemy(episode, map_area, enemy, rare_monster_table)); } enemy_data } fn enemy_data_from_map_data(map_variant: &MapVariant, episode: &Episode) -> Vec> { +// fn enemy_data_from_map_data(map_variant: &MapVariant, episode: &Episode, rare_monster_table: enemy::RareMonsterAppearTable) -> Vec> { let path = map_variant.dat_file(); let mut cursor = File::open(path).unwrap(); enemy_data_from_stream(&mut cursor, &map_variant.map, episode) + // enemy_data_from_stream(&mut cursor, &map_variant.map, episode, rare_monster_table) } @@ -252,7 +268,8 @@ pub struct Maps { } impl Maps { - pub fn new(room_mode: RoomMode) -> Maps { + // pub fn new(room_mode: RoomMode) -> Maps { + pub fn new(room_mode: RoomMode, rare_monster_table: &enemy::RareMonsterAppearTable) -> Maps { let map_variants = match (room_mode.episode(), room_mode.single_player()) { (Episode::One, 0) => { vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online), @@ -344,16 +361,20 @@ impl Maps { _ => unreachable!() }; - let maps = Maps { - enemy_data: map_variants.iter().fold(Vec::new(), |mut enemy_data, map_variant| { - enemy_data.append(&mut enemy_data_from_map_data(map_variant, &room_mode.episode())); - enemy_data - }), - object_data: map_variants.iter().map(|map_variant| { - objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) - }).flatten().collect(), - map_variants, + let mut maps = Maps { + enemy_data: map_variants.iter() + .fold(Vec::new(), |mut enemy_data, map_variant| { + enemy_data.append(&mut enemy_data_from_map_data(map_variant, &room_mode.episode())); + // enemy_data.append(&mut enemy_data_from_map_data(map_variant, &room_mode.episode(), rare_monster_table)); + enemy_data + }), + object_data: map_variants.iter() + .map(|map_variant| { + objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) + }).flatten().collect(), + map_variants, }; + maps.roll_monster_appearance(rare_monster_table); maps } @@ -378,7 +399,18 @@ impl Maps { } pub fn set_quest_data(&mut self, enemies: Vec>, objects: Vec>) { + // pub fn set_quest_data(&mut self, enemies: Vec>, objects: Vec>, rare_monster_table: RareMonsterAppearTable) { self.enemy_data = enemies; + + // self.enemy_data = enemies + // .iter() + // .map(|&x| if x.is_some() { + // Some(x.unwrap().roll_appearance_for_quest(rare_monster_table)) + // } else { + // x + // }) + // .collect(); + self.object_data = objects; } @@ -403,4 +435,15 @@ impl Maps { } rare_monsters } + + pub fn roll_monster_appearance(&mut self, rare_monster_table: &RareMonsterAppearTable) { + self.enemy_data = self.enemy_data + .iter() + .map(|&x| if x.is_some() { + Some(x.unwrap().roll_appearance_for_quest(&rare_monster_table)) + } else { + x + }) + .collect(); + } } diff --git a/src/ship/map/mod.rs b/src/ship/map/mod.rs index f57c80c..6c54343 100644 --- a/src/ship/map/mod.rs +++ b/src/ship/map/mod.rs @@ -1,5 +1,5 @@ pub mod area; -mod enemy; +pub mod enemy; mod object; mod variant; mod maps; diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs index 283c2e4..8c2ba8c 100644 --- a/src/ship/packet/handler/room.rs +++ b/src/ship/packet/handler/room.rs @@ -130,9 +130,10 @@ pub fn done_bursting(id: ClientId, .flatten() ); + // TODO: check how often `done_bursting` is called. ie: make sure it's only used when joining a room and not each time a player warps in a pipe if rare_monster_list.is_some() { let rare_monster_packet = SendShipPacket::RareMonsterList(builder::room::build_rare_monster_list(rare_monster_list.unwrap()).unwrap()); // TODO: don't double unwrap - result = Box::new(result.chain(vec![(id, rare_monster_packet)])); + result = Box::new(result.chain(vec![(id, rare_monster_packet)])); // TODO: make sure we arent clobbering `result` here } result diff --git a/src/ship/room.rs b/src/ship/room.rs index 3aae5da..3f0918a 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -7,6 +7,7 @@ use crate::ship::drops::DropTable; use crate::entity::character::SectionID; use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats}; use crate::ship::map::area::MapAreaLookup; +use crate::ship::map::enemy::RareMonsterAppearTable; #[derive(Debug)] pub enum RoomCreationError { @@ -167,6 +168,7 @@ pub struct RoomState { pub bursting: bool, pub monster_stats: Box>, pub map_areas: MapAreaLookup, + pub rare_monster_table: Box, // items on ground // enemy info } @@ -231,13 +233,19 @@ impl RoomState { } }; + let random_seed = rand::thread_rng().gen(); + let rare_monster_table = RareMonsterAppearTable::new(room_mode.episode(), random_seed); + Ok(RoomState { monster_stats: Box::new(load_monster_stats_table(&room_mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(room_mode))?), mode: room_mode, - random_seed: rand::thread_rng().gen(), + // random_seed: rand::thread_rng().gen(), + random_seed: random_seed, + rare_monster_table: Box::new(rare_monster_table.clone()), name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(), password: create_room.password, - maps: Maps::new(room_mode), + // maps: Maps::new(room_mode), + maps: Maps::new(room_mode, &rare_monster_table), section_id, drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)), bursting: false,