mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Fmt and clippy lints fixes
This commit is contained in:
parent
331a61e426
commit
a8b0a678d8
@ -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!",
|
||||||
|
@ -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::*;
|
||||||
|
@ -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};
|
||||||
|
@ -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)
|
||||||
|
@ -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() }
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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(
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -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);
|
||||||
|
@ -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),
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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 {
|
||||||
|
@ -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));
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user