Removed all rng matches in code to determine loot tables, and moved to loot tables specific for each sprite, creature, or dungeon.

This commit is contained in:
Sam 2021-04-02 23:03:59 -04:00
parent 9ad5b0f6b7
commit 27f178286d
40 changed files with 416 additions and 453 deletions

View File

@ -0,0 +1,4 @@
[
(1.0, LootTable("common.loot_tables.food.prepared")),
(2.0, LootTable("common.loot_tables.cave_large")),
]

View File

@ -0,0 +1,6 @@
[
(1.0, LootTable("common.loot_tables.food.prepared")),
(1.0, LootTable("common.loot_tables.cave_large")),
(1.0, LootTable("common.loot_tables.weapons.tier-2")),
(5.0, Item("common.items.crafting_ing.leather_troll")),
]

View File

@ -0,0 +1,6 @@
[
(1.0, LootTable("common.loot_tables.food.prepared")),
(1.0, Item("common.items.crafting_ing.icy_fang")),
(1.0, LootTable("common.loot_tables.weapons.tier-2")),
(4.0, LootTable("common.loot_tables.cave_large")),
]

View File

@ -0,0 +1,4 @@
[
(1.0, LootTable("common.loot_tables.food.wild_ingredients")),
(1.0, LootTable("common.loot_tables.fallback")),
]

View File

@ -0,0 +1,3 @@
[
(1.0, LootTable("common.loot_tables.weapons.tier-5")),
]

View File

@ -0,0 +1,7 @@
[
(1.0, LootTable("common.loot_tables.food.prepared")),
(1.0, LootTable("common.loot_tables.armor.steel")),
(1.0, LootTable("common.loot_tables.weapons.tier-1")),
(1.0, LootTable("common.loot_tables.weapons.tier-2")),
(1.0, LootTable("common.loot_tables.weapons.tier-3")),
]

View File

@ -0,0 +1,7 @@
[
(1.0, LootTable("common.loot_tables.humanoids")),
(1.0, LootTable("common.loot_tables.armor.swift")),
(1.0, LootTable("common.loot_tables.armor.cloth")),
(1.0, LootTable("common.loot_tables.weapons.starter")),
(1.0, LootTable("common.loot_tables.fallback")),
]

View File

@ -0,0 +1,5 @@
[
(1.0, LootTable("common.loot_tables.food.wild_ingredients")),
(1.0, Item("common.items.crafting_ing.leather_scraps")),
(1.0, LootTable("common.loot_tables.fallback")),
]

View File

@ -0,0 +1,4 @@
[
(1.0, LootTable("common.loot_tables.food.wild_ingredients")),
(1.0, Item("common.items.crafting_ing.leather_scraps")),
]

View File

@ -0,0 +1,5 @@
[
(1.0, LootTable("common.loot_tables.food.wild_ingredients")),
(1.0, Item("common.items.crafting_ing.leather_scraps")),
(1.0, Item("common.items.crafting_ing.icy_fang")),
]

View File

@ -0,0 +1,4 @@
[
(1.0, LootTable("common.loot_tables.food.wild_ingredients")),
(1.0, Item("common.items.crafting_ing.leather_scraps")),
]

View File

@ -0,0 +1,3 @@
[
(1.0, LootTable("common.loot_tables.materials.underground")),
]

View File

@ -1,4 +1,3 @@
[
[
(1.0, Item("common.items.crafting_ing.leather_scraps")),
(1.0, CreatureMaterial),
]
]

View File

@ -0,0 +1,4 @@
[
(1.0, Item("common.items.crafting_ing.leather_scraps")),
(1.0, Item("common.items.crafting_ing.raptor_feather")),
]

View File

@ -0,0 +1,5 @@
[
(1.0, LootTable("common.loot_tables.humanoids")),
(1.0, LootTable("common.loot_tables.armor.cloth")),
(2.0, LootTable("common.loot_tables.weapons.tier-0")),
]

View File

@ -0,0 +1,5 @@
[
(1.0, LootTable("common.loot_tables.humanoids")),
(1.0, LootTable("common.loot_tables.armor.swift")),
(2.0, LootTable("common.loot_tables.weapons.tier-1")),
]

View File

@ -0,0 +1,5 @@
[
(1.0, LootTable("common.loot_tables.humanoids")),
(1.0, LootTable("common.loot_tables.armor.plate")),
(2.0, LootTable("common.loot_tables.weapons.tier-2")),
]

View File

@ -0,0 +1,6 @@
[
(1.0, LootTable("common.loot_tables.humanoids")),
(1.0, LootTable("common.loot_tables.armor.steel")),
(1.0, LootTable("common.loot_tables.weapons.tier-3")),
(3.0, LootTable("common.loot_tables.cultists")),
]

View File

@ -0,0 +1,5 @@
[
(1.0, LootTable("common.loot_tables.humanoids")),
(1.0, LootTable("common.loot_tables.weapons.tier-4")),
(5.0, LootTable("common.loot_tables.cultists")),
]

View File

@ -0,0 +1,4 @@
[
(1.0, LootTable("common.loot_tables.creature.biped_large.mindflayer")),
(3.0, LootTable("common.loot_tables.miniboss")),
]

View File

@ -0,0 +1,6 @@
[
(1.0, LootTable("common.loot_tables.humanoids")),
(1.0, LootTable("common.loot_tables.weapons.tier-5")),
(3.0, LootTable("common.loot_tables.cultists")),
(5.0, Item("common.items.food.cheese")),
]

View File

@ -0,0 +1,6 @@
[
(1.0, LootTable("common.loot_tables.weapons.tier-1")),
(1.0, LootTable("common.loot_tables.armor.cloth")),
(1.0, LootTable("common.loot_tables.armor.swift")),
(1.0, LootTable("common.loot_tables.fallback")),
]

View File

@ -0,0 +1,8 @@
[
(1.0, LootTable("common.loot_tables.weapons.tier-0")),
(1.0, LootTable("common.loot_tables.weapons.tier-1")),
(1.0, LootTable("common.loot_tables.armor.cloth")),
(1.0, LootTable("common.loot_tables.armor.swift")),
(0.1, LootTable("common.loot_tables.armor.plate")),
(1.0, LootTable("common.loot_tables.fallback")),
]

View File

@ -0,0 +1,4 @@
[
(1.0, LootTable("common.loot_tables.materials.common")),
(2.0, LootTable("common.loot_tables.food.prepared")),
]

View File

@ -0,0 +1,6 @@
[
(1.0, LootTable("common.loot_tables.materials.common")),
(1.0, LootTable("common.loot_tables.weapons.tier-0")),
(1.0, LootTable("common.loot_tables.materials.underground")),
(1.0, LootTable("common.loot_tables.fallback")),
]

View File

@ -2190,7 +2190,7 @@ GrassBlue: Some((
wind_sway: 1.0,
)),
// Underwater Chests
ChestBurried: Some((
ChestBuried: Some((
variations: [
(
model: "voxygen.voxel.sprite.underwater_chests.chest_skull",

View File

@ -254,9 +254,6 @@ fn loot_table(loot_table: &str) -> Result<(), Box<dyn Error>> {
LootSpec::LootTable(table) => {
wtr.write_record(&[&chance, "LootTable", table, "", ""])?
},
LootSpec::CreatureMaterial => {
wtr.write_record(&[&chance, "CreatureMaterial", "", "", ""])?
},
}
}

View File

@ -403,7 +403,6 @@ fn loot_table(loot_table: &str) -> Result<(), Box<dyn Error>> {
.expect("No loot table")
.to_string(),
),
"CreatureMaterial" => LootSpec::CreatureMaterial,
a => panic!(
"Loot specifier kind must be either \"Item\" or \"LootTable\"\n{}",
a

View File

@ -16,7 +16,6 @@ pub mod theropod;
use crate::{
assets::{self, Asset},
comp::Item,
make_case_elim,
npc::NpcKind,
};
@ -583,30 +582,6 @@ impl Body {
_ => Vec3::unit_z(),
}
}
pub fn get_material(&self) -> Item {
Item::new_from_asset_expect(match self {
Body::QuadrupedSmall(_) => "common.items.crafting_ing.leather_scraps",
Body::QuadrupedMedium(b) => match b.species {
quadruped_medium::Species::Frostfang | quadruped_medium::Species::Roshwalr => {
"common.items.crafting_ing.icy_fang"
},
_ => "common.items.crafting_ing.leather_scraps",
},
Body::Theropod(b) => match b.species {
theropod::Species::Sandraptor
| theropod::Species::Snowraptor
| theropod::Species::Woodraptor => "common.items.crafting_ing.raptor_feather",
_ => "common.items.crafting_ing.leather_scraps",
},
Body::BipedLarge(b) => match b.species {
biped_large::Species::Troll => "common.items.crafting_ing.leather_troll",
biped_large::Species::Wendigo => "common.items.crafting_ing.icy_fang",
_ => "common.items.food.cheese",
},
_ => "common.items.food.cheese",
})
}
}
impl Component for Body {

View File

@ -19,7 +19,6 @@ use crate::{
};
use core::mem;
use crossbeam_utils::atomic::AtomicCell;
use rand::prelude::*;
use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage};
use specs_idvs::IdvStorage;
@ -579,7 +578,6 @@ impl Item {
pub fn try_reclaim_from_block(block: Block) -> Option<Self> {
let chosen;
let mut rng = rand::thread_rng();
Some(Item::new_from_asset_expect(match block.get_sprite()? {
SpriteKind::Apple => "common.items.food.apple",
SpriteKind::Mushroom => "common.items.food.mushroom",
@ -601,44 +599,21 @@ impl Item {
// Containers
// IMPORTANT: Add any new container to `SpriteKind::is_container`
SpriteKind::Chest => {
chosen = Lottery::<LootSpec>::load_expect(match rng.gen_range(0..7) {
0 => "common.loot_tables.weapons.tier-0",
1 => "common.loot_tables.weapons.tier-1",
2 => "common.loot_tables.armor.swift",
3 => "common.loot_tables.armor.cloth",
4 => "common.loot_tables.armor.plate",
_ => "common.loot_tables.fallback",
})
.read();
return Some(chosen.choose().to_item(None));
chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.sprite.chest").read();
return Some(chosen.choose().to_item());
},
SpriteKind::ChestBurried => {
chosen = Lottery::<LootSpec>::load_expect(match rng.gen_range(0..7) {
1 => "common.loot_tables.weapons.tier-1",
2 => "common.loot_tables.armor.swift",
3 => "common.loot_tables.armor.cloth",
_ => "common.loot_tables.fallback",
})
.read();
return Some(chosen.choose().to_item(None));
SpriteKind::ChestBuried => {
chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.sprite.chest-buried")
.read();
return Some(chosen.choose().to_item());
},
SpriteKind::Mud => {
chosen = Lottery::<LootSpec>::load_expect(match rng.gen_range(0..5) {
0 => "common.loot_tables.materials.common",
1 => "common.loot_tables.weapons.tier-0",
2 => "common.loot_tables.materials.underground",
_ => "common.loot_tables.fallback",
})
.read();
return Some(chosen.choose().to_item(None));
chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.sprite.mud").read();
return Some(chosen.choose().to_item());
},
SpriteKind::Crate => {
chosen = Lottery::<LootSpec>::load_expect(match rng.gen_range(0..4) {
0 => "common.loot_tables.materials.common",
_ => "common.loot_tables.food.prepared",
})
.read();
return Some(chosen.choose().to_item(None));
chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.sprite.crate").read();
return Some(chosen.choose().to_item());
},
SpriteKind::Beehive => "common.items.crafting_ing.honey",

View File

@ -68,7 +68,6 @@ impl From<Vec<(f32, LootSpec)>> for ProbabilityFile {
.collect::<Vec<_>>()
.into_iter()
},
LootSpec::CreatureMaterial => vec![].into_iter(),
})
.collect(),
}

View File

@ -28,7 +28,7 @@
use crate::{
assets::{self, AssetExt},
comp::{Body, Item},
comp::Item,
};
use rand::prelude::*;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
@ -83,30 +83,23 @@ pub enum LootSpec {
ItemQuantity(String, u32, u32),
/// Loot table
LootTable(String),
/// Matches on species to provide a crafting material
CreatureMaterial,
}
impl LootSpec {
#[allow(unused_must_use)]
pub fn to_item(&self, body: Option<Body>) -> Item {
pub fn to_item(&self) -> Item {
match self {
Self::Item(item) => Item::new_from_asset_expect(&item),
Self::ItemQuantity(item, lower, upper) => {
let range = *lower..=*upper;
let quantity = thread_rng().gen_range(range);
let mut item = Item::new_from_asset_expect(&item);
item.set_amount(quantity);
let _ = item.set_amount(quantity);
item
},
Self::LootTable(table) => Lottery::<LootSpec>::load_expect(&table)
.read()
.choose()
.to_item(body),
Self::CreatureMaterial => body.map_or(
Item::new_from_asset_expect("common.items.food.cheese"),
|b| b.get_material(),
),
.to_item(),
}
}
}
@ -164,9 +157,6 @@ mod tests {
let loot_table = Lottery::<LootSpec>::load_expect_cloned(&loot_table);
validate_table_contents(loot_table);
},
LootSpec::CreatureMaterial => {
item.to_item(None);
},
}
}
}

View File

@ -105,7 +105,7 @@ make_case_elim!(
VialEmpty = 0x4E,
PotionMinor = 0x4F,
GrassBlue = 0x50,
ChestBurried = 0x51,
ChestBuried = 0x51,
Mud = 0x52,
FireBowlGround = 0x53,
CaveMushroom = 0x54,
@ -182,7 +182,7 @@ impl SpriteKind {
SpriteKind::WardrobeDouble => 3.0,
SpriteKind::Pot => 0.90,
SpriteKind::Mud => 0.36,
SpriteKind::ChestBurried => 0.91,
SpriteKind::ChestBuried => 0.91,
SpriteKind::StonyCoral => 1.4,
// TODO: Find suitable heights.
SpriteKind::BarrelCactus
@ -233,7 +233,7 @@ impl SpriteKind {
SpriteKind::VialEmpty => true,
SpriteKind::PotionMinor => true,
SpriteKind::Bowl => true,
SpriteKind::ChestBurried => true,
SpriteKind::ChestBuried => true,
SpriteKind::Mud => true,
SpriteKind::Seashells => true,
_ => false,
@ -244,7 +244,7 @@ impl SpriteKind {
pub fn is_container(&self) -> bool {
matches!(
self,
SpriteKind::Chest | SpriteKind::ChestBurried | SpriteKind::Mud | SpriteKind::Crate,
SpriteKind::Chest | SpriteKind::ChestBuried | SpriteKind::Mud | SpriteKind::Crate,
)
}

View File

@ -1,6 +1,9 @@
use crate::{
client::Client,
comp::{biped_large, quadruped_low, quadruped_small, skills::SkillGroupKind, PhysicsState},
comp::{
biped_large, quadruped_low, quadruped_medium, quadruped_small, skills::SkillGroupKind,
theropod, PhysicsState,
},
rtsim::RtSim,
Server, SpawnPoint, StateExt,
};
@ -28,7 +31,6 @@ use common::{
use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
use common_sys::state::BlockChange;
use hashbrown::HashSet;
use rand::prelude::*;
use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt};
use tracing::error;
use vek::{Vec2, Vec3};
@ -338,77 +340,56 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
// Decide for a loot drop before turning into a lootbag
let old_body = state.ecs().write_storage::<Body>().remove(entity);
let mut rng = rand::thread_rng();
let mut lottery = || {
let lottery = || {
Lottery::<LootSpec>::load_expect(match old_body {
Some(common::comp::Body::Humanoid(_)) => match rng.gen_range(0..5) {
0 => "common.loot_tables.humanoids",
1 => "common.loot_tables.armor.swift",
2 => "common.loot_tables.armor.cloth",
3 => "common.loot_tables.weapons.starter",
4 => "common.loot_tables.humanoids",
_ => "common.loot_tables.fallback",
},
Some(common::comp::Body::Humanoid(_)) => "common.loot_tables.creature.humanoid",
Some(common::comp::Body::QuadrupedSmall(quadruped_small)) => {
match quadruped_small.species {
quadruped_small::Species::Dodarock => {
"common.loot_tables.materials.underground"
},
_ => match rng.gen_range(0..4) {
0 => "common.loot_tables.food.wild_ingredients",
_ => "common.loot_tables.wild_animal",
"common.loot_tables.creature.quad_small.dodarock"
},
_ => "common.loot_tables.creature.quad_small.default",
}
},
Some(common::comp::Body::QuadrupedMedium(_)) => match rng.gen_range(0..4) {
0 => "common.loot_tables.food.wild_ingredients",
_ => "common.loot_tables.wild_animal",
Some(Body::QuadrupedMedium(quadruped_medium)) => match quadruped_medium.species {
quadruped_medium::Species::Frostfang | quadruped_medium::Species::Roshwalr => {
"common.loot_tables.creature.quad_medium.ice"
},
_ => "common.loot_tables.creature.quad_medium.default",
},
Some(common::comp::Body::BirdMedium(_)) => match rng.gen_range(0..3) {
0 => "common.loot_tables.food.wild_ingredients",
_ => "common.loot_tables.fallback",
Some(common::comp::Body::BirdMedium(_)) => {
"common.loot_tables.creature.bird_medium"
},
Some(common::comp::Body::FishMedium(_)) => "common.loot_tables.fish",
Some(common::comp::Body::FishSmall(_)) => "common.loot_tables.fish",
Some(common::comp::Body::FishMedium(_)) => "common.loot_tables.creature.fish",
Some(common::comp::Body::FishSmall(_)) => "common.loot_tables.creature.fish",
Some(common::comp::Body::BipedLarge(biped_large)) => match biped_large.species {
biped_large::Species::Wendigo => match rng.gen_range(0..7) {
0 => "common.loot_tables.food.prepared",
1 => "common.loot_tables.wild_animal",
2 => "common.loot_tables.weapons.tier-2",
_ => "common.loot_tables.cave_large",
},
biped_large::Species::Troll => match rng.gen_range(0..8) {
0 => "common.loot_tables.food.prepared",
1 => "common.loot_tables.cave_large",
2 => "common.loot_tables.weapons.tier-2",
_ => "common.loot_tables.wild_animal",
biped_large::Species::Wendigo => {
"common.loot_tables.creature.biped_large.wendigo"
},
biped_large::Species::Troll => "common.loot_tables.creature.biped_large.troll",
biped_large::Species::Occultsaurok
| biped_large::Species::Mightysaurok
| biped_large::Species::Slysaurok => "common.loot_tables.saurok",
_ => match rng.gen_range(0..3) {
0 => "common.loot_tables.food.prepared",
_ => "common.loot_tables.cave_large",
| biped_large::Species::Slysaurok => {
"common.loot_tables.creature.biped_large.saurok"
},
_ => "common.loot_tables.creature.biped_large.default",
},
Some(common::comp::Body::Golem(_)) => match rng.gen_range(0..5) {
0 => "common.loot_tables.food.prepared",
1 => "common.loot_tables.armor.steel",
2 => "common.loot_tables.weapons.tier-1",
3 => "common.loot_tables.weapons.tier-2",
4 => "common.loot_tables.weapons.tier-3",
_ => "common.loot_tables.fallback",
Some(common::comp::Body::Golem(_)) => "common.loot_tables.creature.golem",
Some(common::comp::Body::Theropod(theropod)) => match theropod.species {
theropod::Species::Sandraptor
| theropod::Species::Snowraptor
| theropod::Species::Woodraptor => {
"common.loot_tables.creature.theropod.raptor"
},
_ => "common.loot_tables.creature.theropod.default",
},
Some(common::comp::Body::Theropod(_)) => "common.loot_tables.wild_animal",
Some(common::comp::Body::Dragon(_)) => "common.loot_tables.weapons.tier-5",
Some(common::comp::Body::Dragon(_)) => "common.loot_tables.creature.dragon",
Some(common::comp::Body::QuadrupedLow(quadruped_low)) => {
match quadruped_low.species {
quadruped_low::Species::Maneater => "common.loot_tables.maneater",
_ => match rng.gen_range(0..3) {
0 => "common.loot_tables.food.wild_ingredients",
1 => "common.loot_tables.wild_animal",
_ => "common.loot_tables.fallback",
quadruped_low::Species::Maneater => {
"common.loot_tables.creature.quad_low.maneater"
},
_ => "common.loot_tables.creature.quad_low.default",
}
},
_ => "common.loot_tables.fallback",
@ -418,7 +399,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
let item = {
let mut item_drops = state.ecs().write_storage::<comp::ItemDrop>();
item_drops.remove(entity).map_or_else(
|| lottery().read().choose().to_item(old_body),
|| lottery().read().choose().to_item(),
|item_drop| item_drop.0,
)
};

View File

@ -282,7 +282,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, rng: &mut impl Rng) {
)
}),
// Underwater chests
(ChestBurried, true, |_, col| {
(ChestBuried, true, |_, col| {
(
MUSH_FACT
* 1.0e-6

View File

@ -553,54 +553,25 @@ impl Floor {
// Bad
let chosen = match room.difficulty {
0 => Lottery::<LootSpec>::load_expect(
match dynamic_rng.gen_range(0..4) {
0 => "common.loot_tables.humanoids",
1 => "common.loot_tables.armor.cloth",
_ => "common.loot_tables.weapons.tier-0",
},
"common.loot_tables.dungeon.tier-0.enemy",
),
1 => Lottery::<LootSpec>::load_expect(
match dynamic_rng.gen_range(0..4) {
0 => "common.loot_tables.humanoids",
1 => "common.loot_tables.armor.swift",
_ => "common.loot_tables.weapons.tier-1",
},
"common.loot_tables.dungeon.tier-1.enemy",
),
2 => Lottery::<LootSpec>::load_expect(
match dynamic_rng.gen_range(0..4) {
0 => "common.loot_tables.humanoids",
1 => "common.loot_tables.armor.plate",
_ => "common.loot_tables.weapons.tier-2",
},
"common.loot_tables.dungeon.tier-2.enemy",
),
3 => Lottery::<LootSpec>::load_expect(
match dynamic_rng.gen_range(0..10) {
0 => "common.loot_tables.humanoids",
1 => "common.loot_tables.armor.steel",
2 => "common.loot_tables.weapons.tier-3",
_ => "common.loot_tables.cultists",
},
"common.loot_tables.dungeon.tier-3.enemy",
),
4 => Lottery::<LootSpec>::load_expect(
match dynamic_rng.gen_range(0..6) {
0 => "common.loot_tables.humanoids",
1 => "common.loot_tables.fallback",
2 => "common.loot_tables.weapons.tier-4",
_ => "common.loot_tables.cultists",
},
"common.loot_tables.dungeon.tier-4.enemy",
),
5 => Lottery::<LootSpec>::load_expect(
match dynamic_rng.gen_range(0..5) {
0 => "common.loot_tables.humanoids",
1 => "common.loot_tables.fallback",
2 => "common.loot_tables.weapons.tier-5",
_ => "common.loot_tables.cultists",
},
"common.loot_tables.dungeon.tier-5.enemy",
),
_ => Lottery::<LootSpec>::load_expect("common.loot_tables.fallback"),
};
let chosen = chosen.read();
let chosen = chosen.choose();
//let is_giant =
// RandomField::new(room.seed.wrapping_add(1)).chance(Vec3::from(tile_pos),
// 0.2) && !room.boss;
@ -615,181 +586,160 @@ impl Floor {
.with_alignment(comp::Alignment::Enemy)
.with_loadout_config(loadout_builder::LoadoutConfig::CultistAcolyte)
.with_skillset_config(common::skillset_builder::SkillSetConfig::CultistAcolyte)
.with_loot_drop(chosen.to_item(None))
.with_loot_drop(chosen.read().choose().to_item())
.with_level(dynamic_rng.gen_range((room.difficulty as f32).powf(1.25) + 3.0..(room.difficulty as f32).powf(1.5) + 4.0).round() as u16);
let entity = match room.difficulty {
0 => {
let body =
comp::Body::BipedSmall(comp::biped_small::Body::random_with(
0 => entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Gnarling,
));
entity
.with_body(body)
.with_name("Gnarling")
.with_loadout_config(loadout_builder::LoadoutConfig::Gnarling)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Gnarling,
)
.with_loot_drop(chosen.to_item(Some(body)))
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.gnarling.\
adlet_bow"
},
1 => {
"common.items.npc_weapons.biped_small.gnarling.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.gnarling.\
wooden_spear"
},
),
))
.with_name("Gnarling")
.with_loadout_config(loadout_builder::LoadoutConfig::Gnarling)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Gnarling,
)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.gnarling.\
adlet_bow"
},
))
},
1 => {
let body =
comp::Body::BipedSmall(comp::biped_small::Body::random_with(
1 => {
"common.items.npc_weapons.biped_small.gnarling.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.gnarling.\
wooden_spear"
},
},
)),
1 => entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Adlet,
));
entity
.with_body(body)
.with_name("Adlet")
.with_loadout_config(loadout_builder::LoadoutConfig::Adlet)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Adlet,
)
.with_loot_drop(chosen.to_item(Some(body)))
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.adlet.\
adlet_bow"
},
1 => {
"common.items.npc_weapons.biped_small.adlet.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.adlet.\
wooden_spear"
},
),
))
.with_name("Adlet")
.with_loadout_config(loadout_builder::LoadoutConfig::Adlet)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Adlet,
)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => "common.items.npc_weapons.biped_small.adlet.adlet_bow",
1 => {
"common.items.npc_weapons.biped_small.adlet.gnoll_staff"
},
))
},
2 => {
let body =
comp::Body::BipedSmall(comp::biped_small::Body::random_with(
_ => {
"common.items.npc_weapons.biped_small.adlet.\
wooden_spear"
},
},
)),
2 => entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Sahagin,
));
entity
.with_body(body)
.with_name("Sahagin")
.with_loadout_config(loadout_builder::LoadoutConfig::Sahagin)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Sahagin,
)
.with_loot_drop(chosen.to_item(Some(body)))
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.sahagin.\
adlet_bow"
},
1 => {
"common.items.npc_weapons.biped_small.sahagin.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.sahagin.\
wooden_spear"
},
),
))
.with_name("Sahagin")
.with_loadout_config(loadout_builder::LoadoutConfig::Sahagin)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Sahagin,
)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.sahagin.adlet_bow"
},
))
},
3 => {
let body =
comp::Body::BipedSmall(comp::biped_small::Body::random_with(
1 => {
"common.items.npc_weapons.biped_small.sahagin.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.sahagin.\
wooden_spear"
},
},
)),
3 => entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Haniwa,
));
entity
.with_body(body)
.with_name("Haniwa")
.with_loadout_config(loadout_builder::LoadoutConfig::Haniwa)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Haniwa,
)
.with_loot_drop(chosen.to_item(Some(body)))
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.haniwa.\
adlet_bow"
},
1 => {
"common.items.npc_weapons.biped_small.haniwa.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.haniwa.\
wooden_spear"
},
),
))
.with_name("Haniwa")
.with_loadout_config(loadout_builder::LoadoutConfig::Haniwa)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Haniwa,
)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.haniwa.adlet_bow"
},
))
},
4 => {
let body =
comp::Body::BipedSmall(comp::biped_small::Body::random_with(
1 => {
"common.items.npc_weapons.biped_small.haniwa.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.haniwa.\
wooden_spear"
},
},
)),
4 => entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Myrmidon,
));
entity
.with_body(body)
.with_name("Myrmidon")
.with_loadout_config(loadout_builder::LoadoutConfig::Myrmidon)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Myrmidon,
)
.with_loot_drop(chosen.to_item(Some(body)))
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.myrmidon.\
adlet_bow"
},
1 => {
"common.items.npc_weapons.biped_small.myrmidon.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.myrmidon.\
wooden_spear"
},
),
))
.with_name("Myrmidon")
.with_loadout_config(loadout_builder::LoadoutConfig::Myrmidon)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Myrmidon,
)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => {
"common.items.npc_weapons.biped_small.myrmidon.\
adlet_bow"
},
))
},
1 => {
"common.items.npc_weapons.biped_small.myrmidon.\
gnoll_staff"
},
_ => {
"common.items.npc_weapons.biped_small.myrmidon.\
wooden_spear"
},
},
)),
5 => match dynamic_rng.gen_range(0..6) {
0 => {
let body = comp::Body::Humanoid(comp::humanoid::Body::random());
entity
.with_body(body)
.with_name("Cultist Warlock")
.with_loadout_config(
loadout_builder::LoadoutConfig::Warlock,
)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Warlock,
)
.with_loot_drop(chosen.to_item(Some(body)))
.with_main_tool(comp::Item::new_from_asset_expect(
"common.items.weapons.staff.cultist_staff",
))
},
0 => entity
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
.with_name("Cultist Warlock")
.with_loadout_config(loadout_builder::LoadoutConfig::Warlock)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Warlock,
)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
"common.items.weapons.staff.cultist_staff",
)),
1 => entity
.with_body(comp::Body::Object(comp::object::Body::Crossbow))
.with_name("Possessed Turret".to_string())
@ -802,7 +752,7 @@ impl Floor {
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Warlord,
)
.with_loot_drop(chosen.to_item(None))
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => "common.items.weapons.axe.malachite_axe-0",
@ -853,10 +803,7 @@ impl Floor {
"common.loot_tables.weapons.tier-4",
),
5 => Lottery::<LootSpec>::load_expect(
match dynamic_rng.gen_range(0..3) {
0 => "common.loot_tables.mindflayer",
_ => "common.loot_tables.miniboss",
},
"common.loot_tables.dungeon.tier-5.boss",
),
_ => {
Lottery::<LootSpec>::load_expect("common.loot_tables.fallback")
@ -866,85 +813,81 @@ impl Floor {
let chosen = chosen.choose();
let entity = match room.difficulty {
0 => {
let body = comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Harvester,
),
);
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Harvester,
),
))
.with_name("Harvester".to_string())
.with_loot_drop(chosen.to_item(Some(body))),
.with_loot_drop(chosen.to_item()),
]
},
1 => {
let body = comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Yeti,
),
);
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Yeti,
),
))
.with_name("Yeti".to_string())
.with_loot_drop(chosen.to_item(Some(body))),
.with_loot_drop(chosen.to_item()),
]
},
2 => {
let body = comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Tidalwarrior,
),
);
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Tidalwarrior,
),
))
.with_name("Tidal Warrior".to_string())
.with_loot_drop(chosen.to_item(Some(body))),
.with_loot_drop(chosen.to_item()),
]
},
3 => {
let body = comp::Body::Golem(comp::golem::Body::random_with(
dynamic_rng,
&comp::golem::Species::ClayGolem,
));
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::Golem(
comp::golem::Body::random_with(
dynamic_rng,
&comp::golem::Species::ClayGolem,
),
))
.with_name("Clay Golem".to_string())
.with_loot_drop(chosen.to_item(Some(body))),
.with_loot_drop(chosen.to_item()),
]
},
4 => {
let body = comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Minotaur,
),
);
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Minotaur,
),
))
.with_name("Minotaur".to_string())
.with_loot_drop(chosen.to_item(Some(body))),
.with_loot_drop(chosen.to_item()),
]
},
5 => {
let body = comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Mindflayer,
),
);
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Mindflayer,
),
))
.with_name("Mindflayer".to_string())
.with_loot_drop(chosen.to_item(Some(body)))
.with_loot_drop(chosen.to_item())
.with_skillset_config(
common::skillset_builder::SkillSetConfig::Mindflayer,
),
@ -997,13 +940,13 @@ impl Floor {
if tile_pos == miniboss_spawn_tile && tile_wcenter.xy() == wpos2d {
let chosen = match room.difficulty {
0 => Lottery::<LootSpec>::load_expect(
"common.loot_tables.wild_animal",
"common.loot_tables.weapons.tier-0",
),
1 => Lottery::<LootSpec>::load_expect(
"common.loot_tables.wild_animal",
"common.loot_tables.weapons.tier-1",
),
2 => Lottery::<LootSpec>::load_expect(
"common.loot_tables.wild_animal",
"common.loot_tables.weapons.tier-2",
),
3 => Lottery::<LootSpec>::load_expect(
"common.loot_tables.weapons.tier-3",
@ -1011,71 +954,63 @@ impl Floor {
4 => Lottery::<LootSpec>::load_expect(
"common.loot_tables.weapons.tier-4",
),
5 => Lottery::<LootSpec>::load_expect("common.loot_tables.cultist"),
5 => {
Lottery::<LootSpec>::load_expect("common.loot_tables.cultists")
},
_ => {
Lottery::<LootSpec>::load_expect("common.loot_tables.fallback")
},
};
let entity = match room.difficulty {
0 => {
let body = comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng,
&comp::quadruped_medium::Species::Bonerattler,
),
);
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng,
&comp::quadruped_medium::Species::Bonerattler,
),
))
.with_name("Bonerattler".to_string())
.with_loot_drop(
chosen.read().choose().to_item(Some(body)),
),
.with_loot_drop(chosen.read().choose().to_item()),
]
},
1 => {
let body = comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng,
&comp::quadruped_medium::Species::Bonerattler,
),
);
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng,
&comp::quadruped_medium::Species::Bonerattler,
),
))
.with_name("Bonerattler".to_string())
.with_loot_drop(
chosen.read().choose().to_item(Some(body))
);
.with_loot_drop(chosen.read().choose().to_item());
3
]
},
2 => {
let mut entities = Vec::new();
let body = comp::Body::QuadrupedLow(
comp::quadruped_low::Body::random_with(
dynamic_rng,
&comp::quadruped_low::Species::Hakulaq,
),
);
entities.resize_with(6, || {
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::QuadrupedLow(
comp::quadruped_low::Body::random_with(
dynamic_rng,
&comp::quadruped_low::Species::Hakulaq,
),
))
.with_name("Hakulaq".to_string())
.with_loot_drop(
chosen.read().choose().to_item(Some(body)),
)
.with_loot_drop(chosen.read().choose().to_item())
});
entities
},
3 => {
let mut entities = Vec::new();
let body = comp::Body::Humanoid(comp::humanoid::Body::random());
entities.push(
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
.with_name("Animal Trainer".to_string())
.with_loot_drop(chosen.read().choose().to_item(Some(body)))
.with_loot_drop(chosen.read().choose().to_item())
.with_loadout_config(loadout_builder::LoadoutConfig::CultistAcolyte)
.with_skillset_config(
common::skillset_builder::SkillSetConfig::CultistAcolyte
@ -1092,53 +1027,44 @@ impl Floor {
},
)),
);
let body = comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng,
&comp::quadruped_medium::Species::Darkhound,
),
);
entities.resize_with(entities.len() + 2, || {
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng,
&comp::quadruped_medium::Species::Darkhound,
),
))
.with_name("Tamed Darkhound".to_string())
.with_loot_drop(
chosen.read().choose().to_item(Some(body)),
)
.with_loot_drop(chosen.read().choose().to_item())
});
entities
},
4 => {
let body = comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Dullahan,
),
);
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng,
&comp::biped_large::Species::Dullahan,
),
))
.with_name("Dullahan Guard".to_string())
.with_loot_drop(
chosen.read().choose().to_item(Some(body)),
),
.with_loot_drop(chosen.read().choose().to_item()),
]
},
5 => {
let body = comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Husk,
),
);
let mut entities = Vec::new();
entities.resize_with(10, || {
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(body)
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Husk,
),
))
.with_name("Cultist Husk".to_string())
.with_loot_drop(
chosen.read().choose().to_item(Some(body)),
)
.with_loot_drop(chosen.read().choose().to_item())
.with_loadout_config(
loadout_builder::LoadoutConfig::Husk,
)