mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'christof/christmas23' into 'master'
Christmas theme revival See merge request veloren/veloren!4209
This commit is contained in:
commit
5af8c4687e
@ -1,8 +1,12 @@
|
||||
// Christmas event
|
||||
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
#![enable(implicit_some)]
|
||||
(
|
||||
head: Item("common.items.armor.pirate.hat"),
|
||||
head: Seasonal([
|
||||
(Some(Christmas), Choice([
|
||||
(1, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
(1, Some(Item("common.items.armor.pirate.hat")))
|
||||
])),
|
||||
(None, Item("common.items.armor.pirate.hat")),
|
||||
]),
|
||||
shoulders: Item("common.items.armor.mail.orichalcum.shoulder"),
|
||||
chest: Item("common.items.armor.mail.orichalcum.chest"),
|
||||
gloves: Item("common.items.armor.mail.orichalcum.hand"),
|
||||
|
@ -1,11 +1,17 @@
|
||||
// Christmas event
|
||||
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
#![enable(implicit_some)]
|
||||
(
|
||||
head: Choice([
|
||||
(3, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.bamboo_twig")),
|
||||
(2, None),
|
||||
head: Seasonal([
|
||||
(Some(Christmas), Choice([
|
||||
(9, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
(3, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.bamboo_twig")),
|
||||
(2, None),
|
||||
])),
|
||||
(None, Choice([
|
||||
(3, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.bamboo_twig")),
|
||||
(2, None),
|
||||
])),
|
||||
]),
|
||||
chest: Choice([
|
||||
(1, Item("common.items.armor.misc.chest.worker_green_0")),
|
||||
|
@ -1,14 +1,11 @@
|
||||
// Christmas event
|
||||
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
// Christmas event
|
||||
//(1.0, Some(Item("common.items.lantern.blue_0"))),
|
||||
//(1.0, Some(Item("common.items.lantern.polaris"))),
|
||||
//(2.0, Some(Item("common.items.lantern.red_0"))),
|
||||
//(2.0, Some(Item("common.items.lantern.green_0"))),
|
||||
#![enable(implicit_some)]
|
||||
(
|
||||
head: Choice([
|
||||
(1, Item("common.items.armor.misc.head.helmet")),
|
||||
head: Seasonal([
|
||||
(Some(Christmas), Choice([
|
||||
(1, Some(Item("common.items.armor.misc.head.helmet"))),
|
||||
(1, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
])),
|
||||
(None, Item("common.items.armor.misc.head.helmet")),
|
||||
]),
|
||||
shoulders: Item("common.items.armor.leather_plate.shoulder"),
|
||||
chest: Item("common.items.armor.leather_plate.chest"),
|
||||
@ -16,8 +13,18 @@
|
||||
belt: Item("common.items.armor.leather_plate.belt"),
|
||||
legs: Item("common.items.armor.leather_plate.pants"),
|
||||
feet: Item("common.items.armor.leather_plate.foot"),
|
||||
lantern: Choice([
|
||||
(1, Item("common.items.lantern.black_0")),
|
||||
(2, None),
|
||||
]),
|
||||
lantern: Seasonal([
|
||||
(Some(Christmas), Choice([
|
||||
(1, Some(Item("common.items.lantern.blue_0"))),
|
||||
(1, Some(Item("common.items.lantern.polaris"))),
|
||||
(2, Some(Item("common.items.lantern.red_0"))),
|
||||
(2, Some(Item("common.items.lantern.green_0"))),
|
||||
(1, Item("common.items.lantern.black_0")),
|
||||
(2, None),
|
||||
])),
|
||||
(None, Choice([
|
||||
(1, Item("common.items.lantern.black_0")),
|
||||
(2, None),
|
||||
])),
|
||||
])
|
||||
)
|
@ -1,11 +1,17 @@
|
||||
// Christmas event
|
||||
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
#![enable(implicit_some)]
|
||||
(
|
||||
head: Choice([
|
||||
(3, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.hood")),
|
||||
(2, None),
|
||||
head: Seasonal([
|
||||
(Some(Christmas), Choice([
|
||||
(9, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
(3, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.hood")),
|
||||
(2, None),
|
||||
])),
|
||||
(None, Choice([
|
||||
(3, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.hood")),
|
||||
(2, None),
|
||||
])),
|
||||
]),
|
||||
chest: Choice([
|
||||
(1, Item("common.items.armor.twigs.chest")),
|
||||
|
@ -1,12 +1,19 @@
|
||||
// Christmas event
|
||||
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
#![enable(implicit_some)]
|
||||
(
|
||||
head: Choice([
|
||||
(6, None),
|
||||
(2, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.hood")),
|
||||
(3, Item("common.items.armor.misc.head.hood_dark")),
|
||||
head: Seasonal([
|
||||
(Some(Christmas), Choice([
|
||||
(15, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
(6, None),
|
||||
(2, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.hood")),
|
||||
(3, Item("common.items.armor.misc.head.hood_dark")),
|
||||
])),
|
||||
(None, Choice([
|
||||
(6, None),
|
||||
(2, Item("common.items.armor.misc.head.straw")),
|
||||
(3, Item("common.items.armor.misc.head.hood")),
|
||||
(3, Item("common.items.armor.misc.head.hood_dark")),
|
||||
])),
|
||||
]),
|
||||
chest: Choice([
|
||||
(1, Item("common.items.armor.hide.leather.chest")),
|
||||
|
@ -1,10 +1,15 @@
|
||||
// Christmas event
|
||||
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
#![enable(implicit_some)]
|
||||
(
|
||||
head: Choice([
|
||||
(1, Item("common.items.armor.misc.head.headband")),
|
||||
(2, None),
|
||||
head: Seasonal([
|
||||
(Some(Christmas), Choice([
|
||||
(3, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
(2, None),
|
||||
(1, Item("common.items.armor.misc.head.headband")),
|
||||
])),
|
||||
(None, Choice([
|
||||
(2, None),
|
||||
(1, Item("common.items.armor.misc.head.headband")),
|
||||
])),
|
||||
]),
|
||||
shoulders: Choice([
|
||||
(1, Item("common.items.armor.cloth_blue.shoulder_0")),
|
||||
|
@ -1,10 +1,15 @@
|
||||
// Christmas event
|
||||
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
#![enable(implicit_some)]
|
||||
(
|
||||
head: Choice([
|
||||
(1, Item("common.items.armor.misc.head.straw")),
|
||||
(2, None),
|
||||
head: Seasonal([
|
||||
(Some(Christmas), Choice([
|
||||
(3, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||
(1, Item("common.items.armor.misc.head.straw")),
|
||||
(2, None),
|
||||
])),
|
||||
(None, Choice([
|
||||
(1, Item("common.items.armor.misc.head.straw")),
|
||||
(2, None),
|
||||
])),
|
||||
]),
|
||||
chest: Choice([
|
||||
(1, Item("common.items.armor.misc.chest.worker_green_0")),
|
||||
|
BIN
assets/voxygen/voxel/sprite/furniture/hirdrasil-antler-1.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/furniture/hirdrasil-antler-1.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/furniture/hirdrasil-antler.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/furniture/hirdrasil-antler.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -2240,6 +2240,16 @@ ChristmasOrnament: Some((
|
||||
offset: (-5.5, 0.5, 0.0),
|
||||
lod_axes: (1.0, 1.0, 1.0),
|
||||
),
|
||||
(
|
||||
model: "voxygen.voxel.sprite.furniture.hirdrasil-antler",
|
||||
offset: (-10.5, -2.5, -3.0),
|
||||
lod_axes: (1.0, 1.0, 1.0),
|
||||
),
|
||||
(
|
||||
model: "voxygen.voxel.sprite.furniture.hirdrasil-antler-1",
|
||||
offset: (-6.5, -2.5, -3.0),
|
||||
lod_axes: (1.0, 1.0, 1.0),
|
||||
),
|
||||
(
|
||||
model: "voxygen.voxel.sprite.furniture.moravian-star-orange",
|
||||
offset: (-5.5, -7.5, 0.0),
|
||||
|
@ -326,8 +326,11 @@ fn entity_drops(entity_config: &str) -> Result<(), Box<dyn Error>> {
|
||||
asset_path: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let entity_config = EntityConfig::load_expect(asset_path).read();
|
||||
let entity_info = EntityInfo::at(Vec3::new(0.0, 0.0, 0.0))
|
||||
.with_asset_expect(asset_path, &mut rand::thread_rng());
|
||||
let entity_info = EntityInfo::at(Vec3::new(0.0, 0.0, 0.0)).with_asset_expect(
|
||||
asset_path,
|
||||
&mut rand::thread_rng(),
|
||||
None,
|
||||
);
|
||||
let name = entity_info.name.unwrap_or_default();
|
||||
|
||||
// Create initial entry in drop table
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
assets::{self, AssetExt},
|
||||
calendar::{Calendar, CalendarEvent},
|
||||
comp::{
|
||||
arthropod, biped_large, biped_small, bird_large, bird_medium, golem,
|
||||
inventory::{
|
||||
@ -9,7 +10,7 @@ use crate::{
|
||||
item::{self, Item},
|
||||
object, quadruped_low, quadruped_medium, quadruped_small, theropod, Body,
|
||||
},
|
||||
resources::Time,
|
||||
resources::{Time, TimeOfDay},
|
||||
trade::SiteInformation,
|
||||
};
|
||||
use rand::{self, distributions::WeightedError, seq::SliceRandom, Rng};
|
||||
@ -48,10 +49,15 @@ enum ItemSpec {
|
||||
hands: Option<item::tool::Hands>,
|
||||
},
|
||||
Choice(Vec<(Weight, Option<ItemSpec>)>),
|
||||
Seasonal(Vec<(Option<CalendarEvent>, ItemSpec)>),
|
||||
}
|
||||
|
||||
impl ItemSpec {
|
||||
fn try_to_item(&self, rng: &mut impl Rng) -> Result<Option<Item>, SpecError> {
|
||||
fn try_to_item(
|
||||
&self,
|
||||
rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Result<Option<Item>, SpecError> {
|
||||
match self {
|
||||
ItemSpec::Item(item_asset) => {
|
||||
let item = Item::new_from_asset(item_asset).map_err(SpecError::ItemAssetError)?;
|
||||
@ -63,7 +69,7 @@ impl ItemSpec {
|
||||
.map_err(SpecError::ItemChoiceError)?;
|
||||
|
||||
let item = if let Some(item_spec) = item_spec {
|
||||
item_spec.try_to_item(rng)?
|
||||
item_spec.try_to_item(rng, time)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -76,6 +82,20 @@ impl ItemSpec {
|
||||
} => item::modular::random_weapon(*tool, *material, *hands, rng)
|
||||
.map(Some)
|
||||
.map_err(SpecError::ModularWeaponCreationError),
|
||||
ItemSpec::Seasonal(specs) => specs
|
||||
.iter()
|
||||
.find_map(|(season, spec)| match (season, time) {
|
||||
(Some(season), Some((_time, calendar))) => {
|
||||
if calendar.is_event(*season) {
|
||||
Some(spec.try_to_item(rng, time))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
(Some(_season), None) => None,
|
||||
(None, _) => Some(spec.try_to_item(rng, time)),
|
||||
})
|
||||
.unwrap_or(Ok(None)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +123,9 @@ impl ItemSpec {
|
||||
} => item::modular::random_weapon(*tool, *material, *hands, &mut rng)
|
||||
.map(drop)
|
||||
.map_err(ValidationError::ModularWeaponCreationError),
|
||||
ItemSpec::Seasonal(specs) => {
|
||||
specs.iter().try_for_each(|(_season, spec)| spec.validate())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,10 +139,14 @@ enum Hands {
|
||||
}
|
||||
|
||||
impl Hands {
|
||||
fn try_to_pair(&self, rng: &mut impl Rng) -> Result<(Option<Item>, Option<Item>), SpecError> {
|
||||
fn try_to_pair(
|
||||
&self,
|
||||
rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Result<(Option<Item>, Option<Item>), SpecError> {
|
||||
match self {
|
||||
Hands::InHands((mainhand, offhand)) => {
|
||||
let mut from_spec = |i: &ItemSpec| i.try_to_item(rng);
|
||||
let mut from_spec = |i: &ItemSpec| i.try_to_item(rng, time);
|
||||
|
||||
let mainhand = mainhand.as_ref().map(&mut from_spec).transpose()?.flatten();
|
||||
let offhand = offhand.as_ref().map(&mut from_spec).transpose()?.flatten();
|
||||
@ -130,7 +157,7 @@ impl Hands {
|
||||
.choose_weighted(rng, |(weight, _)| *weight)
|
||||
.map_err(SpecError::ItemChoiceError)?;
|
||||
|
||||
pair_spec.try_to_pair(rng)
|
||||
pair_spec.try_to_pair(rng, time)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -897,14 +924,22 @@ impl LoadoutBuilder {
|
||||
#[must_use]
|
||||
/// Construct new `LoadoutBuilder` from `asset_specifier`
|
||||
/// Will panic if asset is broken
|
||||
pub fn from_asset_expect(asset_specifier: &str, rng: &mut impl Rng) -> Self {
|
||||
Self::from_asset(asset_specifier, rng).expect("failed to load loadut config")
|
||||
pub fn from_asset_expect(
|
||||
asset_specifier: &str,
|
||||
rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Self {
|
||||
Self::from_asset(asset_specifier, rng, time).expect("failed to load loadut config")
|
||||
}
|
||||
|
||||
/// Construct new `LoadoutBuilder` from `asset_specifier`
|
||||
pub fn from_asset(asset_specifier: &str, rng: &mut impl Rng) -> Result<Self, SpecError> {
|
||||
pub fn from_asset(
|
||||
asset_specifier: &str,
|
||||
rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Result<Self, SpecError> {
|
||||
let loadout = Self::empty();
|
||||
loadout.with_asset(asset_specifier, rng)
|
||||
loadout.with_asset(asset_specifier, rng, time)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@ -923,17 +958,22 @@ impl LoadoutBuilder {
|
||||
pub fn from_loadout_spec(
|
||||
loadout_spec: LoadoutSpec,
|
||||
rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Result<Self, SpecError> {
|
||||
let loadout = Self::empty();
|
||||
loadout.with_loadout_spec(loadout_spec, rng)
|
||||
loadout.with_loadout_spec(loadout_spec, rng, time)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// Construct new `LoadoutBuilder` from `asset_specifier`
|
||||
///
|
||||
/// Will panic if asset is broken
|
||||
pub fn from_loadout_spec_expect(loadout_spec: LoadoutSpec, rng: &mut impl Rng) -> Self {
|
||||
Self::from_loadout_spec(loadout_spec, rng).expect("failed to load loadout spec")
|
||||
pub fn from_loadout_spec_expect(
|
||||
loadout_spec: LoadoutSpec,
|
||||
rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Self {
|
||||
Self::from_loadout_spec(loadout_spec, rng, time).expect("failed to load loadout spec")
|
||||
}
|
||||
|
||||
#[must_use = "Method consumes builder and returns updated builder."]
|
||||
@ -1049,14 +1089,18 @@ impl LoadoutBuilder {
|
||||
let rng = &mut rand::thread_rng();
|
||||
match preset {
|
||||
Preset::HuskSummon => {
|
||||
self = self.with_asset_expect("common.loadout.dungeon.cultist.husk", rng);
|
||||
self = self.with_asset_expect("common.loadout.dungeon.cultist.husk", rng, None);
|
||||
},
|
||||
Preset::BorealSummon => {
|
||||
self = self.with_asset_expect("common.loadout.world.boreal.boreal_warrior", rng);
|
||||
self =
|
||||
self.with_asset_expect("common.loadout.world.boreal.boreal_warrior", rng, None);
|
||||
},
|
||||
Preset::ClockworkSummon => {
|
||||
self =
|
||||
self.with_asset_expect("common.loadout.dungeon.dwarven_quarry.clockwork", rng);
|
||||
self = self.with_asset_expect(
|
||||
"common.loadout.dungeon.dwarven_quarry.clockwork",
|
||||
rng,
|
||||
None,
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@ -1066,10 +1110,15 @@ impl LoadoutBuilder {
|
||||
#[must_use = "Method consumes builder and returns updated builder."]
|
||||
pub fn with_creator(
|
||||
mut self,
|
||||
creator: fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder,
|
||||
creator: fn(
|
||||
LoadoutBuilder,
|
||||
Option<&SiteInformation>,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder,
|
||||
economy: Option<&SiteInformation>,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
self = creator(self, economy);
|
||||
self = creator(self, economy, time);
|
||||
|
||||
self
|
||||
}
|
||||
@ -1079,6 +1128,7 @@ impl LoadoutBuilder {
|
||||
mut self,
|
||||
spec: LoadoutSpec,
|
||||
rng: &mut R,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Result<Self, SpecError> {
|
||||
// Include any inheritance
|
||||
let spec = spec.eval(rng)?;
|
||||
@ -1086,7 +1136,7 @@ impl LoadoutBuilder {
|
||||
// Utility function to unwrap our itemspec
|
||||
let mut to_item = |maybe_item: Option<ItemSpec>| {
|
||||
if let Some(item) = maybe_item {
|
||||
item.try_to_item(rng)
|
||||
item.try_to_item(rng, time)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@ -1094,7 +1144,7 @@ impl LoadoutBuilder {
|
||||
|
||||
let to_pair = |maybe_hands: Option<Hands>, rng: &mut R| {
|
||||
if let Some(hands) = maybe_hands {
|
||||
hands.try_to_pair(rng)
|
||||
hands.try_to_pair(rng, time)
|
||||
} else {
|
||||
Ok((None, None))
|
||||
}
|
||||
@ -1174,10 +1224,15 @@ impl LoadoutBuilder {
|
||||
}
|
||||
|
||||
#[must_use = "Method consumes builder and returns updated builder."]
|
||||
pub fn with_asset(self, asset_specifier: &str, rng: &mut impl Rng) -> Result<Self, SpecError> {
|
||||
pub fn with_asset(
|
||||
self,
|
||||
asset_specifier: &str,
|
||||
rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Result<Self, SpecError> {
|
||||
let spec =
|
||||
LoadoutSpec::load_cloned(asset_specifier).map_err(SpecError::LoadoutAssetError)?;
|
||||
self.with_loadout_spec(spec, rng)
|
||||
self.with_loadout_spec(spec, rng, time)
|
||||
}
|
||||
|
||||
/// # Usage
|
||||
@ -1188,8 +1243,13 @@ impl LoadoutBuilder {
|
||||
/// 1) Will panic if there is no asset with such `asset_specifier`
|
||||
/// 2) Will panic if path to item specified in loadout file doesn't exist
|
||||
#[must_use = "Method consumes builder and returns updated builder."]
|
||||
pub fn with_asset_expect(self, asset_specifier: &str, rng: &mut impl Rng) -> Self {
|
||||
self.with_asset(asset_specifier, rng)
|
||||
pub fn with_asset_expect(
|
||||
self,
|
||||
asset_specifier: &str,
|
||||
rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Self {
|
||||
self.with_asset(asset_specifier, rng, time)
|
||||
.expect("failed loading loadout config")
|
||||
}
|
||||
|
||||
@ -1198,7 +1258,7 @@ impl LoadoutBuilder {
|
||||
#[must_use = "Method consumes builder and returns updated builder."]
|
||||
pub fn defaults(self) -> Self {
|
||||
let rng = &mut rand::thread_rng();
|
||||
self.with_asset_expect("common.loadout.default", rng)
|
||||
self.with_asset_expect("common.loadout.default", rng, None)
|
||||
}
|
||||
|
||||
#[must_use = "Method consumes builder and returns updated builder."]
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
assets::{self, AssetExt, Error},
|
||||
calendar::Calendar,
|
||||
comp::{
|
||||
self, agent, humanoid,
|
||||
inventory::loadout_builder::{LoadoutBuilder, LoadoutSpec},
|
||||
@ -8,6 +9,7 @@ use crate::{
|
||||
},
|
||||
lottery::LootSpec,
|
||||
npc::{self, NPC_NAMES},
|
||||
resources::TimeOfDay,
|
||||
rtsim,
|
||||
trade::SiteInformation,
|
||||
};
|
||||
@ -97,8 +99,11 @@ pub enum Meta {
|
||||
/// let dummy_position = Vec3::new(0.0, 0.0, 0.0);
|
||||
/// // rng is required because some elements may be randomly generated
|
||||
/// let mut dummy_rng = rand::thread_rng();
|
||||
/// let entity =
|
||||
/// EntityInfo::at(dummy_position).with_asset_expect("common.entity.template", &mut dummy_rng);
|
||||
/// let entity = EntityInfo::at(dummy_position).with_asset_expect(
|
||||
/// "common.entity.template",
|
||||
/// &mut dummy_rng,
|
||||
/// None,
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@ -189,7 +194,13 @@ pub struct EntityInfo {
|
||||
// Loadout
|
||||
pub inventory: Vec<(u32, Item)>,
|
||||
pub loadout: LoadoutBuilder,
|
||||
pub make_loadout: Option<fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder>,
|
||||
pub make_loadout: Option<
|
||||
fn(
|
||||
LoadoutBuilder,
|
||||
Option<&SiteInformation>,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder,
|
||||
>,
|
||||
// Skills
|
||||
pub skillset_asset: Option<String>,
|
||||
|
||||
@ -234,13 +245,18 @@ impl EntityInfo {
|
||||
/// Helper function for applying config from asset
|
||||
/// with specified Rng for managing loadout.
|
||||
#[must_use]
|
||||
pub fn with_asset_expect<R>(self, asset_specifier: &str, loadout_rng: &mut R) -> Self
|
||||
pub fn with_asset_expect<R>(
|
||||
self,
|
||||
asset_specifier: &str,
|
||||
loadout_rng: &mut R,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Self
|
||||
where
|
||||
R: rand::Rng,
|
||||
{
|
||||
let config = EntityConfig::load_expect_cloned(asset_specifier);
|
||||
|
||||
self.with_entity_config(config, Some(asset_specifier), loadout_rng)
|
||||
self.with_entity_config(config, Some(asset_specifier), loadout_rng, time)
|
||||
}
|
||||
|
||||
/// Evaluate and apply EntityConfig
|
||||
@ -250,6 +266,7 @@ impl EntityInfo {
|
||||
config: EntityConfig,
|
||||
config_asset: Option<&str>,
|
||||
loadout_rng: &mut R,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Self
|
||||
where
|
||||
R: rand::Rng,
|
||||
@ -297,7 +314,7 @@ impl EntityInfo {
|
||||
self = self.with_loot_drop(loot);
|
||||
|
||||
// NOTE: set loadout after body, as it's used with default equipement
|
||||
self = self.with_inventory(inventory, config_asset, loadout_rng);
|
||||
self = self.with_inventory(inventory, config_asset, loadout_rng, time);
|
||||
|
||||
// Prefer the new configuration, if possible
|
||||
let AgentConfig {
|
||||
@ -330,6 +347,7 @@ impl EntityInfo {
|
||||
inventory: InventorySpec,
|
||||
config_asset: Option<&str>,
|
||||
rng: &mut R,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> Self
|
||||
where
|
||||
R: rand::Rng,
|
||||
@ -350,14 +368,14 @@ impl EntityInfo {
|
||||
self = self.with_default_equip();
|
||||
},
|
||||
LoadoutKind::Asset(loadout) => {
|
||||
let loadout = LoadoutBuilder::from_asset(&loadout, rng).unwrap_or_else(|e| {
|
||||
let loadout = LoadoutBuilder::from_asset(&loadout, rng, time).unwrap_or_else(|e| {
|
||||
panic!("failed to load loadout for {config_asset}: {e:?}");
|
||||
});
|
||||
self.loadout = loadout;
|
||||
},
|
||||
LoadoutKind::Inline(loadout_spec) => {
|
||||
let loadout =
|
||||
LoadoutBuilder::from_loadout_spec(*loadout_spec, rng).unwrap_or_else(|e| {
|
||||
let loadout = LoadoutBuilder::from_loadout_spec(*loadout_spec, rng, time)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("failed to load loadout for {config_asset}: {e:?}");
|
||||
});
|
||||
self.loadout = loadout;
|
||||
@ -436,7 +454,11 @@ impl EntityInfo {
|
||||
#[must_use]
|
||||
pub fn with_lazy_loadout(
|
||||
mut self,
|
||||
creator: fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder,
|
||||
creator: fn(
|
||||
LoadoutBuilder,
|
||||
Option<&SiteInformation>,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder,
|
||||
) -> Self {
|
||||
self.make_loadout = Some(creator);
|
||||
self
|
||||
|
@ -654,6 +654,7 @@ fn handle_make_npc(
|
||||
config.clone(),
|
||||
Some(&entity_config),
|
||||
&mut loadout_rng,
|
||||
None,
|
||||
);
|
||||
|
||||
match NpcData::from_entity_info(entity_info) {
|
||||
|
@ -3,6 +3,7 @@
|
||||
use super::*;
|
||||
use crate::sys::terrain::NpcData;
|
||||
use common::{
|
||||
calendar::Calendar,
|
||||
comp::{self, Agent, Body, Presence, PresenceKind},
|
||||
event::{EventBus, NpcBuilder, ServerEvent},
|
||||
generation::{BodyBuilder, EntityConfig, EntityInfo},
|
||||
@ -53,13 +54,18 @@ fn humanoid_config(profession: &Profession) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn loadout_default(loadout: LoadoutBuilder, _economy: Option<&SiteInformation>) -> LoadoutBuilder {
|
||||
fn loadout_default(
|
||||
loadout: LoadoutBuilder,
|
||||
_economy: Option<&SiteInformation>,
|
||||
_time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
loadout
|
||||
}
|
||||
|
||||
fn merchant_loadout(
|
||||
loadout_builder: LoadoutBuilder,
|
||||
economy: Option<&SiteInformation>,
|
||||
_time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
trader_loadout(loadout_builder, economy, |_| true)
|
||||
}
|
||||
@ -67,6 +73,7 @@ fn merchant_loadout(
|
||||
fn farmer_loadout(
|
||||
loadout_builder: LoadoutBuilder,
|
||||
economy: Option<&SiteInformation>,
|
||||
_time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Food))
|
||||
}
|
||||
@ -74,6 +81,7 @@ fn farmer_loadout(
|
||||
fn herbalist_loadout(
|
||||
loadout_builder: LoadoutBuilder,
|
||||
economy: Option<&SiteInformation>,
|
||||
_time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
trader_loadout(loadout_builder, economy, |good| {
|
||||
matches!(good, Good::Ingredients)
|
||||
@ -83,6 +91,7 @@ fn herbalist_loadout(
|
||||
fn chef_loadout(
|
||||
loadout_builder: LoadoutBuilder,
|
||||
economy: Option<&SiteInformation>,
|
||||
_time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Food))
|
||||
}
|
||||
@ -90,6 +99,7 @@ fn chef_loadout(
|
||||
fn blacksmith_loadout(
|
||||
loadout_builder: LoadoutBuilder,
|
||||
economy: Option<&SiteInformation>,
|
||||
_time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
trader_loadout(loadout_builder, economy, |good| {
|
||||
matches!(good, Good::Tools | Good::Armor)
|
||||
@ -99,6 +109,7 @@ fn blacksmith_loadout(
|
||||
fn alchemist_loadout(
|
||||
loadout_builder: LoadoutBuilder,
|
||||
economy: Option<&SiteInformation>,
|
||||
_time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
trader_loadout(loadout_builder, economy, |good| {
|
||||
matches!(good, Good::Potions)
|
||||
@ -107,7 +118,11 @@ fn alchemist_loadout(
|
||||
|
||||
fn profession_extra_loadout(
|
||||
profession: Option<&Profession>,
|
||||
) -> fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder {
|
||||
) -> fn(
|
||||
LoadoutBuilder,
|
||||
Option<&SiteInformation>,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
match profession {
|
||||
Some(Profession::Merchant) => merchant_loadout,
|
||||
Some(Profession::Farmer) => farmer_loadout,
|
||||
@ -134,7 +149,12 @@ fn profession_agent_mark(profession: Option<&Profession>) -> Option<comp::agent:
|
||||
}
|
||||
}
|
||||
|
||||
fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo {
|
||||
fn get_npc_entity_info(
|
||||
npc: &Npc,
|
||||
sites: &Sites,
|
||||
index: IndexRef,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> EntityInfo {
|
||||
let pos = comp::Pos(npc.wpos);
|
||||
|
||||
let mut rng = npc.rng(Npc::PERM_ENTITY_CONFIG);
|
||||
@ -149,7 +169,7 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo
|
||||
let entity_config = EntityConfig::from_asset_expect_owned(config_asset)
|
||||
.with_body(BodyBuilder::Exact(npc.body));
|
||||
EntityInfo::at(pos.0)
|
||||
.with_entity_config(entity_config, Some(config_asset), &mut rng)
|
||||
.with_entity_config(entity_config, Some(config_asset), &mut rng, time)
|
||||
.with_alignment(if matches!(profession, Profession::Cultist) {
|
||||
comp::Alignment::Enemy
|
||||
} else {
|
||||
@ -204,7 +224,7 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo
|
||||
let entity_config = EntityConfig::from_asset_expect_owned(config_asset)
|
||||
.with_body(BodyBuilder::Exact(npc.body));
|
||||
|
||||
EntityInfo::at(pos.0).with_entity_config(entity_config, Some(config_asset), &mut rng)
|
||||
EntityInfo::at(pos.0).with_entity_config(entity_config, Some(config_asset), &mut rng, time)
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,6 +245,7 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, RtSimEntity>,
|
||||
WriteStorage<'a, comp::Agent>,
|
||||
ReadStorage<'a, Presence>,
|
||||
ReadExpect<'a, Calendar>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "rtsim::tick";
|
||||
@ -247,10 +268,12 @@ impl<'a> System<'a> for Sys {
|
||||
rtsim_entities,
|
||||
mut agents,
|
||||
presences,
|
||||
calendar,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut emitter = server_event_bus.emitter();
|
||||
let rtsim = &mut *rtsim;
|
||||
let calendar_data = (*time_of_day, (*calendar).clone());
|
||||
|
||||
// Set up rtsim inputs
|
||||
{
|
||||
@ -303,7 +326,12 @@ impl<'a> System<'a> for Sys {
|
||||
});
|
||||
},
|
||||
_ => {
|
||||
let entity_info = get_npc_entity_info(npc, &data.sites, index.as_index_ref());
|
||||
let entity_info = get_npc_entity_info(
|
||||
npc,
|
||||
&data.sites,
|
||||
index.as_index_ref(),
|
||||
Some(&calendar_data),
|
||||
);
|
||||
|
||||
emitter.emit(match NpcData::from_entity_info(entity_info) {
|
||||
NpcData::Data {
|
||||
@ -359,8 +387,12 @@ impl<'a> System<'a> for Sys {
|
||||
let npc = data.npcs.npcs.get_mut(npc_id)?;
|
||||
if matches!(npc.mode, SimulationMode::Simulated) {
|
||||
npc.mode = SimulationMode::Loaded;
|
||||
let entity_info =
|
||||
get_npc_entity_info(npc, &data.sites, index.as_index_ref());
|
||||
let entity_info = get_npc_entity_info(
|
||||
npc,
|
||||
&data.sites,
|
||||
index.as_index_ref(),
|
||||
Some(&calendar_data),
|
||||
);
|
||||
|
||||
Some(match NpcData::from_entity_info(entity_info) {
|
||||
NpcData::Data {
|
||||
|
@ -476,7 +476,8 @@ impl NpcData {
|
||||
let inventory = {
|
||||
// Evaluate lazy function for loadout creation
|
||||
if let Some(make_loadout) = make_loadout {
|
||||
loadout_builder = loadout_builder.with_creator(make_loadout, economy.as_ref());
|
||||
loadout_builder =
|
||||
loadout_builder.with_creator(make_loadout, economy.as_ref(), None);
|
||||
}
|
||||
let loadout = loadout_builder.build();
|
||||
let mut inventory = comp::inventory::Inventory::with_loadout(loadout, body);
|
||||
|
@ -270,9 +270,18 @@ pub fn get_sprite_instances<'a, I: 'a>(
|
||||
.overflowing_add((wpos.x as u64).overflowing_mul(wpos.y as u64).0)
|
||||
.0; // Awful PRNG
|
||||
|
||||
let ori = (block.get_ori().unwrap_or((seed % 4) as u8 * 2)) & 0b111;
|
||||
// % 4 is non uniform, take 7 and combine two lesser probable outcomes
|
||||
let ori = (block.get_ori().unwrap_or((((seed % 7) + 1) / 2) as u8 * 2)) & 0b111;
|
||||
if !cfg.variations.is_empty() {
|
||||
let variation = seed as usize % cfg.variations.len();
|
||||
// try to make the variation more uniform as the PRNG is highly unfair
|
||||
let variation = match cfg.variations.len() {
|
||||
1 => 0,
|
||||
2 => (seed as usize % 4) / 3,
|
||||
3 => (seed as usize % 5) / 2,
|
||||
// for four use a different seed than for ori to not have them match always
|
||||
4 => (((seed.overflowing_add(wpos.x as u64).0) as usize % 7) + 1) / 2,
|
||||
_ => seed as usize % cfg.variations.len(),
|
||||
};
|
||||
let key = (sprite, variation);
|
||||
|
||||
// NOTE: Safe because we called sprite_config_for already.
|
||||
|
@ -305,7 +305,7 @@ impl<'a> Canvas<'a> {
|
||||
}
|
||||
});
|
||||
for (pos, spec) in entities.drain(..) {
|
||||
self.spawn(EntityInfo::at(pos).with_asset_expect(&spec, &mut rng));
|
||||
self.spawn(EntityInfo::at(pos).with_asset_expect(&spec, &mut rng, None));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
astar::Astar,
|
||||
calendar::Calendar,
|
||||
path::Path,
|
||||
spiral::Spiral2d,
|
||||
store::{Id, Store},
|
||||
@ -236,6 +237,7 @@ impl Civs {
|
||||
seed: u32,
|
||||
sim: &mut WorldSim,
|
||||
index: &mut Index,
|
||||
calendar: Option<&Calendar>,
|
||||
report_stage: &dyn Fn(WorldCivStage),
|
||||
) -> Self {
|
||||
prof_span!("Civs::generate");
|
||||
@ -543,6 +545,7 @@ impl Civs {
|
||||
&mut rng,
|
||||
wpos,
|
||||
size,
|
||||
calendar,
|
||||
))
|
||||
},
|
||||
SiteKind::CliffTown => WorldSite::cliff_town(site2::Site::generate_cliff_town(
|
||||
|
@ -942,8 +942,11 @@ fn apply_entity_spawns<R: Rng>(canvas: &mut Canvas, wpos: Vec3<i32>, biome: &Bio
|
||||
.ok()
|
||||
.and_then(|s| s.0)
|
||||
{
|
||||
canvas
|
||||
.spawn(EntityInfo::at(wpos.map(|e| e as f32)).with_asset_expect(entity_asset, rng));
|
||||
canvas.spawn(EntityInfo::at(wpos.map(|e| e as f32)).with_asset_expect(
|
||||
entity_asset,
|
||||
rng,
|
||||
None,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -668,7 +668,7 @@ pub fn apply_caves_supplement<'a>(
|
||||
_ => "common.entity.wild.aggressive.cave_troll",
|
||||
}
|
||||
};
|
||||
entity.with_asset_expect(asset, dynamic_rng)
|
||||
entity.with_asset_expect(asset, dynamic_rng, None)
|
||||
};
|
||||
|
||||
supplement.add_entity(entity);
|
||||
|
@ -618,7 +618,7 @@ pub fn apply_spots_to(canvas: &mut Canvas, _dynamic_rng: &mut impl Rng) {
|
||||
{
|
||||
canvas.spawn(
|
||||
EntityInfo::at(wpos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0))
|
||||
.with_asset_expect(spec, &mut rng),
|
||||
.with_asset_expect(spec, &mut rng, None),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ impl Pack {
|
||||
.groups
|
||||
.choose_weighted(dynamic_rng, |(p, _group)| *p)
|
||||
.expect("Failed to choose group");
|
||||
let entity = EntityInfo::at(pos).with_asset_expect(entity_asset, dynamic_rng);
|
||||
let entity = EntityInfo::at(pos).with_asset_expect(entity_asset, dynamic_rng, None);
|
||||
let group_size = dynamic_rng.gen_range(*from..=*to);
|
||||
|
||||
(entity, group_size)
|
||||
@ -665,7 +665,8 @@ mod tests {
|
||||
let (_, (_, _, asset)) = group;
|
||||
let dummy_pos = Vec3::new(0.0, 0.0, 0.0);
|
||||
let mut dummy_rng = thread_rng();
|
||||
let entity = EntityInfo::at(dummy_pos).with_asset_expect(asset, &mut dummy_rng);
|
||||
let entity =
|
||||
EntityInfo::at(dummy_pos).with_asset_expect(asset, &mut dummy_rng, None);
|
||||
drop(entity);
|
||||
}
|
||||
}
|
||||
|
@ -128,14 +128,16 @@ impl World {
|
||||
// is broken.
|
||||
threadpool.install(|| {
|
||||
let mut index = Index::new(seed);
|
||||
let calendar = opts.calendar.clone();
|
||||
|
||||
let mut sim = sim::WorldSim::generate(seed, opts, threadpool, &|stage| {
|
||||
report_stage(WorldGenerateStage::WorldSimGenerate(stage))
|
||||
});
|
||||
|
||||
let civs = civ::Civs::generate(seed, &mut sim, &mut index, &|stage| {
|
||||
report_stage(WorldGenerateStage::WorldCivGenerate(stage))
|
||||
});
|
||||
let civs =
|
||||
civ::Civs::generate(seed, &mut sim, &mut index, calendar.as_ref(), &|stage| {
|
||||
report_stage(WorldGenerateStage::WorldCivGenerate(stage))
|
||||
});
|
||||
|
||||
report_stage(WorldGenerateStage::EconomySimulation);
|
||||
sim2::simulate(&mut index, &mut sim);
|
||||
@ -542,6 +544,7 @@ impl World {
|
||||
sample_get,
|
||||
&mut supplement,
|
||||
site.id(),
|
||||
time.as_ref(),
|
||||
)
|
||||
});
|
||||
|
||||
|
@ -345,7 +345,7 @@ mod tests {
|
||||
info!("Index created");
|
||||
let mut sim = sim::WorldSim::generate(seed, opts, &threadpool, &|_| {});
|
||||
info!("World loaded");
|
||||
let _civs = crate::civ::Civs::generate(seed, &mut sim, &mut index, &|_| {});
|
||||
let _civs = crate::civ::Civs::generate(seed, &mut sim, &mut index, None, &|_| {});
|
||||
info!("Civs created");
|
||||
crate::sim2::simulate(&mut index, &mut sim);
|
||||
show_economy(&index.sites, &None);
|
||||
@ -374,7 +374,7 @@ mod tests {
|
||||
let mut names = None;
|
||||
let regenerate_input = false;
|
||||
if regenerate_input {
|
||||
let _civs = crate::civ::Civs::generate(seed, &mut sim, &mut index, &|_| {});
|
||||
let _civs = crate::civ::Civs::generate(seed, &mut sim, &mut index, None, &|_| {});
|
||||
info!("Civs created");
|
||||
let mut outarr: Vec<EconomySetup> = Vec::new();
|
||||
for i in index.sites.values() {
|
||||
|
@ -13,7 +13,7 @@ pub use self::{
|
||||
pub use common::terrain::site::{DungeonKindMeta, SettlementKindMeta, SiteKindMeta};
|
||||
|
||||
use crate::{column::ColumnSample, site2, Canvas};
|
||||
use common::generation::ChunkSupplement;
|
||||
use common::{calendar::Calendar, generation::ChunkSupplement, resources::TimeOfDay};
|
||||
use rand::Rng;
|
||||
use serde::Deserialize;
|
||||
use vek::*;
|
||||
@ -378,13 +378,14 @@ impl Site {
|
||||
get_column: impl FnMut(Vec2<i32>) -> Option<&'a ColumnSample<'a>>,
|
||||
supplement: &mut ChunkSupplement,
|
||||
site_id: common::trade::SiteId,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) {
|
||||
match &self.kind {
|
||||
SiteKind::Settlement(s) => {
|
||||
let economy = self
|
||||
.trade_information(site_id)
|
||||
.expect("Settlement has no economy");
|
||||
s.apply_supplement(dynamic_rng, wpos2d, get_column, supplement, economy)
|
||||
s.apply_supplement(dynamic_rng, wpos2d, get_column, supplement, economy, time)
|
||||
},
|
||||
SiteKind::Dungeon(d) => d.apply_supplement(dynamic_rng, wpos2d, supplement),
|
||||
SiteKind::Castle(c) => c.apply_supplement(dynamic_rng, wpos2d, get_column, supplement),
|
||||
|
@ -15,6 +15,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
astar::Astar,
|
||||
calendar::Calendar,
|
||||
comp::{
|
||||
self, agent, bird_medium,
|
||||
inventory::{
|
||||
@ -24,6 +25,7 @@ use common::{
|
||||
},
|
||||
generation::{ChunkSupplement, EntityInfo},
|
||||
path::Path,
|
||||
resources::TimeOfDay,
|
||||
spiral::Spiral2d,
|
||||
store::{Id, Store},
|
||||
terrain::{Block, BlockKind, SpriteKind, TerrainChunkSize},
|
||||
@ -853,6 +855,7 @@ impl Settlement {
|
||||
mut get_column: impl FnMut(Vec2<i32>) -> Option<&'a ColumnSample<'a>>,
|
||||
supplement: &mut ChunkSupplement,
|
||||
economy: SiteInformation,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) {
|
||||
// let economy: HashMap<Good, (f32, f32)> = SiteInformation::economy
|
||||
// .values
|
||||
@ -893,12 +896,12 @@ impl Settlement {
|
||||
let entity = if is_dummy {
|
||||
EntityInfo::at(entity_wpos)
|
||||
.with_agency(false)
|
||||
.with_asset_expect("common.entity.village.dummy", dynamic_rng)
|
||||
.with_asset_expect("common.entity.village.dummy", dynamic_rng, time)
|
||||
} else {
|
||||
match dynamic_rng.gen_range(0..=4) {
|
||||
0 => barnyard(entity_wpos, dynamic_rng),
|
||||
1 => bird(entity_wpos, dynamic_rng),
|
||||
_ => humanoid(entity_wpos, &economy, dynamic_rng),
|
||||
_ => humanoid(entity_wpos, &economy, dynamic_rng, time),
|
||||
}
|
||||
};
|
||||
|
||||
@ -993,27 +996,37 @@ fn bird(pos: Vec3<f32>, dynamic_rng: &mut impl Rng) -> EntityInfo {
|
||||
.with_automatic_name(None)
|
||||
}
|
||||
|
||||
fn humanoid(pos: Vec3<f32>, economy: &SiteInformation, dynamic_rng: &mut impl Rng) -> EntityInfo {
|
||||
fn humanoid(
|
||||
pos: Vec3<f32>,
|
||||
economy: &SiteInformation,
|
||||
dynamic_rng: &mut impl Rng,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> EntityInfo {
|
||||
let entity = EntityInfo::at(pos);
|
||||
match dynamic_rng.gen_range(0..8) {
|
||||
0 | 1 => entity
|
||||
.with_agent_mark(agent::Mark::Guard)
|
||||
.with_asset_expect("common.entity.village.guard", dynamic_rng),
|
||||
.with_asset_expect("common.entity.village.guard", dynamic_rng, time),
|
||||
2 => entity
|
||||
.with_agent_mark(agent::Mark::Merchant)
|
||||
.with_economy(economy)
|
||||
.with_lazy_loadout(merchant_loadout)
|
||||
.with_asset_expect("common.entity.village.merchant", dynamic_rng),
|
||||
_ => entity.with_asset_expect("common.entity.village.villager", dynamic_rng),
|
||||
.with_asset_expect("common.entity.village.merchant", dynamic_rng, time),
|
||||
_ => entity.with_asset_expect("common.entity.village.villager", dynamic_rng, time),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn merchant_loadout(
|
||||
loadout_builder: LoadoutBuilder,
|
||||
economy: Option<&SiteInformation>,
|
||||
time: Option<&(TimeOfDay, Calendar)>,
|
||||
) -> LoadoutBuilder {
|
||||
trader_loadout(
|
||||
loadout_builder.with_asset_expect("common.loadout.village.merchant", &mut thread_rng()),
|
||||
loadout_builder.with_asset_expect(
|
||||
"common.loadout.village.merchant",
|
||||
&mut thread_rng(),
|
||||
time,
|
||||
),
|
||||
economy,
|
||||
|_| true,
|
||||
)
|
||||
|
@ -44,6 +44,7 @@ impl Tree {
|
||||
|
||||
pub fn render(&self, canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
|
||||
let nz = FastNoise::new(self.seed);
|
||||
let calendar = None;
|
||||
|
||||
canvas.foreach_col(|canvas, wpos2d, col| {
|
||||
let rpos2d = wpos2d - self.origin;
|
||||
@ -81,6 +82,7 @@ impl Tree {
|
||||
_ => "common.entity.wild.aggressive.maneater",
|
||||
},
|
||||
dynamic_rng,
|
||||
calendar,
|
||||
),
|
||||
);
|
||||
} else if above && dynamic_rng.gen_bool(0.0001) {
|
||||
@ -89,6 +91,7 @@ impl Tree {
|
||||
.with_asset_expect(
|
||||
"common.entity.wild.aggressive.swamp_troll",
|
||||
dynamic_rng,
|
||||
calendar,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
astar::Astar,
|
||||
calendar::Calendar,
|
||||
comp::Alignment,
|
||||
generation::EntityInfo,
|
||||
lottery::Lottery,
|
||||
@ -579,6 +580,7 @@ impl Site {
|
||||
rng: &mut impl Rng,
|
||||
origin: Vec2<i32>,
|
||||
size: f32,
|
||||
calendar: Option<&Calendar>,
|
||||
) -> Self {
|
||||
let mut rng = reseed(rng);
|
||||
|
||||
@ -664,6 +666,7 @@ impl Site {
|
||||
door_tile,
|
||||
door_dir,
|
||||
aabr,
|
||||
calendar,
|
||||
);
|
||||
let house_alt = house.alt;
|
||||
let plot = site.create_plot(Plot {
|
||||
@ -1639,6 +1642,7 @@ impl Site {
|
||||
(-border..TILE_SIZE as i32 + border)
|
||||
.map(move |x| (twpos + Vec2::new(x, y), Vec2::new(x, y)))
|
||||
});
|
||||
let calendar = None;
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match &tile.kind {
|
||||
@ -1693,7 +1697,7 @@ impl Site {
|
||||
.unwrap();
|
||||
canvas.spawn(
|
||||
EntityInfo::at(Vec3::new(wpos2d.x, wpos2d.y, alt).as_())
|
||||
.with_asset_expect(spec, dynamic_rng)
|
||||
.with_asset_expect(spec, dynamic_rng, calendar)
|
||||
.with_alignment(Alignment::Tame),
|
||||
);
|
||||
}
|
||||
@ -2022,6 +2026,7 @@ pub fn test_site() -> Site {
|
||||
&mut thread_rng(),
|
||||
Vec2::zero(),
|
||||
0.5,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2290,18 +2290,27 @@ impl RibCageGenerator {
|
||||
}
|
||||
|
||||
fn adlet_hunter<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.adlet.hunter", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.adlet.hunter",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn adlet_icepicker<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.adlet.icepicker", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.adlet.icepicker",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn adlet_tracker<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.adlet.tracker", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.adlet.tracker",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn random_adlet<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
@ -2313,42 +2322,67 @@ fn random_adlet<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
}
|
||||
|
||||
fn adlet_elder<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.adlet.elder", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.adlet.elder",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn rat<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect("common.entity.wild.peaceful.rat", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.wild.peaceful.rat",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn wolf<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.wild.aggressive.wolf", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.wild.aggressive.wolf",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn bear<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.wild.aggressive.bear", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.wild.aggressive.bear",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn frostfang<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.wild.aggressive.frostfang", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.wild.aggressive.frostfang",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn roshwalr<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.wild.aggressive.roshwalr", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.wild.aggressive.roshwalr",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn icedrake<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.wild.aggressive.icedrake", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.wild.aggressive.icedrake",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn tursus<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.wild.aggressive.tursus", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.wild.aggressive.tursus",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn random_yetipit_mob<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
@ -2361,7 +2395,11 @@ fn random_yetipit_mob<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
}
|
||||
|
||||
fn yeti<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect("common.entity.dungeon.adlet.yeti", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.adlet.yeti",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -511,8 +511,11 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
||||
let mut rng = thread_rng();
|
||||
if rng.gen_bool(0.1) {
|
||||
painter.spawn(
|
||||
EntityInfo::at(c.with_z(bridge.center.z).as_())
|
||||
.with_asset_expect("common.entity.wild.aggressive.swamp_troll", &mut rng),
|
||||
EntityInfo::at(c.with_z(bridge.center.z).as_()).with_asset_expect(
|
||||
"common.entity.wild.aggressive.swamp_troll",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -88,8 +88,11 @@ impl Structure for Camp {
|
||||
CampType::Pirate => {
|
||||
for p in 0..npc_rng {
|
||||
painter.spawn(
|
||||
EntityInfo::at((center + p).with_z(base + 2).as_())
|
||||
.with_asset_expect("common.entity.spot.pirate", &mut thread_rng),
|
||||
EntityInfo::at((center + p).with_z(base + 2).as_()).with_asset_expect(
|
||||
"common.entity.spot.pirate",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
let pet = if npc_rng < 3 {
|
||||
@ -98,21 +101,30 @@ impl Structure for Camp {
|
||||
"common.entity.wild.peaceful.rat"
|
||||
};
|
||||
painter.spawn(
|
||||
EntityInfo::at(center.with_z(base + 2).as_())
|
||||
.with_asset_expect(pet, &mut thread_rng),
|
||||
EntityInfo::at(center.with_z(base + 2).as_()).with_asset_expect(
|
||||
pet,
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
},
|
||||
_ => {
|
||||
if npc_rng > 2 {
|
||||
painter.spawn(
|
||||
EntityInfo::at((center - 1).with_z(base + 2).as_())
|
||||
.with_asset_expect("common.entity.village.bowman", &mut thread_rng),
|
||||
EntityInfo::at((center - 1).with_z(base + 2).as_()).with_asset_expect(
|
||||
"common.entity.village.bowman",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
if npc_rng < 4 {
|
||||
painter.spawn(
|
||||
EntityInfo::at((center + 1).with_z(base + 2).as_())
|
||||
.with_asset_expect("common.entity.village.skinner", &mut thread_rng),
|
||||
EntityInfo::at((center + 1).with_z(base + 2).as_()).with_asset_expect(
|
||||
"common.entity.village.skinner",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
@ -704,9 +704,19 @@ fn enemy_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInf
|
||||
// TODO: give enemies health skills?
|
||||
let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32));
|
||||
match dynamic_rng.gen_range(0..=4) {
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.sahagin.sniper", dynamic_rng),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.sahagin.sorcerer", dynamic_rng),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.sahagin.spearman", dynamic_rng),
|
||||
0 => {
|
||||
entity.with_asset_expect("common.entity.dungeon.sahagin.sniper", dynamic_rng, None)
|
||||
},
|
||||
1 => entity.with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.sorcerer",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
_ => entity.with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.spearman",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
}
|
||||
});
|
||||
|
||||
@ -720,9 +730,11 @@ fn enemy_3(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInf
|
||||
// TODO: give enemies health skills?
|
||||
let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32));
|
||||
match dynamic_rng.gen_range(0..=4) {
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.haniwa.archer", dynamic_rng),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.haniwa.soldier", dynamic_rng),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.haniwa.guard", dynamic_rng),
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.haniwa.archer", dynamic_rng, None),
|
||||
1 => {
|
||||
entity.with_asset_expect("common.entity.dungeon.haniwa.soldier", dynamic_rng, None)
|
||||
},
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.haniwa.guard", dynamic_rng, None),
|
||||
}
|
||||
});
|
||||
|
||||
@ -736,9 +748,21 @@ fn enemy_4(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInf
|
||||
// TODO: give enemies health skills?
|
||||
let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32));
|
||||
match dynamic_rng.gen_range(0..=4) {
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.myrmidon.marksman", dynamic_rng),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.myrmidon.strategian", dynamic_rng),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.myrmidon.hoplite", dynamic_rng),
|
||||
0 => entity.with_asset_expect(
|
||||
"common.entity.dungeon.myrmidon.marksman",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
1 => entity.with_asset_expect(
|
||||
"common.entity.dungeon.myrmidon.strategian",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
_ => entity.with_asset_expect(
|
||||
"common.entity.dungeon.myrmidon.hoplite",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
}
|
||||
});
|
||||
|
||||
@ -752,9 +776,15 @@ fn enemy_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInf
|
||||
// TODO: give enemies health skills?
|
||||
let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32));
|
||||
match dynamic_rng.gen_range(0..=4) {
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.cultist.warlock", dynamic_rng),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.cultist.warlord", dynamic_rng),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.cultist.cultist", dynamic_rng),
|
||||
0 => {
|
||||
entity.with_asset_expect("common.entity.dungeon.cultist.warlock", dynamic_rng, None)
|
||||
},
|
||||
1 => {
|
||||
entity.with_asset_expect("common.entity.dungeon.cultist.warlord", dynamic_rng, None)
|
||||
},
|
||||
_ => {
|
||||
entity.with_asset_expect("common.entity.dungeon.cultist.cultist", dynamic_rng, None)
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
@ -766,31 +796,37 @@ fn enemy_fallback(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<En
|
||||
let mut entities = Vec::new();
|
||||
entities.resize_with(number, || {
|
||||
let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32));
|
||||
entity.with_asset_expect("common.entity.dungeon.fallback.enemy", dynamic_rng)
|
||||
entity.with_asset_expect("common.entity.dungeon.fallback.enemy", dynamic_rng, None)
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn turret_3(dynamic_rng: &mut impl Rng, pos: Vec3<f32>) -> EntityInfo {
|
||||
EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.haniwa.sentry", dynamic_rng)
|
||||
EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.haniwa.sentry", dynamic_rng, None)
|
||||
}
|
||||
|
||||
fn turret_5(dynamic_rng: &mut impl Rng, pos: Vec3<f32>) -> EntityInfo {
|
||||
EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.cultist.turret", dynamic_rng)
|
||||
EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.cultist.turret", dynamic_rng, None)
|
||||
}
|
||||
|
||||
fn boss_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.sahagin.tidalwarrior", dynamic_rng),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.tidalwarrior",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
]
|
||||
}
|
||||
fn boss_3(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
let mut entities = Vec::new();
|
||||
entities.resize_with(2, || {
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.haniwa.claygolem", dynamic_rng)
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.haniwa.claygolem",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)
|
||||
});
|
||||
|
||||
entities
|
||||
@ -798,30 +834,42 @@ fn boss_3(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo
|
||||
|
||||
fn boss_4(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.myrmidon.minotaur", dynamic_rng),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.myrmidon.minotaur",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
fn boss_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.cultist.mindflayer", dynamic_rng),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.cultist.mindflayer",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
fn boss_fallback(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.fallback.boss", dynamic_rng),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.fallback.boss",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
fn mini_boss_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
let mut entities = Vec::new();
|
||||
entities.resize_with(6, || {
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.sahagin.hakulaq", dynamic_rng)
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.hakulaq",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)
|
||||
});
|
||||
entities
|
||||
}
|
||||
@ -829,16 +877,22 @@ fn mini_boss_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<Entit
|
||||
fn mini_boss_3(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
let mut entities = Vec::new();
|
||||
entities.resize_with(3, || {
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.haniwa.bonerattler", dynamic_rng)
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.haniwa.bonerattler",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)
|
||||
});
|
||||
entities
|
||||
}
|
||||
|
||||
fn mini_boss_4(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.myrmidon.cyclops", dynamic_rng),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.myrmidon.cyclops",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
@ -847,24 +901,36 @@ fn mini_boss_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<Entit
|
||||
match dynamic_rng.gen_range(0..=2) {
|
||||
0 => {
|
||||
entities.push(
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.cultist.beastmaster", dynamic_rng),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.cultist.beastmaster",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
entities.resize_with(entities.len() + 4, || {
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.cultist.hound", dynamic_rng)
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.cultist.hound",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)
|
||||
});
|
||||
},
|
||||
1 => {
|
||||
entities.resize_with(2, || {
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.cultist.husk_brute", dynamic_rng)
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.cultist.husk_brute",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)
|
||||
});
|
||||
},
|
||||
_ => {
|
||||
entities.resize_with(10, || {
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.cultist.husk", dynamic_rng)
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.cultist.husk",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -873,8 +939,11 @@ fn mini_boss_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<Entit
|
||||
|
||||
fn mini_boss_fallback(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_asset_expect("common.entity.dungeon.fallback.miniboss", dynamic_rng),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.fallback.miniboss",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -637,7 +637,7 @@ fn spawn_entity(pos: Vec3<f32>, painter: &Painter, entity_path: &str) {
|
||||
let mut rng = thread_rng();
|
||||
painter.spawn(
|
||||
EntityInfo::at(pos)
|
||||
.with_asset_expect(entity_path, &mut rng)
|
||||
.with_asset_expect(entity_path, &mut rng, None)
|
||||
.with_no_flee(),
|
||||
);
|
||||
}
|
||||
@ -668,7 +668,7 @@ fn spawn_entities(
|
||||
|
||||
let spawn_pos = pos + Vec3::new(x_offset, y_offset, 0.0);
|
||||
|
||||
painter.spawn(EntityInfo::at(spawn_pos).with_asset_expect(entity_path, &mut rng));
|
||||
painter.spawn(EntityInfo::at(spawn_pos).with_asset_expect(entity_path, &mut rng, None));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,27 +49,31 @@ impl GiantTree {
|
||||
if above_block.kind() == BlockKind::Leaves && dynamic_rng.gen_bool(0.001) {
|
||||
let entity = EntityInfo::at(pos.as_());
|
||||
match dynamic_rng.gen_range(0..=4) {
|
||||
0 => {
|
||||
Some(entity.with_asset_expect(
|
||||
"common.entity.wild.aggressive.horn_beetle",
|
||||
dynamic_rng,
|
||||
))
|
||||
},
|
||||
1 => {
|
||||
Some(entity.with_asset_expect(
|
||||
"common.entity.wild.aggressive.stag_beetle",
|
||||
dynamic_rng,
|
||||
))
|
||||
},
|
||||
2 => Some(
|
||||
entity.with_asset_expect("common.entity.wild.aggressive.deadwood", dynamic_rng),
|
||||
),
|
||||
3 => Some(
|
||||
entity.with_asset_expect("common.entity.wild.aggressive.maneater", dynamic_rng),
|
||||
),
|
||||
4 => Some(
|
||||
entity.with_asset_expect("common.entity.wild.peaceful.parrot", dynamic_rng),
|
||||
),
|
||||
0 => Some(entity.with_asset_expect(
|
||||
"common.entity.wild.aggressive.horn_beetle",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)),
|
||||
1 => Some(entity.with_asset_expect(
|
||||
"common.entity.wild.aggressive.stag_beetle",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)),
|
||||
2 => Some(entity.with_asset_expect(
|
||||
"common.entity.wild.aggressive.deadwood",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)),
|
||||
3 => Some(entity.with_asset_expect(
|
||||
"common.entity.wild.aggressive.maneater",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)),
|
||||
4 => Some(entity.with_asset_expect(
|
||||
"common.entity.wild.peaceful.parrot",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
|
@ -1874,18 +1874,27 @@ impl Structure for GnarlingFortification {
|
||||
}
|
||||
|
||||
fn gnarling_mugger<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.gnarling.mugger", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.gnarling.mugger",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn gnarling_stalker<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.gnarling.stalker", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.gnarling.stalker",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn gnarling_logger<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.gnarling.logger", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.gnarling.logger",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn random_gnarling<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
@ -1898,28 +1907,40 @@ fn random_gnarling<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
|
||||
fn gnarling_chieftain<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.gnarling.chieftain", rng)
|
||||
.with_asset_expect("common.entity.dungeon.gnarling.chieftain", rng, None)
|
||||
.with_no_flee()
|
||||
}
|
||||
|
||||
fn deadwood<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.wild.aggressive.deadwood", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.wild.aggressive.deadwood",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn mandragora<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.gnarling.mandragora", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.gnarling.mandragora",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn wood_golem<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.gnarling.woodgolem", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.gnarling.woodgolem",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn harvester_boss<R: Rng>(pos: Vec3<i32>, rng: &mut R) -> EntityInfo {
|
||||
EntityInfo::at(pos.map(|x| x as f32))
|
||||
.with_asset_expect("common.entity.dungeon.gnarling.harvester", rng)
|
||||
EntityInfo::at(pos.map(|x| x as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.gnarling.harvester",
|
||||
rng,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -4,7 +4,10 @@ use crate::{
|
||||
util::{RandomField, Sampler, DIRS},
|
||||
Land,
|
||||
};
|
||||
use common::terrain::{Block, BlockKind, SpriteKind};
|
||||
use common::{
|
||||
calendar::{Calendar, CalendarEvent},
|
||||
terrain::{Block, BlockKind, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use vek::*;
|
||||
|
||||
@ -25,6 +28,7 @@ pub struct House {
|
||||
/// Color of the roof
|
||||
roof_color: Rgb<u8>,
|
||||
front: u8,
|
||||
christmas_decorations: bool,
|
||||
}
|
||||
|
||||
impl House {
|
||||
@ -35,6 +39,7 @@ impl House {
|
||||
door_tile: Vec2<i32>,
|
||||
door_dir: Vec2<i32>,
|
||||
tile_aabr: Aabr<i32>,
|
||||
calendar: Option<&Calendar>,
|
||||
) -> Self {
|
||||
let levels = rng.gen_range(1..2 + (tile_aabr.max - tile_aabr.min).product() / 6) as u32;
|
||||
let door_tile_pos = site.tile_center_wpos(door_tile);
|
||||
@ -52,6 +57,8 @@ impl House {
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let christmas_decorations =
|
||||
calendar.map_or(false, |c| c.is_event(CalendarEvent::Christmas));
|
||||
|
||||
Self {
|
||||
door_tile: door_tile_pos,
|
||||
@ -83,6 +90,7 @@ impl House {
|
||||
*colors.choose(rng).unwrap_or(&Rgb::new(21, 43, 48))
|
||||
},
|
||||
front,
|
||||
christmas_decorations,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2041,6 +2049,52 @@ impl Structure for House {
|
||||
painter.prim(Primitive::Aabb(fire_embers)),
|
||||
Fill::Block(Block::air(SpriteKind::Ember)),
|
||||
);
|
||||
if self.christmas_decorations {
|
||||
let (wreath_pos, wreath_ori) = match self.front {
|
||||
0 => (
|
||||
Aabb {
|
||||
min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 3)
|
||||
.with_z(alt + 2),
|
||||
max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 4)
|
||||
.with_z(alt + 3),
|
||||
},
|
||||
4,
|
||||
),
|
||||
1 => (
|
||||
Aabb {
|
||||
min: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 1)
|
||||
.with_z(alt + 2),
|
||||
max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 2)
|
||||
.with_z(alt + 3),
|
||||
},
|
||||
2,
|
||||
),
|
||||
2 => (
|
||||
Aabb {
|
||||
min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y - 1)
|
||||
.with_z(alt + 2),
|
||||
max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y).with_z(alt + 3),
|
||||
},
|
||||
0,
|
||||
),
|
||||
_ => (
|
||||
Aabb {
|
||||
min: Vec2::new(fireplace_origin.x - 1, fireplace_origin.y + 1)
|
||||
.with_z(alt + 2),
|
||||
max: Vec2::new(fireplace_origin.x, fireplace_origin.y + 2).with_z(alt + 3),
|
||||
},
|
||||
6,
|
||||
),
|
||||
};
|
||||
painter.fill(
|
||||
painter.prim(Primitive::Aabb(wreath_pos)),
|
||||
Fill::Block(
|
||||
Block::air(SpriteKind::ChristmasWreath)
|
||||
.with_ori(wreath_ori)
|
||||
.unwrap(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Door
|
||||
// Fill around the door with wall
|
||||
@ -2170,5 +2224,56 @@ impl Structure for House {
|
||||
painter.prim(Primitive::Aabb(door2)),
|
||||
Fill::Block(Block::air(SpriteKind::Door).with_ori(door2_ori).unwrap()),
|
||||
);
|
||||
if self.christmas_decorations {
|
||||
// we need to randomize position to see both variants
|
||||
let rng = RandomField::new(0).get(self.door_tile.with_z(alt + 3));
|
||||
let right = (rng % 2) as i32;
|
||||
let (door_light_pos, door_light_ori) = match self.front {
|
||||
0 => (
|
||||
Aabb {
|
||||
min: Vec2::new(self.door_tile.x + right, self.bounds.max.y + 1)
|
||||
.with_z(alt + 3),
|
||||
max: Vec2::new(self.door_tile.x + 1 + right, self.bounds.max.y + 2)
|
||||
.with_z(alt + 4),
|
||||
},
|
||||
4,
|
||||
),
|
||||
1 => (
|
||||
Aabb {
|
||||
min: Vec2::new(self.bounds.max.x + 1, self.door_tile.y + right)
|
||||
.with_z(alt + 3),
|
||||
max: Vec2::new(self.bounds.max.x + 2, self.door_tile.y + 1 + right)
|
||||
.with_z(alt + 4),
|
||||
},
|
||||
2,
|
||||
),
|
||||
2 => (
|
||||
Aabb {
|
||||
min: Vec2::new(self.door_tile.x + right, self.bounds.min.y - 1)
|
||||
.with_z(alt + 3),
|
||||
max: Vec2::new(self.door_tile.x + 1 + right, self.bounds.min.y)
|
||||
.with_z(alt + 4),
|
||||
},
|
||||
0,
|
||||
),
|
||||
_ => (
|
||||
Aabb {
|
||||
min: Vec2::new(self.bounds.min.x - 1, self.door_tile.y + right)
|
||||
.with_z(alt + 3),
|
||||
max: Vec2::new(self.bounds.min.x, self.door_tile.y + 1 + right)
|
||||
.with_z(alt + 4),
|
||||
},
|
||||
6,
|
||||
),
|
||||
};
|
||||
painter.fill(
|
||||
painter.prim(Primitive::Aabb(door_light_pos)),
|
||||
Fill::Block(
|
||||
Block::air(SpriteKind::ChristmasOrnament)
|
||||
.with_ori(door_light_ori)
|
||||
.unwrap(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,17 +240,24 @@ impl Structure for JungleRuin {
|
||||
EntityInfo::at(npc_pos.with_z(plot_base + 5).as_()).with_asset_expect(
|
||||
"common.entity.spot.dwarf_grave_robber",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
),
|
||||
// sauroks
|
||||
1 => painter.spawn(
|
||||
EntityInfo::at(npc_pos.with_z(plot_base + 5).as_())
|
||||
.with_asset_expect("common.entity.spot.saurok", &mut thread_rng),
|
||||
EntityInfo::at(npc_pos.with_z(plot_base + 5).as_()).with_asset_expect(
|
||||
"common.entity.spot.saurok",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
),
|
||||
// grim salvager
|
||||
2 => painter.spawn(
|
||||
EntityInfo::at(npc_pos.with_z(plot_base + 5).as_())
|
||||
.with_asset_expect("common.entity.spot.grim_salvager", &mut thread_rng),
|
||||
EntityInfo::at(npc_pos.with_z(plot_base + 5).as_()).with_asset_expect(
|
||||
"common.entity.spot.grim_salvager",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
),
|
||||
_ => {},
|
||||
}
|
||||
|
@ -68,18 +68,27 @@ impl Structure for PirateHideout {
|
||||
match RandomField::new(0).get(npc_pos.with_z(base)) % 10 {
|
||||
// rat
|
||||
0 => painter.spawn(
|
||||
EntityInfo::at(npc_pos.with_z(base).as_())
|
||||
.with_asset_expect("common.entity.wild.peaceful.rat", &mut thread_rng),
|
||||
EntityInfo::at(npc_pos.with_z(base).as_()).with_asset_expect(
|
||||
"common.entity.wild.peaceful.rat",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
),
|
||||
// parrot
|
||||
1 => painter.spawn(
|
||||
EntityInfo::at(npc_pos.with_z(base).as_())
|
||||
.with_asset_expect("common.entity.wild.peaceful.parrot", &mut thread_rng),
|
||||
EntityInfo::at(npc_pos.with_z(base).as_()).with_asset_expect(
|
||||
"common.entity.wild.peaceful.parrot",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
),
|
||||
// pirates
|
||||
_ => painter.spawn(
|
||||
EntityInfo::at(npc_pos.with_z(base).as_())
|
||||
.with_asset_expect("common.entity.spot.pirate", &mut thread_rng),
|
||||
EntityInfo::at(npc_pos.with_z(base).as_()).with_asset_expect(
|
||||
"common.entity.spot.pirate",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -57,8 +57,11 @@ impl Structure for RockCircle {
|
||||
if thread_rng.gen_range(0..=8) < 1 {
|
||||
// dullahan
|
||||
painter.spawn(
|
||||
EntityInfo::at(center.with_z(base + 2).as_())
|
||||
.with_asset_expect("common.entity.wild.aggressive.dullahan", &mut thread_rng),
|
||||
EntityInfo::at(center.with_z(base + 2).as_()).with_asset_expect(
|
||||
"common.entity.wild.aggressive.dullahan",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -611,10 +611,11 @@ impl Structure for SeaChapel {
|
||||
// cellar sea crocodiles
|
||||
let cellar_sea_croc_pos = (center - (diameter / 4)).with_z(base - (diameter / 2));
|
||||
for _ in 0..(3 + ((RandomField::new(0).get((cellar_sea_croc_pos).with_z(base))) % 5)) {
|
||||
painter.spawn(
|
||||
EntityInfo::at(cellar_sea_croc_pos.as_())
|
||||
.with_asset_expect("common.entity.wild.aggressive.sea_crocodile", &mut rng),
|
||||
)
|
||||
painter.spawn(EntityInfo::at(cellar_sea_croc_pos.as_()).with_asset_expect(
|
||||
"common.entity.wild.aggressive.sea_crocodile",
|
||||
&mut rng,
|
||||
None,
|
||||
))
|
||||
}
|
||||
// clear chapel main room
|
||||
painter
|
||||
@ -681,20 +682,29 @@ impl Structure for SeaChapel {
|
||||
// organ on chapel top floor organ podium
|
||||
let first_floor_organ_pos = center_o2.with_z(base - (diameter / 8) + diameter - 4);
|
||||
painter.spawn(
|
||||
EntityInfo::at(first_floor_organ_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.organ", &mut rng),
|
||||
EntityInfo::at(first_floor_organ_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.organ",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
// sea clerics, bishop on top floor
|
||||
let first_floor_spawn_pos = (center_o2 - 2).with_z(base - (diameter / 8) + diameter - 4);
|
||||
for _ in 0..(2 + ((RandomField::new(0).get((first_floor_spawn_pos).with_z(base))) % 2)) {
|
||||
painter.spawn(
|
||||
EntityInfo::at(first_floor_spawn_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.sea_cleric", &mut rng),
|
||||
EntityInfo::at(first_floor_spawn_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_cleric",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
painter.spawn(
|
||||
EntityInfo::at(first_floor_spawn_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.sea_bishop", &mut rng),
|
||||
EntityInfo::at(first_floor_spawn_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_bishop",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
// chapel main room gold decor ring and floor
|
||||
painter
|
||||
@ -739,26 +749,38 @@ impl Structure for SeaChapel {
|
||||
// organ on chapel main room organ podium
|
||||
let first_floor_organ_pos = center_o1.with_z(base + 2);
|
||||
painter.spawn(
|
||||
EntityInfo::at(first_floor_organ_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.organ", &mut rng),
|
||||
EntityInfo::at(first_floor_organ_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.organ",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
// sea clerics on main floor
|
||||
let main_room_sea_clerics_pos = (center_o1 - 2).with_z(base + 2);
|
||||
for _ in 0..(3 + ((RandomField::new(0).get((main_room_sea_clerics_pos).with_z(base))) % 3))
|
||||
{
|
||||
painter.spawn(
|
||||
EntityInfo::at(main_room_sea_clerics_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.sea_cleric", &mut rng),
|
||||
EntityInfo::at(main_room_sea_clerics_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_cleric",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
// coral golem on main floor
|
||||
painter.spawn(
|
||||
EntityInfo::at((first_floor_organ_pos + 2).as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.coralgolem", &mut rng),
|
||||
EntityInfo::at((first_floor_organ_pos + 2).as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.coralgolem",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
painter.spawn(
|
||||
EntityInfo::at((first_floor_organ_pos + 4).as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.sea_bishop", &mut rng),
|
||||
EntityInfo::at((first_floor_organ_pos + 4).as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_bishop",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
// chapel main room glassbarrier to cellar
|
||||
let center_g = center - diameter / 7;
|
||||
@ -833,17 +855,19 @@ impl Structure for SeaChapel {
|
||||
// cardinals room sea clerics
|
||||
let cr_sea_clerics_pos = (center - (diameter / 5)).with_z(base - (diameter / 4) - 3);
|
||||
for _ in 0..(2 + ((RandomField::new(0).get((cr_sea_clerics_pos).with_z(base))) % 3)) {
|
||||
painter.spawn(
|
||||
EntityInfo::at(cr_sea_clerics_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.sea_cleric", &mut rng),
|
||||
)
|
||||
painter.spawn(EntityInfo::at(cr_sea_clerics_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_cleric",
|
||||
&mut rng,
|
||||
None,
|
||||
))
|
||||
}
|
||||
// Cardinal
|
||||
let cr_cardinal_pos = (center - (diameter / 6)).with_z(base - (diameter / 4) - 3);
|
||||
painter.spawn(
|
||||
EntityInfo::at(cr_cardinal_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.cardinal", &mut rng),
|
||||
);
|
||||
painter.spawn(EntityInfo::at(cr_cardinal_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.cardinal",
|
||||
&mut rng,
|
||||
None,
|
||||
));
|
||||
// glassbarrier to water basin
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
@ -1394,6 +1418,7 @@ impl Structure for SeaChapel {
|
||||
painter.spawn(EntityInfo::at(room_clerics_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_cleric",
|
||||
&mut rng,
|
||||
None,
|
||||
));
|
||||
};
|
||||
// decor for top rooms
|
||||
@ -1668,8 +1693,11 @@ impl Structure for SeaChapel {
|
||||
let underwater_organ_pos =
|
||||
(center - (diameter / 4)).with_z(base - (3 * diameter) + (diameter / 2) + 1);
|
||||
painter.spawn(
|
||||
EntityInfo::at(underwater_organ_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.organ", &mut rng),
|
||||
EntityInfo::at(underwater_organ_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.organ",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
// underwater chamber decor ring
|
||||
painter
|
||||
@ -1724,10 +1752,11 @@ impl Structure for SeaChapel {
|
||||
.fill(gold_chain);
|
||||
// underwater chamber dagon
|
||||
let cellar_miniboss_pos = (center + 6).with_z(base - (3 * diameter) + (diameter / 2) + 1);
|
||||
painter.spawn(
|
||||
EntityInfo::at(cellar_miniboss_pos.as_())
|
||||
.with_asset_expect("common.entity.dungeon.sea_chapel.dagon", &mut rng),
|
||||
);
|
||||
painter.spawn(EntityInfo::at(cellar_miniboss_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.dagon",
|
||||
&mut rng,
|
||||
None,
|
||||
));
|
||||
// underwater chamber floor entry
|
||||
painter
|
||||
.cylinder_with_radius(
|
||||
@ -2764,8 +2793,11 @@ impl Structure for SeaChapel {
|
||||
0..(2 + ((RandomField::new(0).get((bldg_cellar_sea_croc_pos).with_z(base))) % 2))
|
||||
{
|
||||
painter.spawn(
|
||||
EntityInfo::at(bldg_cellar_sea_croc_pos.as_())
|
||||
.with_asset_expect("common.entity.wild.aggressive.sea_crocodile", &mut rng),
|
||||
EntityInfo::at(bldg_cellar_sea_croc_pos.as_()).with_asset_expect(
|
||||
"common.entity.wild.aggressive.sea_crocodile",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
match bldg_variant {
|
||||
@ -2821,6 +2853,7 @@ impl Structure for SeaChapel {
|
||||
EntityInfo::at(bldg_floor_sea_cleric_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_cleric",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -2962,6 +2995,7 @@ impl Structure for SeaChapel {
|
||||
EntityInfo::at(bldg_floor_sea_cleric_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_cleric",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -2974,6 +3008,7 @@ impl Structure for SeaChapel {
|
||||
EntityInfo::at(bldg_floor3_sea_cleric_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.sea_cleric",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -3319,6 +3354,7 @@ impl Structure for SeaChapel {
|
||||
EntityInfo::at(prisoner_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sea_chapel.prisoner",
|
||||
&mut rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -73,13 +73,19 @@ impl Structure for TrollCave {
|
||||
|
||||
// troll
|
||||
painter.spawn(
|
||||
EntityInfo::at(center.with_z(base - 15).as_())
|
||||
.with_asset_expect(troll, &mut thread_rng),
|
||||
EntityInfo::at(center.with_z(base - 15).as_()).with_asset_expect(
|
||||
troll,
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
// bat
|
||||
painter.spawn(
|
||||
EntityInfo::at((center - 2).with_z(base + 5).as_())
|
||||
.with_asset_expect("common.entity.wild.aggressive.bat", &mut thread_rng),
|
||||
EntityInfo::at((center - 2).with_z(base + 5).as_()).with_asset_expect(
|
||||
"common.entity.wild.aggressive.bat",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user