Fmt and clippy lints fixes

This commit is contained in:
Joshua Barretto 2020-08-12 15:10:12 +01:00
parent 331a61e426
commit a8b0a678d8
27 changed files with 352 additions and 255 deletions

View File

@ -150,7 +150,7 @@ impl Client {
recipe_book, recipe_book,
} => { } => {
// TODO: Display that versions don't match in Voxygen // TODO: Display that versions don't match in Voxygen
if &server_info.git_hash != *common::util::GIT_HASH { if server_info.git_hash != *common::util::GIT_HASH {
warn!( warn!(
"Server is running {}[{}], you are running {}[{}], versions \ "Server is running {}[{}], you are running {}[{}], versions \
might be incompatible!", might be incompatible!",

View File

@ -1,4 +1,4 @@
use crate::{path::Chaser, sync::Uid, comp::Body}; use crate::{comp::Body, path::Chaser, sync::Uid};
use specs::{Component, Entity as EcsEntity}; use specs::{Component, Entity as EcsEntity};
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
use vek::*; use vek::*;

View File

@ -7,8 +7,8 @@ pub use tool::{Hands, Tool, ToolCategory, ToolKind};
use crate::{ use crate::{
assets::{self, Asset}, assets::{self, Asset},
effect::Effect, effect::Effect,
terrain::{Block, BlockKind},
lottery::Lottery, lottery::Lottery,
terrain::{Block, BlockKind},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{Component, FlaggedStorage}; use specs::{Component, FlaggedStorage};

View File

@ -503,7 +503,7 @@ impl Inventory {
} }
} }
if missing.len() == 0 { if missing.is_empty() {
Ok(slot_claims) Ok(slot_claims)
} else { } else {
Err(missing) Err(missing)

View File

@ -1,6 +1,6 @@
use crate::assets::{self, Asset}; use crate::assets::{self, Asset};
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize, de::DeserializeOwned}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{fs::File, io::BufReader}; use std::{fs::File, io::BufReader};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -40,9 +40,7 @@ impl<T> Lottery<T> {
.1 .1
} }
pub fn choose(&self) -> &T { pub fn choose(&self) -> &T { self.choose_seeded(thread_rng().gen()) }
self.choose_seeded(thread_rng().gen())
}
pub fn iter(&self) -> impl Iterator<Item = &(f32, T)> { self.items.iter() } pub fn iter(&self) -> impl Iterator<Item = &(f32, T)> { self.items.iter() }
} }

View File

@ -100,9 +100,7 @@ impl Route {
{ {
let (next0, next1, next_tgt, be_precise) = loop { let (next0, next1, next_tgt, be_precise) = loop {
// If we've reached the end of the path, stop // If we've reached the end of the path, stop
if self.next(0).is_none() { self.next(0)?;
return None;
}
let next0 = self let next0 = self
.next(0) .next(0)
@ -115,10 +113,11 @@ impl Route {
} }
let be_precise = DIAGONALS.iter().any(|pos| { let be_precise = DIAGONALS.iter().any(|pos| {
(-1..2) (-1..2).all(|z| {
.all(|z| vol.get(next0 + Vec3::new(pos.x, pos.y, z)) vol.get(next0 + Vec3::new(pos.x, pos.y, z))
.map(|b| !b.is_solid()) .map(|b| !b.is_solid())
.unwrap_or(false)) .unwrap_or(false)
})
}); });
let next_tgt = next0.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0); let next_tgt = next0.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0);
@ -331,7 +330,8 @@ impl Chaser {
let pos_to_tgt = pos.distance(tgt); let pos_to_tgt = pos.distance(tgt);
// If we're already close to the target then there's nothing to do // If we're already close to the target then there's nothing to do
let end = self.route let end = self
.route
.as_ref() .as_ref()
.and_then(|(r, _)| r.path.end().copied()) .and_then(|(r, _)| r.path.end().copied())
.map(|e| e.map(|e| e as f32 + 0.5)) .map(|e| e.map(|e| e as f32 + 0.5))
@ -343,7 +343,8 @@ impl Chaser {
return None; return None;
} }
let bearing = if let Some((end, complete)) = self.route let bearing = if let Some((end, complete)) = self
.route
.as_ref() .as_ref()
.and_then(|(r, complete)| Some((r.path().end().copied()?, *complete))) .and_then(|(r, complete)| Some((r.path().end().copied()?, *complete)))
{ {
@ -354,7 +355,9 @@ impl Chaser {
// theory this shouldn't happen, but in practice the world is full // theory this shouldn't happen, but in practice the world is full
// of unpredictable obstacles that are more than willing to mess up // of unpredictable obstacles that are more than willing to mess up
// our day. TODO: Come up with a better heuristic for this // our day. TODO: Come up with a better heuristic for this
if (end_to_tgt > pos_to_tgt * 0.3 + 5.0 && complete) || thread_rng().gen::<f32>() < 0.001 { if (end_to_tgt > pos_to_tgt * 0.3 + 5.0 && complete)
|| thread_rng().gen::<f32>() < 0.001
{
None None
} else { } else {
self.route self.route
@ -388,20 +391,31 @@ impl Chaser {
let start_index = path let start_index = path
.iter() .iter()
.enumerate() .enumerate()
.min_by_key(|(_, node)| node.xy().map(|e| e as f32).distance_squared(pos.xy() + tgt_dir) as i32) .min_by_key(|(_, node)| {
node.xy()
.map(|e| e as f32)
.distance_squared(pos.xy() + tgt_dir)
as i32
})
.map(|(idx, _)| idx); .map(|(idx, _)| idx);
(Route { (
path, Route {
next_idx: start_index.unwrap_or(0), path,
}, complete) next_idx: start_index.unwrap_or(0),
},
complete,
)
}); });
} }
let walking_towards_edge = (-3..2) let walking_towards_edge = (-3..2).all(|z| {
.all(|z| vol.get((pos + Vec3::<f32>::from(tgt_dir) * 2.5).map(|e| e as i32) + Vec3::unit_z() * z) vol.get(
.map(|b| !b.is_solid()) (pos + Vec3::<f32>::from(tgt_dir) * 2.5).map(|e| e as i32) + Vec3::unit_z() * z,
.unwrap_or(false)); )
.map(|b| !b.is_solid())
.unwrap_or(false)
});
if !walking_towards_edge { if !walking_towards_edge {
Some(((tgt - pos) * Vec3::new(1.0, 1.0, 0.0), 0.75)) Some(((tgt - pos) * Vec3::new(1.0, 1.0, 0.0), 0.75))
@ -430,8 +444,8 @@ where
.unwrap_or(true) .unwrap_or(true)
} }
/// Attempt to search for a path to a target, returning the path (if one was found) /// Attempt to search for a path to a target, returning the path (if one was
/// and whether it is complete (reaches the target) /// found) and whether it is complete (reaches the target)
fn find_path<V>( fn find_path<V>(
astar: &mut Option<Astar<Vec3<i32>, DefaultHashBuilder>>, astar: &mut Option<Astar<Vec3<i32>, DefaultHashBuilder>>,
vol: &V, vol: &V,

View File

@ -21,7 +21,7 @@ impl Spiral2d {
impl Iterator for Spiral2d { impl Iterator for Spiral2d {
type Item = Vec2<i32>; type Item = Vec2<i32>;
#[allow(clippy::erasing_op)] #[allow(clippy::erasing_op, clippy::identity_op)]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let layer_size = (self.layer * 8 + 4 * self.layer.min(1) - 4).max(1); let layer_size = (self.layer * 8 + 4 * self.layer.min(1) - 4).max(1);
if self.i >= layer_size { if self.i >= layer_size {

View File

@ -24,7 +24,12 @@ impl CharacterBehavior for Data {
update.character = CharacterState::GlideWield; update.character = CharacterState::GlideWield;
return update; return update;
} }
if data.physics.in_fluid.map(|depth| depth > 0.5).unwrap_or(false) { if data
.physics
.in_fluid
.map(|depth| depth > 0.5)
.unwrap_or(false)
{
update.character = CharacterState::Idle; update.character = CharacterState::Idle;
} }
// If there is a wall in front of character and they are trying to climb go to // If there is a wall in front of character and they are trying to climb go to

View File

@ -19,7 +19,12 @@ impl CharacterBehavior for Data {
if !data.physics.on_ground { if !data.physics.on_ground {
update.character = CharacterState::Glide; update.character = CharacterState::Glide;
} }
if data.physics.in_fluid.map(|depth| depth > 0.5).unwrap_or(false) { if data
.physics
.in_fluid
.map(|depth| depth > 0.5)
.unwrap_or(false)
{
update.character = CharacterState::Idle; update.character = CharacterState::Idle;
} }

View File

@ -119,8 +119,9 @@ fn swim_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, depth:
// Swim // Swim
if data.inputs.swimup.is_pressed() { if data.inputs.swimup.is_pressed() {
update.vel.0.z = update.vel.0.z = (update.vel.0.z
(update.vel.0.z + data.dt.0 * GRAVITY * 4.0 * depth.clamped(0.0, 1.0).powf(3.0)).min(BASE_HUMANOID_WATER_SPEED); + data.dt.0 * GRAVITY * 4.0 * depth.clamped(0.0, 1.0).powf(3.0))
.min(BASE_HUMANOID_WATER_SPEED);
} }
// Swim // Swim
if data.inputs.swimdown.is_pressed() { if data.inputs.swimdown.is_pressed() {
@ -192,14 +193,28 @@ pub fn attempt_swap_loadout(data: &JoinData, update: &mut StateUpdate) {
/// Checks that player can wield the glider and updates `CharacterState` if so /// Checks that player can wield the glider and updates `CharacterState` if so
pub fn attempt_glide_wield(data: &JoinData, update: &mut StateUpdate) { pub fn attempt_glide_wield(data: &JoinData, update: &mut StateUpdate) {
if data.physics.on_ground && !data.physics.in_fluid.map(|depth| depth > 1.0).unwrap_or(false) && data.body.is_humanoid() { if data.physics.on_ground
&& !data
.physics
.in_fluid
.map(|depth| depth > 1.0)
.unwrap_or(false)
&& data.body.is_humanoid()
{
update.character = CharacterState::GlideWield; update.character = CharacterState::GlideWield;
} }
} }
/// Checks that player can jump and sends jump event if so /// Checks that player can jump and sends jump event if so
pub fn handle_jump(data: &JoinData, update: &mut StateUpdate) { pub fn handle_jump(data: &JoinData, update: &mut StateUpdate) {
if data.inputs.jump.is_pressed() && data.physics.on_ground && !data.physics.in_fluid.map(|depth| depth > 1.0).unwrap_or(false) { if data.inputs.jump.is_pressed()
&& data.physics.on_ground
&& !data
.physics
.in_fluid
.map(|depth| depth > 1.0)
.unwrap_or(false)
{
update update
.local_events .local_events
.push_front(LocalEvent::Jump(data.entity)); .push_front(LocalEvent::Jump(data.entity));

View File

@ -317,9 +317,11 @@ impl<'a> System<'a> for Sys {
pos.0, pos.0,
vel.0, vel.0,
// Away from the target (ironically) // Away from the target (ironically)
pos.0 + (pos.0 - tgt_pos.0) pos.0
.try_normalized() + (pos.0 - tgt_pos.0)
.unwrap_or_else(Vec3::unit_y) * 8.0, .try_normalized()
.unwrap_or_else(Vec3::unit_y)
* 8.0,
TraversalConfig { TraversalConfig {
node_tolerance, node_tolerance,
slow_factor, slow_factor,
@ -483,8 +485,11 @@ impl<'a> System<'a> for Sys {
Activity::Attack { target, .. } if target == attacker => {}, Activity::Attack { target, .. } if target == attacker => {},
_ => { _ => {
if agent.can_speak { if agent.can_speak {
let msg = "npc.speech.villager_under_attack".to_string(); let msg =
event_bus.emit_now(ServerEvent::Chat(UnresolvedChatMsg::npc(*uid, msg))); "npc.speech.villager_under_attack".to_string();
event_bus.emit_now(ServerEvent::Chat(
UnresolvedChatMsg::npc(*uid, msg),
));
} }
agent.activity = Activity::Attack { agent.activity = Activity::Attack {

View File

@ -12,8 +12,8 @@ use crate::{
use specs::{ use specs::{
saveload::MarkerAllocator, Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage, saveload::MarkerAllocator, Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage,
}; };
use vek::*;
use std::ops::Range; use std::ops::Range;
use vek::*;
pub const GRAVITY: f32 = 9.81 * 5.0; pub const GRAVITY: f32 = 9.81 * 5.0;
const BOUYANCY: f32 = 1.0; const BOUYANCY: f32 = 1.0;
@ -135,7 +135,11 @@ impl<'a> System<'a> for Sys {
.is_some(); .is_some();
let downward_force = if !in_loaded_chunk { let downward_force = if !in_loaded_chunk {
0.0 // No gravity in unloaded chunks 0.0 // No gravity in unloaded chunks
} else if physics_state.in_fluid.map(|depth| depth > 0.75).unwrap_or(false) { } else if physics_state
.in_fluid
.map(|depth| depth > 0.75)
.unwrap_or(false)
{
(1.0 - BOUYANCY) * GRAVITY (1.0 - BOUYANCY) * GRAVITY
} else { } else {
GRAVITY GRAVITY
@ -159,9 +163,9 @@ impl<'a> System<'a> for Sys {
z_max, z_max,
} => { } => {
// Scale collider // Scale collider
let radius = *radius;// * scale; let radius = *radius; // * scale;
let z_min = *z_min;// * scale; let z_min = *z_min; // * scale;
let z_max = *z_max;// * scale; let z_max = *z_max; // * scale;
// Probe distances // Probe distances
let hdist = radius.ceil() as i32; let hdist = radius.ceil() as i32;
@ -177,47 +181,46 @@ impl<'a> System<'a> for Sys {
.flatten() .flatten()
.flatten(); .flatten();
// Function for iterating over the blocks the player at a specific position collides // Function for iterating over the blocks the player at a specific position
// with // collides with
fn collision_iter<'a>( fn collision_iter<'a>(
pos: Vec3<f32>, pos: Vec3<f32>,
terrain: &'a TerrainGrid, terrain: &'a TerrainGrid,
hit: &'a dyn Fn(&Block) -> bool, hit: &'a dyn Fn(&Block) -> bool,
near_iter: impl Iterator<Item=(i32, i32, i32)> + 'a, near_iter: impl Iterator<Item = (i32, i32, i32)> + 'a,
radius: f32, radius: f32,
z_range: Range<f32>, z_range: Range<f32>,
) -> impl Iterator<Item=Aabb<f32>> + 'a { ) -> impl Iterator<Item = Aabb<f32>> + 'a {
near_iter near_iter.filter_map(move |(i, j, k)| {
.filter_map(move |(i, j, k)| { let block_pos = pos.map(|e| e.floor() as i32) + Vec3::new(i, j, k);
let block_pos = pos.map(|e| e.floor() as i32) + Vec3::new(i, j, k);
if let Some(block) = terrain.get(block_pos).ok().copied().filter(hit) { if let Some(block) = terrain.get(block_pos).ok().copied().filter(hit) {
let player_aabb = Aabb { let player_aabb = Aabb {
min: pos + Vec3::new(-radius, -radius, z_range.start), min: pos + Vec3::new(-radius, -radius, z_range.start),
max: pos + Vec3::new(radius, radius, z_range.end), max: pos + Vec3::new(radius, radius, z_range.end),
}; };
let block_aabb = Aabb { let block_aabb = Aabb {
min: block_pos.map(|e| e as f32), min: block_pos.map(|e| e as f32),
max: block_pos.map(|e| e as f32) max: block_pos.map(|e| e as f32)
+ Vec3::new(1.0, 1.0, block.get_height()), + Vec3::new(1.0, 1.0, block.get_height()),
}; };
if player_aabb.collides_with_aabb(block_aabb) { if player_aabb.collides_with_aabb(block_aabb) {
return Some(block_aabb); return Some(block_aabb);
}
} }
}
None None
}) })
}; };
// Function for determining whether the player at a specific position collides // Function for determining whether the player at a specific position collides
// with blocks with the given criteria // with blocks with the given criteria
let collision_with = |pos: Vec3<f32>, let collision_with = |pos: Vec3<f32>,
hit: &dyn Fn(&Block) -> bool, hit: &dyn Fn(&Block) -> bool,
near_iter| near_iter| {
{ collision_iter(pos, &terrain, hit, near_iter, radius, z_min..z_max).count()
collision_iter(pos, &terrain, hit, near_iter, radius, z_min..z_max).count() > 0 > 0
}; };
let was_on_ground = physics_state.on_ground; let was_on_ground = physics_state.on_ground;
@ -418,9 +421,16 @@ impl<'a> System<'a> for Sys {
} }
// Figure out if we're in water // Figure out if we're in water
physics_state.in_fluid = collision_iter(pos.0, &terrain, &|block| block.is_fluid(), near_iter.clone(), radius, z_min..z_max) physics_state.in_fluid = collision_iter(
.max_by_key(|block_aabb| (block_aabb.max.z * 100.0) as i32) pos.0,
.map(|block_aabb| block_aabb.max.z - pos.0.z); &terrain,
&|block| block.is_fluid(),
near_iter.clone(),
radius,
z_min..z_max,
)
.max_by_key(|block_aabb| (block_aabb.max.z * 100.0) as i32)
.map(|block_aabb| block_aabb.max.z - pos.0.z);
}, },
Collider::Point => { Collider::Point => {
let (dist, block) = terrain.ray(pos.0, pos.0 + pos_delta).ignore_error().cast(); let (dist, block) = terrain.ray(pos.0, pos.0 + pos_delta).ignore_error().cast();

View File

@ -209,12 +209,13 @@ impl BlockKind {
} }
pub fn get_glow(&self) -> Option<u8> { pub fn get_glow(&self) -> Option<u8> {
match self { // TODO: When we have proper volumetric lighting
// TODO: When we have proper volumetric lighting // match self {
//BlockKind::StreetLamp | BlockKind::StreetLampTall => Some(20), // BlockKind::StreetLamp | BlockKind::StreetLampTall => Some(20),
//BlockKind::Velorite | BlockKind::VeloriteFrag => Some(10), // BlockKind::Velorite | BlockKind::VeloriteFrag => Some(10),
_ => None, // _ => None,
} // }
None
} }
pub fn is_opaque(&self) -> bool { pub fn is_opaque(&self) -> bool {

View File

@ -2,9 +2,10 @@ use crate::{client::Client, Server, SpawnPoint, StateExt};
use common::{ use common::{
assets, assets,
comp::{ comp::{
self, object, Alignment, Body, Damage, DamageSource, Group, self, object, Alignment, Body, Damage, DamageSource, Group, HealthChange, HealthSource,
HealthChange, HealthSource, Player, Pos, Stats, Player, Pos, Stats,
}, },
lottery::Lottery,
msg::{PlayerListUpdate, ServerMsg}, msg::{PlayerListUpdate, ServerMsg},
outcome::Outcome, outcome::Outcome,
state::BlockChange, state::BlockChange,
@ -12,7 +13,6 @@ use common::{
sys::combat::BLOCK_ANGLE, sys::combat::BLOCK_ANGLE,
terrain::{Block, TerrainGrid}, terrain::{Block, TerrainGrid},
vol::{ReadVol, Vox}, vol::{ReadVol, Vox},
lottery::Lottery,
}; };
use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt}; use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt};
use tracing::error; use tracing::error;

View File

@ -12,7 +12,6 @@ impl Animation for BetaAnimation {
const UPDATE_FN: &'static [u8] = b"character_beta\0"; const UPDATE_FN: &'static [u8] = b"character_beta\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_beta")] #[cfg_attr(feature = "be-dyn-lib", export_name = "character_beta")]
#[allow(clippy::unnested_or_patterns)] // TODO: Pending review in #587
fn update_skeleton_inner( fn update_skeleton_inner(
skeleton: &Self::Skeleton, skeleton: &Self::Skeleton,
(active_tool_kind, second_tool_kind, _velocity, _global_time): Self::Dependency, (active_tool_kind, second_tool_kind, _velocity, _global_time): Self::Dependency,

View File

@ -16,7 +16,6 @@ impl Animation for SpinAnimation {
const UPDATE_FN: &'static [u8] = b"character_spin\0"; const UPDATE_FN: &'static [u8] = b"character_spin\0";
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_spin")] #[cfg_attr(feature = "be-dyn-lib", export_name = "character_spin")]
#[allow(clippy::unnested_or_patterns)] // TODO: Pending review in #587
fn update_skeleton_inner( fn update_skeleton_inner(
skeleton: &Self::Skeleton, skeleton: &Self::Skeleton,
(active_tool_kind, second_tool_kind, _global_time): Self::Dependency, (active_tool_kind, second_tool_kind, _global_time): Self::Dependency,

View File

@ -581,7 +581,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::character::StandAnimation::update_skeleton( (true, false, false) => anim::character::StandAnimation::update_skeleton(
@ -949,7 +949,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => { (true, false, false) => {
@ -1047,7 +1047,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => { (true, false, false) => {
@ -1143,7 +1143,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => { (true, false, false) => {
@ -1237,7 +1237,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::bird_medium::IdleAnimation::update_skeleton( (true, false, false) => anim::bird_medium::IdleAnimation::update_skeleton(
@ -1329,7 +1329,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::fish_medium::IdleAnimation::update_skeleton( (true, false, false) => anim::fish_medium::IdleAnimation::update_skeleton(
@ -1404,7 +1404,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::dragon::IdleAnimation::update_skeleton( (true, false, false) => anim::dragon::IdleAnimation::update_skeleton(
@ -1478,7 +1478,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::critter::IdleAnimation::update_skeleton( (true, false, false) => anim::critter::IdleAnimation::update_skeleton(
@ -1553,7 +1553,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::bird_small::IdleAnimation::update_skeleton( (true, false, false) => anim::bird_small::IdleAnimation::update_skeleton(
@ -1628,7 +1628,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::fish_small::IdleAnimation::update_skeleton( (true, false, false) => anim::fish_small::IdleAnimation::update_skeleton(
@ -1703,7 +1703,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::biped_large::IdleAnimation::update_skeleton( (true, false, false) => anim::biped_large::IdleAnimation::update_skeleton(
@ -1795,7 +1795,7 @@ impl FigureMgr {
let target_base = match ( let target_base = match (
physics.on_ground, physics.on_ground,
vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving vel.0.magnitude_squared() > MOVING_THRESHOLD_SQR, // Moving
physics.in_fluid.is_some(), // In water physics.in_fluid.is_some(), // In water
) { ) {
// Standing // Standing
(true, false, false) => anim::golem::IdleAnimation::update_skeleton( (true, false, false) => anim::golem::IdleAnimation::update_skeleton(

View File

@ -3,7 +3,7 @@ mod natural;
use crate::{ use crate::{
column::{ColumnGen, ColumnSample}, column::{ColumnGen, ColumnSample},
util::{RandomField, Sampler, SmallCache}, util::{RandomField, Sampler, SmallCache},
Index, CONFIG, Index,
}; };
use common::{ use common::{
terrain::{structure::StructureBlock, Block, BlockKind, Structure}, terrain::{structure::StructureBlock, Block, BlockKind, Structure},
@ -31,7 +31,9 @@ impl<'a> BlockGen<'a> {
wpos: Vec2<i32>, wpos: Vec2<i32>,
index: &Index, index: &Index,
) -> Option<&'b ColumnSample<'a>> { ) -> Option<&'b ColumnSample<'a>> {
cache.get(wpos, |wpos| column_gen.get((wpos, index))).as_ref() cache
.get(wpos, |wpos| column_gen.get((wpos, index)))
.as_ref()
} }
fn get_cliff_height( fn get_cliff_height(
@ -48,7 +50,7 @@ impl<'a> BlockGen<'a> {
|max_height, (cliff_pos, seed)| match Self::sample_column( |max_height, (cliff_pos, seed)| match Self::sample_column(
column_gen, column_gen,
cache, cache,
Vec2::from(*cliff_pos), *cliff_pos,
index, index,
) { ) {
Some(cliff_sample) if cliff_sample.is_cliffs && cliff_sample.spawn_rate > 0.5 => { Some(cliff_sample) if cliff_sample.is_cliffs && cliff_sample.spawn_rate > 0.5 => {
@ -164,14 +166,14 @@ impl<'a> BlockGen<'a> {
//tree_density, //tree_density,
//forest_kind, //forest_kind,
//close_structures, //close_structures,
marble, // marble,
marble_small, // marble_small,
rock, rock,
//cliffs, //cliffs,
cliff_hill, cliff_hill,
close_cliffs, close_cliffs,
temp, // temp,
humidity, // humidity,
stone_col, stone_col,
.. ..
} = sample; } = sample;
@ -181,7 +183,7 @@ impl<'a> BlockGen<'a> {
let wposf = wpos.map(|e| e as f64); let wposf = wpos.map(|e| e as f64);
let (block, _height) = if !only_structures { let (block, _height) = if !only_structures {
let (_definitely_underground, height, on_cliff, basement_height, water_height) = let (_definitely_underground, height, _on_cliff, basement_height, water_height) =
if (wposf.z as f32) < alt - 64.0 * chaos { if (wposf.z as f32) < alt - 64.0 * chaos {
// Shortcut warping // Shortcut warping
(true, alt, false, basement, water_level) (true, alt, false, basement, water_level)
@ -276,83 +278,84 @@ impl<'a> BlockGen<'a> {
}, },
col.map(|e| (e * 255.0) as u8), col.map(|e| (e * 255.0) as u8),
)) ))
} else if (wposf.z as f32) < height + 0.9 // } else if (wposf.z as f32) < height + 0.9
&& temp < CONFIG.desert_temp // && temp < CONFIG.desert_temp
&& (wposf.z as f32 > water_height + 3.0) // && (wposf.z as f32 > water_height + 3.0)
&& marble > 0.6 // && marble > 0.6
&& marble_small > 0.55 // && marble_small > 0.55
&& (marble * 3173.7).fract() < 0.6 // && (marble * 3173.7).fract() < 0.6
&& humidity > CONFIG.desert_hum // && humidity > CONFIG.desert_hum
&& false // && false
{ // {
let treasures = [BlockKind::Chest, BlockKind::Velorite]; // let treasures = [BlockKind::Chest, BlockKind::Velorite];
let flowers = [ // let flowers = [
BlockKind::BlueFlower, // BlockKind::BlueFlower,
BlockKind::PinkFlower, // BlockKind::PinkFlower,
BlockKind::PurpleFlower, // BlockKind::PurpleFlower,
BlockKind::RedFlower, // BlockKind::RedFlower,
BlockKind::WhiteFlower, // BlockKind::WhiteFlower,
BlockKind::YellowFlower, // BlockKind::YellowFlower,
BlockKind::Sunflower, // BlockKind::Sunflower,
BlockKind::Mushroom, //TODO: Better spawnrules // BlockKind::Mushroom, //TODO: Better spawnrules
BlockKind::LeafyPlant, // BlockKind::LeafyPlant,
BlockKind::Blueberry, // BlockKind::Blueberry,
BlockKind::LingonBerry, // BlockKind::LingonBerry,
BlockKind::Fern, // BlockKind::Fern,
/*BlockKind::Twigs, // TODO: Better spawnrules // /*BlockKind::Twigs, // TODO: Better spawnrules
*BlockKind::Stones, // TODO: Better spawnrules // *BlockKind::Stones, // TODO: Better spawnrules
*BlockKind::ShinyGem, // TODO: Better spawnrules */ // *BlockKind::ShinyGem, // TODO: Better spawnrules */
]; // ];
let grasses = [ // let grasses = [
BlockKind::LongGrass, // BlockKind::LongGrass,
BlockKind::MediumGrass, // BlockKind::MediumGrass,
BlockKind::ShortGrass, // BlockKind::ShortGrass,
]; // ];
Some(Block::new( // Some(Block::new(
if on_cliff && (height * 1271.0).fract() < 0.015 { // if on_cliff && (height * 1271.0).fract() < 0.015 {
treasures[(height * 731.3) as usize % treasures.len()] // treasures[(height * 731.3) as usize % treasures.len()]
} else if (height * 1271.0).fract() < 0.1 { // } else if (height * 1271.0).fract() < 0.1 {
flowers[(height * 0.2) as usize % flowers.len()] // flowers[(height * 0.2) as usize % flowers.len()]
} else { // } else {
grasses[(height * 103.3) as usize % grasses.len()] // grasses[(height * 103.3) as usize % grasses.len()]
}, // },
Rgb::broadcast(0), // Rgb::broadcast(0),
)) // ))
} else if (wposf.z as f32) < height + 0.9 // } else if (wposf.z as f32) < height + 0.9
&& temp > CONFIG.desert_temp // && temp > CONFIG.desert_temp
&& (marble * 4423.5).fract() < 0.0005 // && (marble * 4423.5).fract() < 0.0005
&& false // && false
{ // {
let large_cacti = [ // let large_cacti = [
BlockKind::LargeCactus, // BlockKind::LargeCactus,
BlockKind::MedFlatCactus, // BlockKind::MedFlatCactus,
BlockKind::Welwitch, // BlockKind::Welwitch,
]; // ];
let small_cacti = [ // let small_cacti = [
BlockKind::BarrelCactus, // BlockKind::BarrelCactus,
BlockKind::RoundCactus, // BlockKind::RoundCactus,
BlockKind::ShortCactus, // BlockKind::ShortCactus,
BlockKind::ShortFlatCactus, // BlockKind::ShortFlatCactus,
BlockKind::DeadBush, // BlockKind::DeadBush,
]; // ];
Some(Block::new( // Some(Block::new(
if (height * 1271.0).fract() < 0.5 { // if (height * 1271.0).fract() < 0.5 {
large_cacti[(height * 0.2) as usize % large_cacti.len()] // large_cacti[(height * 0.2) as usize % large_cacti.len()]
} else { // } else {
small_cacti[(height * 0.3) as usize % small_cacti.len()] // small_cacti[(height * 0.3) as usize % small_cacti.len()]
}, // },
Rgb::broadcast(0), // Rgb::broadcast(0),
)) // ))
} else { } else {
None None
} }
.or_else(|| { .or_else(|| {
// Rocks // Rocks
if (height + 2.5 - wposf.z as f32).div(7.5).abs().powf(2.0) < rock { if (height + 2.5 - wposf.z as f32).div(7.5).abs().powf(2.0) < rock {
#[allow(clippy::identity_op)]
let field0 = RandomField::new(world.seed + 0); let field0 = RandomField::new(world.seed + 0);
let field1 = RandomField::new(world.seed + 1); let field1 = RandomField::new(world.seed + 1);
let field2 = RandomField::new(world.seed + 2); let field2 = RandomField::new(world.seed + 2);
@ -536,7 +539,7 @@ pub fn block_from_structure(
structure_seed: u32, structure_seed: u32,
sample: &ColumnSample, sample: &ColumnSample,
) -> Option<Block> { ) -> Option<Block> {
let field = RandomField::new(structure_seed + 0); let field = RandomField::new(structure_seed);
let lerp = ((field.get(Vec3::from(structure_pos)).rem_euclid(256)) as f32 / 255.0) * 0.85 let lerp = ((field.get(Vec3::from(structure_pos)).rem_euclid(256)) as f32 / 255.0) * 0.85
+ ((field.get(pos + std::i32::MAX / 2).rem_euclid(256)) as f32 / 255.0) * 0.15; + ((field.get(pos + std::i32::MAX / 2).rem_euclid(256)) as f32 / 255.0) * 0.15;

View File

@ -681,7 +681,6 @@ fn loc_suitable_for_site(sim: &WorldSim, loc: Vec2<i32>) -> bool {
} }
/// Attempt to search for a location that's suitable for site construction /// Attempt to search for a location that's suitable for site construction
#[allow(clippy::useless_conversion)] // TODO: Pending review in #587
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 #[allow(clippy::or_fun_call)] // TODO: Pending review in #587
fn find_site_loc( fn find_site_loc(
ctx: &mut GenCtx<impl Rng>, ctx: &mut GenCtx<impl Rng>,
@ -716,7 +715,7 @@ fn find_site_loc(
loc = ctx.sim.get(test_loc).and_then(|c| { loc = ctx.sim.get(test_loc).and_then(|c| {
Some( Some(
c.downhill? c.downhill?
.map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| { .map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
e / (sz as i32) e / (sz as i32)
}), }),
) )

View File

@ -179,7 +179,6 @@ where
#[allow(clippy::if_same_then_else)] // TODO: Pending review in #587 #[allow(clippy::if_same_then_else)] // TODO: Pending review in #587
#[allow(clippy::nonminimal_bool)] // TODO: Pending review in #587 #[allow(clippy::nonminimal_bool)] // TODO: Pending review in #587
#[allow(clippy::single_match)] // TODO: Pending review in #587 #[allow(clippy::single_match)] // TODO: Pending review in #587
#[allow(clippy::bind_instead_of_map)] // TODO: Pending review in #587
fn get(&self, (wpos, index): Self::Index) -> Option<ColumnSample<'a>> { fn get(&self, (wpos, index): Self::Index) -> Option<ColumnSample<'a>> {
let wposf = wpos.map(|e| e as f64); let wposf = wpos.map(|e| e as f64);
let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32); let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);

View File

@ -26,6 +26,7 @@ pub struct Noise {
} }
impl Noise { impl Noise {
#[allow(clippy::identity_op)]
fn new(seed: u32) -> Self { fn new(seed: u32) -> Self {
Self { Self {
cave_nz: SuperSimplex::new().set_seed(seed + 0), cave_nz: SuperSimplex::new().set_seed(seed + 0),

View File

@ -31,6 +31,7 @@ pub fn apply_scatter_to<'a>(
chunk: &SimChunk, chunk: &SimChunk,
) { ) {
use BlockKind::*; use BlockKind::*;
#[allow(clippy::type_complexity)]
let scatter: &[(_, bool, fn(&SimChunk) -> (f32, Option<(f32, f32)>))] = &[ let scatter: &[(_, bool, fn(&SimChunk) -> (f32, Option<(f32, f32)>))] = &[
// (density, Option<(wavelen, threshold)>) // (density, Option<(wavelen, threshold)>)
(BlueFlower, false, |c| { (BlueFlower, false, |c| {
@ -103,8 +104,7 @@ pub fn apply_scatter_to<'a>(
.enumerate() .enumerate()
.find_map(|(i, (bk, is_underwater, f))| { .find_map(|(i, (bk, is_underwater, f))| {
let (density, patch) = f(chunk); let (density, patch) = f(chunk);
if density <= 0.0 let is_patch = patch
|| patch
.map(|(wavelen, threshold)| { .map(|(wavelen, threshold)| {
index.noise.scatter_nz.get( index.noise.scatter_nz.get(
wpos2d wpos2d
@ -112,7 +112,9 @@ pub fn apply_scatter_to<'a>(
.into_array(), .into_array(),
) < threshold as f64 ) < threshold as f64
}) })
.unwrap_or(false) .unwrap_or(false);
if density <= 0.0
|| is_patch
|| !RandomField::new(i as u32) || !RandomField::new(i as u32)
.chance(Vec3::new(wpos2d.x, wpos2d.y, 0), density) .chance(Vec3::new(wpos2d.x, wpos2d.y, 0), density)
|| underwater != *is_underwater || underwater != *is_underwater
@ -398,6 +400,7 @@ pub fn apply_caves_supplement<'a>(
comp::critter::Body::random_with(rng, &species).into() comp::critter::Body::random_with(rng, &species).into()
}, },
4 => { 4 => {
#[allow(clippy::match_single_binding)]
let species = match rng.gen_range(0, 1) { let species = match rng.gen_range(0, 1) {
_ => comp::golem::Species::StoneGolem, _ => comp::golem::Species::StoneGolem,
}; };

View File

@ -2,10 +2,10 @@ use vek::*;
#[derive(Copy, Clone, Debug, Default)] #[derive(Copy, Clone, Debug, Default)]
pub struct Way { pub struct Way {
/// Offset from chunk center in blocks (no more than half chunk width) /// Offset from chunk center in blocks (no more than half chunk width)
pub offset: Vec2<i8>, pub offset: Vec2<i8>,
/// Neighbor connections, one bit each /// Neighbor connections, one bit each
pub neighbors: u8, pub neighbors: u8,
} }
impl Way { impl Way {
@ -20,23 +20,23 @@ pub struct Path {
} }
impl Default for Path { impl Default for Path {
fn default() -> Self { fn default() -> Self { Self { width: 5.0 } }
Self { width: 5.0 }
}
} }
impl Lerp for Path { impl Lerp for Path {
type Output = Self; type Output = Self;
fn lerp_unclamped(from: Self, to: Self, factor: f32) -> Self::Output { fn lerp_unclamped(from: Self, to: Self, factor: f32) -> Self::Output {
Self { width: Lerp::lerp(from.width, to.width, factor) } Self {
width: Lerp::lerp(from.width, to.width, factor),
}
} }
} }
impl Path { impl Path {
/// Return the number of blocks of headspace required at the given path /// Return the number of blocks of headspace required at the given path
/// distance /// distance
/// TODO: make this generic over width /// TODO: make this generic over width
pub fn head_space(&self, dist: f32) -> i32 { pub fn head_space(&self, dist: f32) -> i32 {
(8 - (dist * 0.25).powf(6.0).round() as i32).max(1) (8 - (dist * 0.25).powf(6.0).round() as i32).max(1)
} }
@ -48,7 +48,7 @@ impl Path {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct Cave { pub struct Cave {
pub width: f32, // Actually radius pub width: f32, // Actually radius
pub alt: f32, // Actually radius pub alt: f32, // Actually radius
} }
impl Default for Cave { impl Default for Cave {

View File

@ -15,32 +15,39 @@ const YEAR: f32 = 12.0 * MONTH;
const TICK_PERIOD: f32 = 3.0 * MONTH; // 3 months const TICK_PERIOD: f32 = 3.0 * MONTH; // 3 months
const HISTORY_DAYS: f32 = 500.0 * YEAR; // 500 years const HISTORY_DAYS: f32 = 500.0 * YEAR; // 500 years
const GENERATE_CSV: bool = false;
pub fn simulate(index: &mut Index, world: &mut WorldSim) { pub fn simulate(index: &mut Index, world: &mut WorldSim) {
use std::io::Write; use std::io::Write;
let mut f = std::fs::File::create("economy.csv").unwrap(); let mut f = if GENERATE_CSV {
write!(f, "Population,").unwrap(); let mut f = std::fs::File::create("economy.csv").unwrap();
for g in Good::list() { write!(f, "Population,").unwrap();
write!(f, "{:?} Value,", g).unwrap(); for g in Good::list() {
} write!(f, "{:?} Value,", g).unwrap();
for g in Good::list() { }
write!(f, "{:?} LaborVal,", g).unwrap(); for g in Good::list() {
} write!(f, "{:?} LaborVal,", g).unwrap();
for g in Good::list() { }
write!(f, "{:?} Stock,", g).unwrap(); for g in Good::list() {
} write!(f, "{:?} Stock,", g).unwrap();
for g in Good::list() { }
write!(f, "{:?} Surplus,", g).unwrap(); for g in Good::list() {
} write!(f, "{:?} Surplus,", g).unwrap();
for l in Labor::list() { }
write!(f, "{:?} Labor,", l).unwrap(); for l in Labor::list() {
} write!(f, "{:?} Labor,", l).unwrap();
for l in Labor::list() { }
write!(f, "{:?} Productivity,", l).unwrap(); for l in Labor::list() {
} write!(f, "{:?} Productivity,", l).unwrap();
for l in Labor::list() { }
write!(f, "{:?} Yields,", l).unwrap(); for l in Labor::list() {
} write!(f, "{:?} Yields,", l).unwrap();
writeln!(f, "").unwrap(); }
writeln!(f).unwrap();
Some(f)
} else {
None
};
for i in 0..(HISTORY_DAYS / TICK_PERIOD) as i32 { for i in 0..(HISTORY_DAYS / TICK_PERIOD) as i32 {
if (index.time / YEAR) as i32 % 50 == 0 && (index.time % YEAR) as i32 == 0 { if (index.time / YEAR) as i32 % 50 == 0 && (index.time % YEAR) as i32 == 0 {
@ -49,31 +56,33 @@ pub fn simulate(index: &mut Index, world: &mut WorldSim) {
tick(index, world, TICK_PERIOD); tick(index, world, TICK_PERIOD);
if i % 5 == 0 { if let Some(f) = f.as_mut() {
let site = index.sites.values().next().unwrap(); if i % 5 == 0 {
write!(f, "{},", site.economy.pop).unwrap(); let site = index.sites.values().next().unwrap();
for g in Good::list() { write!(f, "{},", site.economy.pop).unwrap();
write!(f, "{:?},", site.economy.values[*g].unwrap_or(-1.0)).unwrap(); for g in Good::list() {
write!(f, "{:?},", site.economy.values[*g].unwrap_or(-1.0)).unwrap();
}
for g in Good::list() {
write!(f, "{:?},", site.economy.labor_values[*g].unwrap_or(-1.0)).unwrap();
}
for g in Good::list() {
write!(f, "{:?},", site.economy.stocks[*g]).unwrap();
}
for g in Good::list() {
write!(f, "{:?},", site.economy.marginal_surplus[*g]).unwrap();
}
for l in Labor::list() {
write!(f, "{:?},", site.economy.labors[*l] * site.economy.pop).unwrap();
}
for l in Labor::list() {
write!(f, "{:?},", site.economy.productivity[*l]).unwrap();
}
for l in Labor::list() {
write!(f, "{:?},", site.economy.yields[*l]).unwrap();
}
writeln!(f).unwrap();
} }
for g in Good::list() {
write!(f, "{:?},", site.economy.labor_values[*g].unwrap_or(-1.0)).unwrap();
}
for g in Good::list() {
write!(f, "{:?},", site.economy.stocks[*g]).unwrap();
}
for g in Good::list() {
write!(f, "{:?},", site.economy.marginal_surplus[*g]).unwrap();
}
for l in Labor::list() {
write!(f, "{:?},", site.economy.labors[*l] * site.economy.pop).unwrap();
}
for l in Labor::list() {
write!(f, "{:?},", site.economy.productivity[*l]).unwrap();
}
for l in Labor::list() {
write!(f, "{:?},", site.economy.yields[*l]).unwrap();
}
writeln!(f, "").unwrap();
} }
} }
} }
@ -204,8 +213,7 @@ pub fn tick_site_economy(index: &mut Index, site: Id<Site>, dt: f32) {
// What quantity is this order requesting? // What quantity is this order requesting?
let _quantity = *amount * scale; let _quantity = *amount * scale;
// What proportion of this order is the economy able to satisfy? // What proportion of this order is the economy able to satisfy?
let satisfaction = (stocks_before[*good] / demand[*good]).min(1.0); (stocks_before[*good] / demand[*good]).min(1.0)
satisfaction
}) })
.min_by(|a, b| a.partial_cmp(b).unwrap()) .min_by(|a, b| a.partial_cmp(b).unwrap())
.unwrap_or_else(|| panic!("Industry {:?} requires at least one input order", labor)); .unwrap_or_else(|| panic!("Industry {:?} requires at least one input order", labor));

View File

@ -479,7 +479,8 @@ impl Floor {
.reduce_and() .reduce_and()
}) })
.unwrap_or(false); .unwrap_or(false);
let boss_spawn_tile = boss_spawn_tile + if boss_tile_is_pillar { 1 } else { 0 }; let boss_spawn_tile =
boss_spawn_tile + if boss_tile_is_pillar { 1 } else { 0 };
if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d { if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d {
let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32)) let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32))
@ -641,7 +642,8 @@ impl Floor {
move |z| match self.tiles.get(tile_pos) { move |z| match self.tiles.get(tile_pos) {
Some(Tile::Solid) => BlockMask::nothing(), Some(Tile::Solid) => BlockMask::nothing(),
Some(Tile::Tunnel) => { Some(Tile::Tunnel) => {
if dist_to_wall >= wall_thickness && (z as f32) < tunnel_height * (1.0 - tunnel_dist.powf(4.0)) if dist_to_wall >= wall_thickness
&& (z as f32) < tunnel_height * (1.0 - tunnel_dist.powf(4.0))
{ {
if z == 0 { floor_sprite } else { empty } if z == 0 { floor_sprite } else { empty }
} else { } else {

View File

@ -294,10 +294,16 @@ impl Archetype for House {
let edge_ori = if bound_offset.x.abs() > bound_offset.y.abs() { let edge_ori = if bound_offset.x.abs() > bound_offset.y.abs() {
if center_offset.x > 0 { 6 } else { 2 } if center_offset.x > 0 { 6 } else { 2 }
} else if (center_offset.y > 0) ^ (ori == Ori::East) {
0
} else { } else {
if (center_offset.y > 0) ^ (ori == Ori::East) { 0 } else { 4 } 4
};
let edge_ori = if ori == Ori::East {
(edge_ori + 2) % 8
} else {
edge_ori
}; };
let edge_ori = if ori == Ori::East { (edge_ori + 2) % 8 } else { edge_ori };
if let Pillar::Chimney(chimney_height) = attr.pillar { if let Pillar::Chimney(chimney_height) = attr.pillar {
let chimney_top = roof_top + chimney_height; let chimney_top = roof_top + chimney_height;
@ -491,9 +497,16 @@ impl Archetype for House {
} else if dist == width - 1 } else if dist == width - 1
&& center_offset.sum() % 2 == 0 && center_offset.sum() % 2 == 0
&& profile.y == floor_height + 1 && profile.y == floor_height + 1
&& self.noise.chance(Vec3::new(center_offset.x, center_offset.y, z), 0.2) && self
.noise
.chance(Vec3::new(center_offset.x, center_offset.y, z), 0.2)
{ {
let furniture = match self.noise.get(Vec3::new(center_offset.x, center_offset.y, z + 100)) % 11 { let furniture = match self.noise.get(Vec3::new(
center_offset.x,
center_offset.y,
z + 100,
)) % 11
{
0 => BlockKind::Planter, 0 => BlockKind::Planter,
1 => BlockKind::ChairSingle, 1 => BlockKind::ChairSingle,
2 => BlockKind::ChairDouble, 2 => BlockKind::ChairDouble,
@ -506,7 +519,10 @@ impl Archetype for House {
_ => BlockKind::Pot, _ => BlockKind::Pot,
}; };
return Some(BlockMask::new(Block::new(furniture, Rgb::new(edge_ori, 0, 0)), internal_layer)); return Some(BlockMask::new(
Block::new(furniture, Rgb::new(edge_ori, 0, 0)),
internal_layer,
));
} else { } else {
return Some(internal); return Some(internal);
} }
@ -516,16 +532,26 @@ impl Archetype for House {
if dist == width + 1 if dist == width + 1
&& center_offset.map(|e| e.abs()).reduce_min() == 0 && center_offset.map(|e| e.abs()).reduce_min() == 0
&& profile.y == floor_height + 3 && profile.y == floor_height + 3
&& self.noise.chance(Vec3::new(center_offset.x, center_offset.y, z), 0.35) && self
.noise
.chance(Vec3::new(center_offset.x, center_offset.y, z), 0.35)
&& attr.storey_fill.has_lower() && attr.storey_fill.has_lower()
{ {
let ornament = match self.noise.get(Vec3::new(center_offset.x, center_offset.y, z + 100)) % 4 { let ornament =
0 => BlockKind::HangingSign, match self
1 | 2 | 3 => BlockKind::HangingBasket, .noise
_ => BlockKind::DungeonWallDecor, .get(Vec3::new(center_offset.x, center_offset.y, z + 100))
}; % 4
{
0 => BlockKind::HangingSign,
1 | 2 | 3 => BlockKind::HangingBasket,
_ => BlockKind::DungeonWallDecor,
};
return Some(BlockMask::new(Block::new(ornament, Rgb::new((edge_ori + 4) % 8, 0, 0)), internal_layer)); Some(BlockMask::new(
Block::new(ornament, Rgb::new((edge_ori + 4) % 8, 0, 0)),
internal_layer,
))
} else { } else {
None None
} }

View File

@ -208,9 +208,14 @@ impl Archetype for Keep {
if profile.y > roof_height if profile.y > roof_height
&& (min_dist < rampart_width - 1 || (attr.is_tower && min_dist < rampart_width)) && (min_dist < rampart_width - 1 || (attr.is_tower && min_dist < rampart_width))
{ {
if attr.is_tower && attr.flag && center_offset == Vec2::zero() && profile.y < roof_height + 16 { if attr.is_tower
&& attr.flag
&& center_offset == Vec2::zero()
&& profile.y < roof_height + 16
{
pole pole
} else if attr.is_tower && attr.flag } else if attr.is_tower
&& attr.flag
&& center_offset.x == 0 && center_offset.x == 0
&& center_offset.y > 0 && center_offset.y > 0
&& center_offset.y < 8 && center_offset.y < 8