Fmt, make clippy happy

This commit is contained in:
Joshua Barretto 2020-11-23 15:39:03 +00:00
parent 6215682619
commit 26fd40c0e3
43 changed files with 660 additions and 504 deletions

View File

@ -1,8 +1,8 @@
use crate::{ use crate::{
comp::{humanoid, quadruped_low, quadruped_medium, quadruped_small, Body}, comp::{humanoid, quadruped_low, quadruped_medium, quadruped_small, Body},
path::Chaser, path::Chaser,
sync::Uid,
rtsim::RtSimController, rtsim::RtSimController,
sync::Uid,
}; };
use specs::{Component, Entity as EcsEntity}; use specs::{Component, Entity as EcsEntity};
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;

View File

@ -1,11 +1,4 @@
use crate::{ use crate::{character::CharacterId, comp, rtsim::RtSimEntity, sync::Uid, util::Dir, Explosion};
character::CharacterId,
sync::Uid,
util::Dir,
comp,
Explosion,
rtsim::RtSimEntity,
};
use comp::{ use comp::{
item::{Item, Reagent}, item::{Item, Reagent},
Ori, Pos, Ori, Pos,

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
comp::{self, humanoid, Alignment, Body, Item}, comp::{self, humanoid, Alignment, Body, Item},
npc::{self, NPC_NAMES},
loadout_builder::LoadoutConfig, loadout_builder::LoadoutConfig,
npc::{self, NPC_NAMES},
}; };
use vek::*; use vek::*;

View File

@ -88,7 +88,7 @@ impl LoadoutBuilder {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
pub fn build_loadout( pub fn build_loadout(
body: Body, body: Body,
alignment: Alignment, _alignment: Alignment,
mut main_tool: Option<Item>, mut main_tool: Option<Item>,
is_giant: bool, is_giant: bool,
map: &AbilityMap, map: &AbilityMap,
@ -410,13 +410,11 @@ impl LoadoutBuilder {
back: None, back: None,
ring: None, ring: None,
neck: None, neck: None,
lantern: Some(Item::new_from_asset_expect( lantern: Some(Item::new_from_asset_expect("common.items.lantern.black_0")),
"common.items.lantern.black_0",
)),
glider: None, glider: None,
head: None, head: None,
tabard: None, tabard: None,
} },
} }
} else { } else {
match body { match body {

View File

@ -130,7 +130,8 @@ impl Route {
// Determine whether we're close enough to the next to to consider it completed // Determine whether we're close enough to the next to to consider it completed
let dist_sqrd = pos.xy().distance_squared(closest_tgt.xy()); let dist_sqrd = pos.xy().distance_squared(closest_tgt.xy());
if dist_sqrd < traversal_cfg.node_tolerance.powf(2.0) * if be_precise { 0.25 } else { 1.0 } if dist_sqrd
< traversal_cfg.node_tolerance.powf(2.0) * if be_precise { 0.25 } else { 1.0 }
&& (((pos.z - closest_tgt.z > 1.2 || (pos.z - closest_tgt.z > -0.2 && traversal_cfg.on_ground)) && (((pos.z - closest_tgt.z > 1.2 || (pos.z - closest_tgt.z > -0.2 && traversal_cfg.on_ground))
&& (pos.z - closest_tgt.z < 1.2 || (pos.z - closest_tgt.z < 2.9 && vel.z < -0.05)) && (pos.z - closest_tgt.z < 1.2 || (pos.z - closest_tgt.z < 2.9 && vel.z < -0.05))
&& vel.z <= 0.0 && vel.z <= 0.0
@ -142,7 +143,9 @@ impl Route {
.0 .0
> pos.distance(closest_tgt) * 0.9 || dist_sqrd < 0.5) > pos.distance(closest_tgt) * 0.9 || dist_sqrd < 0.5)
&& self.next_idx < self.path.len()) && self.next_idx < self.path.len())
|| (traversal_cfg.in_liquid && pos.z < closest_tgt.z + 0.8 && pos.z > closest_tgt.z)) || (traversal_cfg.in_liquid
&& pos.z < closest_tgt.z + 0.8
&& pos.z > closest_tgt.z))
{ {
// Node completed, move on to the next one // Node completed, move on to the next one
self.next_idx += 1; self.next_idx += 1;
@ -438,15 +441,14 @@ fn walkable<V>(vol: &V, pos: Vec3<i32>) -> bool
where where
V: BaseVol<Vox = Block> + ReadVol, V: BaseVol<Vox = Block> + ReadVol,
{ {
let below = vol.get(pos - Vec3::unit_z()) let below = vol
.get(pos - Vec3::unit_z())
.ok() .ok()
.copied() .copied()
.unwrap_or_else(Block::empty); .unwrap_or_else(Block::empty);
let a = vol.get(pos) let a = vol.get(pos).ok().copied().unwrap_or_else(Block::empty);
.ok() let b = vol
.copied() .get(pos + Vec3::unit_z())
.unwrap_or_else(Block::empty);
let b = vol.get(pos + Vec3::unit_z())
.ok() .ok()
.copied() .copied()
.unwrap_or_else(Block::empty); .unwrap_or_else(Block::empty);
@ -538,13 +540,15 @@ where
// ]; // ];
DIRS.iter() DIRS.iter()
.chain(Some(JUMPS.iter()) .chain(
.filter(|_| vol Some(JUMPS.iter())
.get(pos) .filter(|_| {
.map(|b| !b.is_liquid()) vol.get(pos).map(|b| !b.is_liquid()).unwrap_or(true)
.unwrap_or(true) || traversal_cfg.can_climb) || traversal_cfg.can_climb
})
.into_iter() .into_iter()
.flatten()) .flatten(),
)
.map(move |dir| (pos, dir)) .map(move |dir| (pos, dir))
.filter(move |(pos, dir)| { .filter(move |(pos, dir)| {
is_walkable(pos) is_walkable(pos)

View File

@ -3,8 +3,8 @@
// `Agent`). When possible, this should be moved to the `rtsim` // `Agent`). When possible, this should be moved to the `rtsim`
// module in `server`. // module in `server`.
use specs_idvs::IdvStorage;
use specs::Component; use specs::Component;
use specs_idvs::IdvStorage;
use vek::*; use vek::*;
pub type RtSimId = usize; pub type RtSimId = usize;
@ -16,20 +16,20 @@ impl Component for RtSimEntity {
type Storage = IdvStorage<Self>; type Storage = IdvStorage<Self>;
} }
/// This type is the map route through which the rtsim (real-time simulation) aspect /// This type is the map route through which the rtsim (real-time simulation)
/// of the game communicates with the rest of the game. It is analagous to /// aspect of the game communicates with the rest of the game. It is analagous
/// `comp::Controller` in that it provides a consistent interface for simulation NPCs /// to `comp::Controller` in that it provides a consistent interface for
/// to control their actions. Unlike `comp::Controller`, it is very abstract and is /// simulation NPCs to control their actions. Unlike `comp::Controller`, it is
/// intended for consumption by both the agent code and the internal rtsim simulation /// very abstract and is intended for consumption by both the agent code and the
/// code (depending on whether the entity is loaded into the game as a physical entity /// internal rtsim simulation code (depending on whether the entity is loaded
/// or not). Agent code should attempt to act upon its instructions where reasonable /// into the game as a physical entity or not). Agent code should attempt to act
/// although deviations for various reasons (obstacle avoidance, counter-attacking, /// upon its instructions where reasonable although deviations for various
/// etc.) are expected. /// reasons (obstacle avoidance, counter-attacking, etc.) are expected.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct RtSimController { pub struct RtSimController {
/// When this field is `Some(..)`, the agent should attempt to make progress /// When this field is `Some(..)`, the agent should attempt to make progress
/// toward the given location, accounting for obstacles and other high-priority /// toward the given location, accounting for obstacles and other
/// situations like being attacked. /// high-priority situations like being attacked.
pub travel_to: Option<Vec3<f32>>, pub travel_to: Option<Vec3<f32>>,
/// Proportion of full speed to move /// Proportion of full speed to move
pub speed_factor: f32, pub speed_factor: f32,
@ -45,7 +45,5 @@ impl Default for RtSimController {
} }
impl RtSimController { impl RtSimController {
pub fn reset(&mut self) { pub fn reset(&mut self) { *self = Self::default(); }
*self = Self::default();
}
} }

View File

@ -5,7 +5,10 @@ use crate::{
}, },
event::LocalEvent, event::LocalEvent,
states::*, states::*,
sys::{character_behavior::JoinData, phys::{GRAVITY, FRIC_GROUND}}, sys::{
character_behavior::JoinData,
phys::{FRIC_GROUND, GRAVITY},
},
util::Dir, util::Dir,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -95,6 +98,7 @@ impl Body {
} }
} }
#[allow(clippy::match_like_matches_macro)]
pub fn can_climb(&self) -> bool { pub fn can_climb(&self) -> bool {
match self { match self {
Body::Humanoid(_) => true, Body::Humanoid(_) => true,

View File

@ -223,20 +223,14 @@ impl<'a> System<'a> for Sys {
match &mut agent.activity { match &mut agent.activity {
Activity::Idle { bearing, chaser } => { Activity::Idle { bearing, chaser } => {
if let Some(travel_to) = agent.rtsim_controller.travel_to { if let Some(travel_to) = agent.rtsim_controller.travel_to {
if let Some((bearing, speed)) = chaser.chase( if let Some((bearing, speed)) =
&*terrain, chaser.chase(&*terrain, pos.0, vel.0, travel_to, TraversalConfig {
pos.0,
vel.0,
travel_to,
TraversalConfig {
min_tgt_dist: 1.25, min_tgt_dist: 1.25,
..traversal_config ..traversal_config
}, })
) { {
inputs.move_dir = bearing inputs.move_dir =
.xy() bearing.xy().try_normalized().unwrap_or(Vec2::zero())
.try_normalized()
.unwrap_or(Vec2::zero())
* speed.min(agent.rtsim_controller.speed_factor); * speed.min(agent.rtsim_controller.speed_factor);
inputs.jump.set_state(bearing.z > 1.5); inputs.jump.set_state(bearing.z > 1.5);
inputs.climb = Some(comp::Climb::Up); inputs.climb = Some(comp::Climb::Up);

View File

@ -19,7 +19,7 @@ use roots::find_roots_cubic;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
vol::{RectVolSize, ReadVol}, vol::{ReadVol, RectVolSize},
volumes::vol_grid_2d::VolGrid2d, volumes::vol_grid_2d::VolGrid2d,
}; };
use vek::*; use vek::*;

View File

@ -437,14 +437,15 @@ fn handle_time(
// Accept `u12345`, seconds since midnight day 0 // Accept `u12345`, seconds since midnight day 0
Err(_) => match n Err(_) => match n
.get(1..) .get(1..)
.filter(|_| n.chars().next() == Some('u')) .filter(|_| n.starts_with('u'))
.and_then(|n| n.trim_left_matches('u').parse::<u64>().ok()) .and_then(|n| n.trim_start_matches('u').parse::<u64>().ok())
{ {
Some(n) => n as f64, Some(n) => n as f64,
None => { None => {
server.notify_client( server.notify_client(
client, client,
ChatType::CommandError.server_msg(format!("'{}' is not a valid time.", n)), ChatType::CommandError
.server_msg(format!("'{}' is not a valid time.", n)),
); );
return; return;
}, },
@ -454,9 +455,49 @@ fn handle_time(
None => { None => {
let time_in_seconds = server.state.ecs_mut().read_resource::<TimeOfDay>().0; let time_in_seconds = server.state.ecs_mut().read_resource::<TimeOfDay>().0;
// Would this ever change? Perhaps in a few hundred thousand years some
// game archeologists of the future will resurrect the best game of all
// time which, obviously, would be Veloren. By that time, the inescapable
// laws of thermodynamics will mean that the earth's rotation period
// would be slower. Of course, a few hundred thousand years is enough
// for the circadian rhythm of human biology to have shifted to account
// accordingly. When booting up Veloren for the first time in 337,241
// years, they might feel a touch of anguish at the fact that their
// earth days and the days within the game do not neatly divide into
// one-another. Understandably, they'll want to change this. Who
// wouldn't? It would be like turning the TV volume up to an odd number
// or having a slightly untuned radio (assuming they haven't begun
// broadcasting information directly into their brains). Totally
// unacceptable. No, the correct and proper thing to do would be to
// release a retroactive definitive edition DLC for $99 with the very
// welcome addition of shorter day periods and a complementary
// 'developer commentary' mode created by digging up the long-decayed
// skeletons of the Veloren team, measuring various attributes of their
// jawlines, and using them to recreate their voices. But how to go about
// this Herculean task? This code is jibberish! The last of the core Rust
// dev team died exactly 337,194 years ago! Rust is now a long-forgotten
// dialect of the ancient ones, lost to the sands of time. Ashes to ashes,
// dust to dust. When all hope is lost, one particularly intrepid
// post-human hominid exployed by the 'Veloren Revival Corp' (no doubt we
// still won't have gotted rid of this blasted 'capitalism' thing by then)
// might notice, after years of searching, a particularly curious
// inscription within the code. The letters `D`, `A`, `Y`. Curious! She
// consults the post-human hominid scholars of the old. Care to empathise
// with her shock when she discovers that these symbols, as alien as they
// may seem, correspond exactly to the word `ⓕя𝐢ᵇᵇ𝔩E`, the word for
// 'day' in the post-human hominid language, which is of course universal.
// Imagine also her surprise when, after much further translating, she
// finds a comment predicting her very existence and her struggle to
// decode this great mystery. Rejoyce! The Veloren Revival Corp. may now
// persist with their great Ultimate Edition DLC because the day period
// might now be changed because they have found the constant that controls
// it! Everybody was henceforth happy until the end of time.
//
// This one's for you, xMac ;)
const DAY: u64 = 86400;
let current_time = NaiveTime::from_num_seconds_from_midnight_opt( let current_time = NaiveTime::from_num_seconds_from_midnight_opt(
// Wraps around back to 0s if it exceeds 24 hours (24 hours = 86400s) // Wraps around back to 0s if it exceeds 24 hours (24 hours = 86400s)
(time_in_seconds as u64 % 86400) as u32, (time_in_seconds as u64 % DAY) as u32,
0, 0,
); );
let msg = match current_time { let msg = match current_time {
@ -470,14 +511,14 @@ fn handle_time(
server.state.ecs_mut().write_resource::<TimeOfDay>().0 = new_time; server.state.ecs_mut().write_resource::<TimeOfDay>().0 = new_time;
if let Some(new_time) = NaiveTime::from_num_seconds_from_midnight_opt(((new_time as u64) % 86400) as u32, 0) { if let Some(new_time) =
NaiveTime::from_num_seconds_from_midnight_opt(((new_time as u64) % 86400) as u32, 0)
{
server.notify_client( server.notify_client(
client, client,
ChatType::CommandInfo.server_msg(format!( ChatType::CommandInfo.server_msg(format!(
"Time changed to: {}", "Time changed to: {}",
new_time new_time.format("%H:%M").to_string(),
.format("%H:%M")
.to_string(),
)), )),
); );
} }

View File

@ -6,8 +6,8 @@ use common::{
LightEmitter, Loadout, Ori, Pos, Projectile, Scale, Stats, Vel, WaypointArea, LightEmitter, Loadout, Ori, Pos, Projectile, Scale, Stats, Vel, WaypointArea,
}, },
outcome::Outcome, outcome::Outcome,
util::Dir,
rtsim::RtSimEntity, rtsim::RtSimEntity,
util::Dir,
}; };
use comp::group; use comp::group;
use specs::{Builder, Entity as EcsEntity, WorldExt}; use specs::{Builder, Entity as EcsEntity, WorldExt};

View File

@ -1,8 +1,8 @@
use crate::{ use crate::{
client::Client, client::Client,
comp::{biped_large, quadruped_medium, quadruped_small, PhysicsState}, comp::{biped_large, quadruped_medium, quadruped_small, PhysicsState},
Server, SpawnPoint, StateExt,
rtsim::RtSim, rtsim::RtSim,
Server, SpawnPoint, StateExt,
}; };
use common::{ use common::{
assets::Asset, assets::Asset,
@ -16,12 +16,12 @@ use common::{
lottery::Lottery, lottery::Lottery,
msg::{PlayerListUpdate, ServerGeneral}, msg::{PlayerListUpdate, ServerGeneral},
outcome::Outcome, outcome::Outcome,
rtsim::RtSimEntity,
state::BlockChange, state::BlockChange,
sync::{Uid, UidAllocator, WorldSyncExt}, sync::{Uid, UidAllocator, WorldSyncExt},
terrain::{Block, TerrainGrid}, terrain::{Block, TerrainGrid},
vol::ReadVol, vol::ReadVol,
Damage, DamageSource, Explosion, GroupTarget, RadiusEffect, Damage, DamageSource, Explosion, GroupTarget, RadiusEffect,
rtsim::RtSimEntity,
}; };
use comp::item::Reagent; use comp::item::Reagent;
use rand::prelude::*; use rand::prelude::*;
@ -462,8 +462,16 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
}; };
if should_delete { if should_delete {
if let Some(rtsim_entity) = state.ecs().read_storage::<RtSimEntity>().get(entity).copied() { if let Some(rtsim_entity) = state
state.ecs().write_resource::<RtSim>().destroy_entity(rtsim_entity.0); .ecs()
.read_storage::<RtSimEntity>()
.get(entity)
.copied()
{
state
.ecs()
.write_resource::<RtSim>()
.destroy_entity(rtsim_entity.0);
} }
let _ = state let _ = state

View File

@ -8,8 +8,8 @@ use entity_creation::{
handle_loaded_character_data, handle_shockwave, handle_shoot, handle_loaded_character_data, handle_shockwave, handle_shoot,
}; };
use entity_manipulation::{ use entity_manipulation::{
handle_buff, handle_damage, handle_destroy, handle_delete, handle_energy_change, handle_explosion, handle_buff, handle_damage, handle_delete, handle_destroy, handle_energy_change,
handle_knockback, handle_land_on_ground, handle_level_up, handle_respawn, handle_explosion, handle_knockback, handle_land_on_ground, handle_level_up, handle_respawn,
}; };
use group_manip::handle_group; use group_manip::handle_group;
use interaction::{handle_lantern, handle_mount, handle_possess, handle_unmount}; use interaction::{handle_lantern, handle_mount, handle_possess, handle_unmount};
@ -120,8 +120,18 @@ impl Server {
drop_item, drop_item,
rtsim_entity, rtsim_entity,
} => handle_create_npc( } => handle_create_npc(
self, pos, stats, health, loadout, body, agent, alignment, scale, drop_item, self,
home_chunk, rtsim_entity, pos,
stats,
health,
loadout,
body,
agent,
alignment,
scale,
drop_item,
home_chunk,
rtsim_entity,
), ),
ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos), ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos),
ServerEvent::ClientDisconnect(entity) => { ServerEvent::ClientDisconnect(entity) => {

View File

@ -52,9 +52,7 @@ use common::{
comp::{self, ChatType}, comp::{self, ChatType},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
msg::{ msg::{
world_msg::{SiteInfo, SiteKind}, ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg,
ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg,
WorldMapMsg,
}, },
outcome::Outcome, outcome::Outcome,
recipe::default_recipe_book, recipe::default_recipe_book,
@ -62,7 +60,7 @@ use common::{
state::{State, TimeOfDay}, state::{State, TimeOfDay},
sync::WorldSyncExt, sync::WorldSyncExt,
terrain::TerrainChunkSize, terrain::TerrainChunkSize,
vol::{ReadVol, RectVolSize}, vol::RectVolSize,
}; };
use futures_executor::block_on; use futures_executor::block_on;
use metrics::{PhysicsMetrics, ServerMetrics, StateTickMetrics, TickMetrics}; use metrics::{PhysicsMetrics, ServerMetrics, StateTickMetrics, TickMetrics};
@ -327,7 +325,7 @@ impl Server {
// Insert the world into the ECS (todo: Maybe not an Arc?) // Insert the world into the ECS (todo: Maybe not an Arc?)
let world = Arc::new(world); let world = Arc::new(world);
state.ecs_mut().insert(world.clone()); state.ecs_mut().insert(Arc::clone(&world));
state.ecs_mut().insert(index.clone()); state.ecs_mut().insert(index.clone());
// Set starting time for the server. // Set starting time for the server.

View File

@ -10,9 +10,7 @@ pub struct Chunks {
impl Chunks { impl Chunks {
pub fn new(size: Vec2<u32>) -> Self { pub fn new(size: Vec2<u32>) -> Self {
Chunks { Chunks {
chunks: Grid::populate_from(size.map(|e| e as i32), |_| Chunk { chunks: Grid::populate_from(size.map(|e| e as i32), |_| Chunk { is_loaded: false }),
is_loaded: false,
}),
chunks_to_load: Vec::new(), chunks_to_load: Vec::new(),
chunks_to_unload: Vec::new(), chunks_to_unload: Vec::new(),
} }
@ -25,7 +23,9 @@ impl Chunks {
pub fn chunk_mut(&mut self, key: Vec2<i32>) -> Option<&mut Chunk> { self.chunks.get_mut(key) } pub fn chunk_mut(&mut self, key: Vec2<i32>) -> Option<&mut Chunk> { self.chunks.get_mut(key) }
pub fn chunk_at(&self, pos: Vec2<f32>) -> Option<&Chunk> { pub fn chunk_at(&self, pos: Vec2<f32>) -> Option<&Chunk> {
self.chunks.get(pos.map2(TerrainChunk::RECT_SIZE, |e, sz| (e.floor() as i32).div_euclid(sz as i32))) self.chunks.get(pos.map2(TerrainChunk::RECT_SIZE, |e, sz| {
(e.floor() as i32).div_euclid(sz as i32)
}))
} }
} }

View File

@ -1,16 +1,14 @@
use super::*; use super::*;
use common::event::{EventBus, ServerEvent}; use common::event::{EventBus, ServerEvent};
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect}; use specs::{Read, System, WriteExpect};
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
type SystemData = ( #[allow(clippy::type_complexity)]
Read<'a, EventBus<ServerEvent>>, type SystemData = (Read<'a, EventBus<ServerEvent>>, WriteExpect<'a, RtSim>);
WriteExpect<'a, RtSim>,
);
fn run(&mut self, (server_event_bus, mut rtsim): Self::SystemData) { fn run(&mut self, (_server_event_bus, mut rtsim): Self::SystemData) {
for chunk in std::mem::take(&mut rtsim.chunks.chunks_to_load) { for _chunk in std::mem::take(&mut rtsim.chunks.chunks_to_load) {
// TODO // TODO
} }
} }

View File

@ -1,25 +1,23 @@
mod load_chunks; #![allow(dead_code)] // TODO: Remove this when rtsim is fleshed out
mod unload_chunks;
mod tick;
mod entity;
mod chunks;
use vek::*; mod chunks;
mod entity;
mod load_chunks;
mod tick;
mod unload_chunks;
use self::{chunks::Chunks, entity::Entity};
use common::{ use common::{
comp,
rtsim::{RtSimController, RtSimEntity, RtSimId},
state::State, state::State,
terrain::TerrainChunk, terrain::TerrainChunk,
rtsim::{RtSimEntity, RtSimId, RtSimController},
vol::RectRasterableVol, vol::RectRasterableVol,
comp,
}; };
use specs::{DispatcherBuilder, WorldExt};
use specs_idvs::IdvStorage;
use slab::Slab;
use rand::prelude::*; use rand::prelude::*;
use self::{ use slab::Slab;
entity::Entity, use specs::{DispatcherBuilder, WorldExt};
chunks::Chunks, use vek::*;
};
pub struct RtSim { pub struct RtSim {
tick: u64, tick: u64,
@ -88,12 +86,14 @@ pub fn init(state: &mut State, world: &world::World) {
let mut rtsim = RtSim::new(world.sim().get_size()); let mut rtsim = RtSim::new(world.sim().get_size());
for _ in 0..2500 { for _ in 0..2500 {
let pos = rtsim.chunks.size().map2( let pos = rtsim
TerrainChunk::RECT_SIZE, .chunks
|sz, chunk_sz| thread_rng().gen_range(0, sz * chunk_sz) as i32, .size()
); .map2(TerrainChunk::RECT_SIZE, |sz, chunk_sz| {
thread_rng().gen_range(0, sz * chunk_sz) as i32
});
let id = rtsim.entities.insert(Entity { rtsim.entities.insert(Entity {
is_loaded: false, is_loaded: false,
pos: Vec3::from(pos.map(|e| e as f32)), pos: Vec3::from(pos.map(|e| e as f32)),
seed: thread_rng().gen(), seed: thread_rng().gen(),
@ -101,8 +101,6 @@ pub fn init(state: &mut State, world: &world::World) {
last_tick: 0, last_tick: 0,
brain: Default::default(), brain: Default::default(),
}); });
// tracing::info!("Spawned rtsim NPC {} at {:?}", id, pos);
} }
state.ecs_mut().insert(rtsim); state.ecs_mut().insert(rtsim);

View File

@ -1,3 +1,5 @@
#![allow(dead_code)] // TODO: Remove this when rtsim is fleshed out
use super::*; use super::*;
use common::{ use common::{
comp, comp,
@ -12,6 +14,7 @@ const ENTITY_TICK_PERIOD: u64 = 30;
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
#[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
@ -33,7 +36,7 @@ impl<'a> System<'a> for Sys {
mut rtsim, mut rtsim,
terrain, terrain,
world, world,
index, _index,
positions, positions,
rtsim_entities, rtsim_entities,
mut agents, mut agents,

View File

@ -4,10 +4,11 @@ use common::{
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
terrain::TerrainGrid, terrain::TerrainGrid,
}; };
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteExpect}; use specs::{Entities, Read, ReadExpect, ReadStorage, System, WriteExpect};
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
#[allow(clippy::type_complexity)]
type SystemData = ( type SystemData = (
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
WriteExpect<'a, RtSim>, WriteExpect<'a, RtSim>,
@ -20,17 +21,17 @@ impl<'a> System<'a> for Sys {
fn run( fn run(
&mut self, &mut self,
( (
server_event_bus, _server_event_bus,
mut rtsim, mut rtsim,
terrain_grid, _terrain_grid,
entities, _entities,
rtsim_entities, _rtsim_entities,
positions, _positions,
): Self::SystemData, ): Self::SystemData,
) { ) {
let chunks = std::mem::take(&mut rtsim.chunks.chunks_to_unload); let chunks = std::mem::take(&mut rtsim.chunks.chunks_to_unload);
for chunk in chunks { for _chunk in chunks {
// TODO // TODO
} }
} }

View File

@ -5,7 +5,7 @@ use common::{
use criterion::{black_box, criterion_group, criterion_main, Benchmark, Criterion}; use criterion::{black_box, criterion_group, criterion_main, Benchmark, Criterion};
use std::sync::Arc; use std::sync::Arc;
use vek::*; use vek::*;
use veloren_voxygen::mesh::Meshable; use veloren_voxygen::{mesh::Meshable, scene::terrain::BlocksOfInterest};
use world::{sim, World}; use world::{sim, World};
const CENTER: Vec2<i32> = Vec2 { x: 512, y: 512 }; const CENTER: Vec2<i32> = Vec2 { x: 512, y: 512 };
@ -133,7 +133,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench( c.bench(
"meshing", "meshing",
Benchmark::new(&format!("Terrain mesh {}, {}", x, y), move |b| { Benchmark::new(&format!("Terrain mesh {}, {}", x, y), move |b| {
b.iter(|| volume.generate_mesh(black_box((range, Vec2::new(8192, 8192))))) b.iter(|| volume.generate_mesh(black_box((range, Vec2::new(8192, 8192), &BlocksOfInterest::default()))))
}) })
// Lower sample size to save time // Lower sample size to save time
.sample_size(15), .sample_size(15),

View File

@ -489,11 +489,7 @@ impl<'a> Widget for Map<'a> {
{ {
continue; continue;
} }
let title = let title = site.name.as_deref().unwrap_or_else(|| match &site.kind {
site.name
.as_ref()
.map(|s| s.as_str())
.unwrap_or_else(|| match &site.kind {
SiteKind::Town => i18n.get("hud.map.town"), SiteKind::Town => i18n.get("hud.map.town"),
SiteKind::Dungeon { .. } => i18n.get("hud.map.dungeon"), SiteKind::Dungeon { .. } => i18n.get("hud.map.dungeon"),
SiteKind::Castle => i18n.get("hud.map.castle"), SiteKind::Castle => i18n.get("hud.map.castle"),
@ -656,10 +652,9 @@ impl<'a> Widget for Map<'a> {
Vec2::new(32.0, 37.0) * scale Vec2::new(32.0, 37.0) * scale
}; };
// Hide if icon could go off of the edge of the map // Hide if icon could go off of the edge of the map
let arrow_mag = arrow_sz.map(|e| e as f32 / 2.0).magnitude();
if !rpos if !rpos
.map2(map_size, |e, sz| { .map2(map_size, |e, sz| e.abs() + arrow_mag > sz as f32 / 2.0)
e.abs() + arrow_sz.map(|e| e as f32 / 2.0).magnitude() > sz as f32 / 2.0
})
.reduce_or() .reduce_or()
{ {
Image::new(self.rot_imgs.indicator_mmap_small.target_north) Image::new(self.rot_imgs.indicator_mmap_small.target_north)

View File

@ -2291,7 +2291,7 @@ impl Hud {
// Reset the map position when it's not showing // Reset the map position when it's not showing
let drag = &global_state.settings.gameplay.map_drag; let drag = &global_state.settings.gameplay.map_drag;
if drag.x != 0.0 || drag.y != 0.0 { if drag.x != 0.0 || drag.y != 0.0 {
events.push(Event::MapDrag(drag - drag)) events.push(Event::MapDrag(Vec2::zero()))
} }
} }

View File

@ -586,16 +586,15 @@ fn draw_col_lights<D>(
0.0 0.0
} }
) / 4.0; ) / 4.0;
let glowiness = ( let glowiness = (get_glow(data, light_pos)
get_glow(data, light_pos)
+ get_glow(data, light_pos - uv.x) + get_glow(data, light_pos - uv.x)
+ get_glow(data, light_pos - uv.y) + get_glow(data, light_pos - uv.y)
+ if direct_u_opacity || direct_v_opacity { + if direct_u_opacity || direct_v_opacity {
get_glow(data, light_pos - uv.x - uv.y) get_glow(data, light_pos - uv.x - uv.y)
} else { } else {
0.0 0.0
} })
) / 4.0; / 4.0;
let col = get_color(data, pos); let col = get_color(data, pos);
let light = (darkness * 31.5) as u8; let light = (darkness * 31.5) as u8;
let glow = (glowiness * 31.5) as u8; let glow = (glowiness * 31.5) as u8;

View File

@ -77,7 +77,7 @@ where
0.0 0.0
} }
}; };
let get_glow = |vol: &mut V, pos: Vec3<i32>| 0.0; let get_glow = |_vol: &mut V, _pos: Vec3<i32>| 0.0;
let get_color = |vol: &mut V, pos: Vec3<i32>| { let get_color = |vol: &mut V, pos: Vec3<i32>| {
vol.get(pos) vol.get(pos)
.ok() .ok()

View File

@ -250,6 +250,7 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + 'static>
Meshable<TerrainPipeline, FluidPipeline> for &'a VolGrid2d<V> Meshable<TerrainPipeline, FluidPipeline> for &'a VolGrid2d<V>
{ {
type Pipeline = TerrainPipeline; type Pipeline = TerrainPipeline;
#[allow(clippy::type_complexity)]
type Result = ( type Result = (
Aabb<f32>, Aabb<f32>,
ColLightInfo, ColLightInfo,
@ -468,7 +469,12 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + 'static>
opaque_mesh, opaque_mesh,
fluid_mesh, fluid_mesh,
Mesh::new(), Mesh::new(),
(bounds, (col_lights, col_lights_size), Box::new(light), Box::new(glow)), (
bounds,
(col_lights, col_lights_size),
Box::new(light),
Box::new(glow),
),
) )
} }
} }

View File

@ -115,7 +115,14 @@ impl Vertex {
} }
impl Instance { impl Instance {
pub fn new(mat: Mat4<f32>, wind_sway: f32, pos: Vec3<i32>, ori_bits: u8, light: f32, glow: f32) -> Self { pub fn new(
mat: Mat4<f32>,
wind_sway: f32,
pos: Vec3<i32>,
ori_bits: u8,
light: f32,
glow: f32,
) -> Self {
const EXTRA_NEG_Z: i32 = 32768; const EXTRA_NEG_Z: i32 = 32768;
let mat_arr = mat.into_col_arrays(); let mat_arr = mat.into_col_arrays();

View File

@ -107,23 +107,25 @@ impl Vertex {
) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType ) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType
{ {
//[col.r, col.g, col.b, light] //[col.r, col.g, col.b, light]
// It would be nice for this to be cleaner, but we want to squeeze 5 fields into 4. // It would be nice for this to be cleaner, but we want to squeeze 5 fields into
// We can do this because both `light` and `glow` go from 0 to 31, meaning that they // 4. We can do this because both `light` and `glow` go from 0 to 31,
// can both fit into 5 bits. If we steal a bit from red and blue each (not green, // meaning that they can both fit into 5 bits. If we steal a bit from
// human eyes are more sensitive to changes in green) then we get just enough to // red and blue each (not green, human eyes are more sensitive to
// expand the nibbles of the alpha field enough to fit both `light` and `glow`. // changes in green) then we get just enough to expand the nibbles of
// the alpha field enough to fit both `light` and `glow`.
// //
// However, we now have a problem. In the shader code with use hardware filtering to // However, we now have a problem. In the shader code with use hardware
// get at the `light` and `glow` attributes (but not colour, that remains constant // filtering to get at the `light` and `glow` attributes (but not
// across a block). How do we resolve this if we're twiddling bits? The answer is to // colour, that remains constant across a block). How do we resolve this
// very carefully manipulate the bit pattern such that the fields we want to filter // if we're twiddling bits? The answer is to very carefully manipulate
// (`light` and `glow`) always sit as the higher bits of the fields. Then, we can do // the bit pattern such that the fields we want to filter (`light` and
// `glow`) always sit as the higher bits of the fields. Then, we can do
// some modulation magic to extract them from the filtering unharmed and use // some modulation magic to extract them from the filtering unharmed and use
// unfiltered texture access (i.e: `texelFetch`) to access the colours, plus a little // unfiltered texture access (i.e: `texelFetch`) to access the colours, plus a
// bit-fiddling. // little bit-fiddling.
// //
// TODO: This isn't currently working (no idea why). See `srgb.glsl` for current impl // TODO: This isn't currently working (no idea why). See `srgb.glsl` for current
// that intead does manual bit-twiddling and filtering. // impl that intead does manual bit-twiddling and filtering.
[ [
(light.min(31) << 3) | ((col.r & 0b1110) >> 1), (light.min(31) << 3) | ((col.r & 0b1110) >> 1),
(glow.min(31) << 3) | ((col.r & 0b1110) >> 1), (glow.min(31) << 3) | ((col.r & 0b1110) >> 1),

View File

@ -33,7 +33,8 @@ use tracing::{error, warn};
use vek::*; use vek::*;
/// Represents the format of the pre-processed color target. /// Represents the format of the pre-processed color target.
// TODO: `(gfx::format::R11_G11_B10, gfx::format::Float)` would be better in theory, but it doesn't seem to work // TODO: `(gfx::format::R11_G11_B10, gfx::format::Float)` would be better in
// theory, but it doesn't seem to work
pub type TgtColorFmt = gfx::format::Rgba16F; pub type TgtColorFmt = gfx::format::Rgba16F;
/// Represents the format of the pre-processed depth and stencil target. /// Represents the format of the pre-processed depth and stencil target.
pub type TgtDepthStencilFmt = gfx::format::Depth; pub type TgtDepthStencilFmt = gfx::format::Depth;

View File

@ -12,8 +12,9 @@ use crate::{
}, },
scene::{ scene::{
camera::{Camera, CameraMode, Dependents}, camera::{Camera, CameraMode, Dependents},
math, LodData, SceneData, math,
terrain::Terrain, terrain::Terrain,
LodData, SceneData,
}, },
}; };
use anim::{ use anim::{
@ -3486,7 +3487,8 @@ impl<S: Skeleton> FigureState<S> {
}) })
.unwrap_or((1.0, 0.0)); .unwrap_or((1.0, 0.0));
// Fade between light and glow levels // Fade between light and glow levels
// TODO: Making this temporal rather than spatial is a bit dumb but it's a very subtle difference // TODO: Making this temporal rather than spatial is a bit dumb but it's a very
// subtle difference
self.last_light = vek::Lerp::lerp(self.last_light, light, 16.0 * dt); self.last_light = vek::Lerp::lerp(self.last_light, light, 16.0 * dt);
self.last_glow = vek::Lerp::lerp(self.last_glow, glow, 16.0 * dt); self.last_glow = vek::Lerp::lerp(self.last_glow, glow, 16.0 * dt);

View File

@ -540,7 +540,8 @@ impl Scene {
lights.clear(); lights.clear();
// Maintain the particles. // Maintain the particles.
self.particle_mgr.maintain(renderer, &scene_data, &self.terrain, lights); self.particle_mgr
.maintain(renderer, &scene_data, &self.terrain, lights);
// Update light constants // Update light constants
lights.extend( lights.extend(

View File

@ -2,8 +2,8 @@ use super::{terrain::BlocksOfInterest, SceneData, Terrain};
use crate::{ use crate::{
mesh::{greedy::GreedyMesh, Meshable}, mesh::{greedy::GreedyMesh, Meshable},
render::{ render::{
pipelines::particle::ParticleMode, GlobalModel, Instances, LodData, Model, pipelines::particle::ParticleMode, GlobalModel, Instances, Light, LodData, Model,
ParticleInstance, ParticlePipeline, Renderer, Light, ParticleInstance, ParticlePipeline, Renderer,
}, },
}; };
use common::{ use common::{
@ -73,7 +73,8 @@ impl ParticleMgr {
ParticleMode::EnergyNature, ParticleMode::EnergyNature,
*pos + Vec3::<f32>::zero() *pos + Vec3::<f32>::zero()
.map(|_| rng.gen_range(-1.0, 1.0)) .map(|_| rng.gen_range(-1.0, 1.0))
.normalized() * *radius, .normalized()
* *radius,
) )
}, },
); );
@ -87,7 +88,8 @@ impl ParticleMgr {
ParticleMode::CampfireFire, ParticleMode::CampfireFire,
*pos + Vec3::<f32>::zero() *pos + Vec3::<f32>::zero()
.map(|_| rng.gen_range(-1.0, 1.0)) .map(|_| rng.gen_range(-1.0, 1.0))
.normalized() * *radius, .normalized()
* *radius,
) )
}, },
); );
@ -121,7 +123,8 @@ impl ParticleMgr {
ParticleMode::CampfireSmoke, ParticleMode::CampfireSmoke,
*pos + Vec3::<f32>::zero() *pos + Vec3::<f32>::zero()
.map(|_| rng.gen_range(-1.0, 1.0)) .map(|_| rng.gen_range(-1.0, 1.0))
.normalized() * *radius, .normalized()
* *radius,
) )
}, },
); );
@ -377,11 +380,7 @@ impl ParticleMgr {
if b.stage_section == StageSection::Cast { if b.stage_section == StageSection::Cast {
if b.static_data.base_hps > 0 { if b.static_data.base_hps > 0 {
// Emit a light when using healing // Emit a light when using healing
lights.push(Light::new( lights.push(Light::new(pos.0 + b.offset, Rgb::new(0.1, 1.0, 0.15), 1.0));
pos.0 + b.offset,
Rgb::new(0.1, 1.0, 0.15),
1.0,
));
for i in 0..self.scheduler.heartbeats(Duration::from_millis(1)) { for i in 0..self.scheduler.heartbeats(Duration::from_millis(1)) {
self.particles.push(Particle::new_beam( self.particles.push(Particle::new_beam(
b.static_data.beam_duration, b.static_data.beam_duration,

View File

@ -144,7 +144,11 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + '
span!(_guard, "mesh_worker"); span!(_guard, "mesh_worker");
let blocks_of_interest = BlocksOfInterest::from_chunk(&chunk); let blocks_of_interest = BlocksOfInterest::from_chunk(&chunk);
let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info, light_map, glow_map)) = let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info, light_map, glow_map)) =
volume.generate_mesh((range, Vec2::new(max_texture_size, max_texture_size), &blocks_of_interest)); volume.generate_mesh((
range,
Vec2::new(max_texture_size, max_texture_size),
&blocks_of_interest,
));
MeshWorkerResponse { MeshWorkerResponse {
pos, pos,
z_bounds: (bounds.min.z, bounds.max.z), z_bounds: (bounds.min.z, bounds.max.z),
@ -472,14 +476,24 @@ impl<V: RectRasterableVol> Terrain<V> {
/// Find the light level (sunlight) at the given world position. /// Find the light level (sunlight) at the given world position.
pub fn light_at_wpos(&self, wpos: Vec3<i32>) -> f32 { pub fn light_at_wpos(&self, wpos: Vec3<i32>) -> f32 {
let chunk_pos = Vec2::from(wpos).map2(TerrainChunk::RECT_SIZE, |e: i32, sz| e.div_euclid(sz as i32)); let chunk_pos = Vec2::from(wpos).map2(TerrainChunk::RECT_SIZE, |e: i32, sz| {
self.chunks.get(&chunk_pos).map(|c| (c.light_map)(wpos)).unwrap_or(1.0) e.div_euclid(sz as i32)
});
self.chunks
.get(&chunk_pos)
.map(|c| (c.light_map)(wpos))
.unwrap_or(1.0)
} }
/// Find the glow level (light from lamps) at the given world position. /// Find the glow level (light from lamps) at the given world position.
pub fn glow_at_wpos(&self, wpos: Vec3<i32>) -> f32 { pub fn glow_at_wpos(&self, wpos: Vec3<i32>) -> f32 {
let chunk_pos = Vec2::from(wpos).map2(TerrainChunk::RECT_SIZE, |e: i32, sz| e.div_euclid(sz as i32)); let chunk_pos = Vec2::from(wpos).map2(TerrainChunk::RECT_SIZE, |e: i32, sz| {
self.chunks.get(&chunk_pos).map(|c| (c.glow_map)(wpos)).unwrap_or(0.0) e.div_euclid(sz as i32)
});
self.chunks
.get(&chunk_pos)
.map(|c| (c.glow_map)(wpos))
.unwrap_or(0.0)
} }
/// Maintain terrain data. To be called once per tick. /// Maintain terrain data. To be called once per tick.

View File

@ -6,6 +6,7 @@ use common::{
use rand::prelude::*; use rand::prelude::*;
use vek::*; use vek::*;
#[derive(Default)]
pub struct BlocksOfInterest { pub struct BlocksOfInterest {
pub leaves: Vec<Vec3<i32>>, pub leaves: Vec<Vec3<i32>>,
pub grass: Vec<Vec3<i32>>, pub grass: Vec<Vec3<i32>>,
@ -22,8 +23,6 @@ pub struct BlocksOfInterest {
pub lights: Vec<(Vec3<i32>, u8)>, pub lights: Vec<(Vec3<i32>, u8)>,
} }
use inline_tweak::*;
impl BlocksOfInterest { impl BlocksOfInterest {
pub fn from_chunk(chunk: &TerrainChunk) -> Self { pub fn from_chunk(chunk: &TerrainChunk) -> Self {
span!(_guard, "from_chunk", "BlocksOfInterest::from_chunk"); span!(_guard, "from_chunk", "BlocksOfInterest::from_chunk");
@ -73,8 +72,10 @@ impl BlocksOfInterest {
// Offset positions to account for block height. // Offset positions to account for block height.
// TODO: Is this a good idea? // TODO: Is this a good idea?
Some(SpriteKind::StreetLamp) => fire_bowls.push(pos + Vec3::unit_z() * 2), Some(SpriteKind::StreetLamp) => fire_bowls.push(pos + Vec3::unit_z() * 2),
Some(SpriteKind::FireBowlGround) => fire_bowls.push(pos + Vec3::unit_z() * 1), Some(SpriteKind::FireBowlGround) => fire_bowls.push(pos + Vec3::unit_z()),
Some(SpriteKind::StreetLampTall) => fire_bowls.push(pos + Vec3::unit_z() * 4), Some(SpriteKind::StreetLampTall) => {
fire_bowls.push(pos + Vec3::unit_z() * 4)
},
Some(SpriteKind::Beehive) => beehives.push(pos), Some(SpriteKind::Beehive) => beehives.push(pos),
Some(SpriteKind::Reed) => reeds.push(pos), Some(SpriteKind::Reed) => reeds.push(pos),
Some(SpriteKind::PinkFlower) => flowers.push(pos), Some(SpriteKind::PinkFlower) => flowers.push(pos),

View File

@ -1,4 +1,4 @@
use crate::{column::ColumnSample, sim::SimChunk, util::RandomField, Canvas, CONFIG}; use crate::{column::ColumnSample, sim::SimChunk, Canvas, CONFIG};
use common::terrain::SpriteKind; use common::terrain::SpriteKind;
use noise::NoiseFn; use noise::NoiseFn;
use rand::prelude::*; use rand::prelude::*;

View File

@ -31,6 +31,7 @@ static MODEL_RAND: RandomPerm = RandomPerm::new(0xDB21C052);
static UNIT_CHOOSER: UnitChooser = UnitChooser::new(0x700F4EC7); static UNIT_CHOOSER: UnitChooser = UnitChooser::new(0x700F4EC7);
static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F); static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F);
#[allow(clippy::if_same_then_else)]
pub fn apply_trees_to(canvas: &mut Canvas) { pub fn apply_trees_to(canvas: &mut Canvas) {
struct Tree { struct Tree {
pos: Vec3<i32>, pos: Vec3<i32>,
@ -51,15 +52,17 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
let is_quirky = QUIRKY_RAND.chance(seed, 1.0 / 500.0); let is_quirky = QUIRKY_RAND.chance(seed, 1.0 / 500.0);
// Ensure that it's valid to place a tree here // Ensure that it's valid to place a *thing* here
if col.alt < col.water_level if col.alt < col.water_level
|| col.spawn_rate < 0.9 || col.spawn_rate < 0.9
|| col.water_dist.map(|d| d < 8.0).unwrap_or(false) || col.water_dist.map(|d| d < 8.0).unwrap_or(false)
|| col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false) || col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false)
{ {
return None; return None;
} else if !is_quirky }
&& ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density
// Ensure that it's valid to place a tree here
if !is_quirky && ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density
{ {
return None; return None;
} }

View File

@ -182,10 +182,20 @@ impl World {
}; };
let meta = TerrainChunkMeta::new( let meta = TerrainChunkMeta::new(
sim_chunk.sites sim_chunk
.sites
.iter() .iter()
.filter(|id| index.sites[**id].get_origin().distance_squared(chunk_center_wpos2d) as f32 <= index.sites[**id].radius().powf(2.0)) .filter(|id| {
.min_by_key(|id| index.sites[**id].get_origin().distance_squared(chunk_center_wpos2d)) index.sites[**id]
.get_origin()
.distance_squared(chunk_center_wpos2d) as f32
<= index.sites[**id].radius().powf(2.0)
})
.min_by_key(|id| {
index.sites[**id]
.get_origin()
.distance_squared(chunk_center_wpos2d)
})
.map(|id| index.sites[*id].name().to_string()), .map(|id| index.sites[*id].name().to_string()),
sim_chunk.get_biome(), sim_chunk.get_biome(),
sim_chunk.alt, sim_chunk.alt,

View File

@ -1,11 +1,9 @@
use crate::sim::WorldSim; use crate::sim::WorldSim;
use common::{ use common::path::Path;
astar::Astar, //use hashbrown::hash_map::DefaultHashBuilder;
path::Path,
};
use hashbrown::hash_map::DefaultHashBuilder;
use vek::*; use vek::*;
#[allow(dead_code)]
pub struct SearchCfg { pub struct SearchCfg {
// 0.0 = no discount, 1.0 = free travel // 0.0 = no discount, 1.0 = free travel
path_discount: f32, path_discount: f32,
@ -14,15 +12,19 @@ pub struct SearchCfg {
gradient_aversion: f32, gradient_aversion: f32,
} }
#[allow(dead_code)]
pub struct Searcher<'a> { pub struct Searcher<'a> {
land: &'a WorldSim, land: &'a WorldSim,
pub cfg: SearchCfg, pub cfg: SearchCfg,
} }
#[allow(dead_code)]
impl<'a> Searcher<'a> { impl<'a> Searcher<'a> {
/// Attempt to find a path between two chunks on the map. /// Attempt to find a path between two chunks on the map.
pub fn search(self, a: Vec2<i32>, b: Vec2<i32>) -> Option<Path<i32>> { pub fn search(self, _a: Vec2<i32>, _b: Vec2<i32>) -> Option<Path<i32>> {
let heuristic = |pos: &Vec2<i32>| (pos - b).map(|e| e as f32).magnitude(); // TODO: implement this function
//let heuristic = |pos: &Vec2<i32>| (pos - b).map(|e| e as f32).magnitude();
// Astar::new( // Astar::new(
// 100_000, // 100_000,
// a, // a,

View File

@ -103,7 +103,7 @@ pub fn sample_pos(
spline_derivative, spline_derivative,
is_path, is_path,
is_cave, is_cave,
near_site, _near_site,
) = sampler ) = sampler
.get(pos) .get(pos)
.map(|sample| { .map(|sample| {

View File

@ -3,11 +3,11 @@ use crate::{
column::ColumnSample, column::ColumnSample,
sim::WorldSim, sim::WorldSim,
site::{ site::{
namegen::NameGen,
settlement::building::{ settlement::building::{
archetype::keep::{Attr, FlagColor, Keep as KeepArchetype, StoneColor}, archetype::keep::{Attr, FlagColor, Keep as KeepArchetype, StoneColor},
Archetype, Ori, Archetype, Ori,
}, },
namegen::NameGen,
}, },
IndexRef, IndexRef,
}; };
@ -156,9 +156,7 @@ impl Castle {
this this
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str { &self.name }
&self.name
}
pub fn contains_point(&self, wpos: Vec2<i32>) -> bool { pub fn contains_point(&self, wpos: Vec2<i32>) -> bool {
let lpos = wpos - self.origin; let lpos = wpos - self.origin;

View File

@ -48,8 +48,6 @@ pub struct Colors {
const ALT_OFFSET: i32 = -2; const ALT_OFFSET: i32 = -2;
const LEVELS: usize = 5;
impl Dungeon { impl Dungeon {
#[allow(clippy::let_and_return)] // TODO: Pending review in #587 #[allow(clippy::let_and_return)] // TODO: Pending review in #587
pub fn generate(wpos: Vec2<i32>, sim: Option<&WorldSim>, rng: &mut impl Rng) -> Self { pub fn generate(wpos: Vec2<i32>, sim: Option<&WorldSim>, rng: &mut impl Rng) -> Self {
@ -321,7 +319,10 @@ impl Floor {
enemy_density: Some((0.0002 * difficulty as f32).min(0.001)), // Minions! enemy_density: Some((0.0002 * difficulty as f32).min(0.001)), // Minions!
miniboss: false, miniboss: false,
boss: true, boss: true,
area: Rect::from((new_stair_tile - tile_offset - 4, Extent2::broadcast(width as i32 * 2 + 1))), area: Rect::from((
new_stair_tile - tile_offset - 4,
Extent2::broadcast(width as i32 * 2 + 1),
)),
height: height as i32, height: height as i32,
pillars: Some(2), pillars: Some(2),
difficulty, difficulty,
@ -482,6 +483,8 @@ impl Floor {
origin: Vec3<i32>, origin: Vec3<i32>,
supplement: &mut ChunkSupplement, supplement: &mut ChunkSupplement,
) { ) {
/*
// Add stair waypoint
let stair_rcenter = let stair_rcenter =
Vec3::from((self.stair_tile + self.tile_offset).map(|e| e * TILE_SIZE + TILE_SIZE / 2)); Vec3::from((self.stair_tile + self.tile_offset).map(|e| e * TILE_SIZE + TILE_SIZE / 2));
@ -493,13 +496,14 @@ impl Floor {
.try_normalized() .try_normalized()
.unwrap_or_else(Vec2::unit_y) .unwrap_or_else(Vec2::unit_y)
* (TILE_SIZE as f32 / 2.0 - 4.0); * (TILE_SIZE as f32 / 2.0 - 4.0);
// if !self.final_level { if !self.final_level {
// supplement.add_entity( supplement.add_entity(
// EntityInfo::at((origin + stair_rcenter).map(|e| e as f32) EntityInfo::at((origin + stair_rcenter).map(|e| e as f32)
// + Vec3::from(offs)) .into_waypoint(), + Vec3::from(offs)) .into_waypoint(),
// ); );
// }
} }
}
*/
for x in area.min.x..area.max.x { for x in area.min.x..area.max.x {
for y in area.min.y..area.max.y { for y in area.min.y..area.max.y {
@ -601,11 +605,11 @@ impl Floor {
(room.difficulty as f32).powf(1.5) + 4.0, (room.difficulty as f32).powf(1.5) + 4.0,
).round() as u32); ).round() as u32);
let entity = match room.difficulty { let entity = match room.difficulty {
0 => entity.with_name("Outcast") 0 => entity
.with_name("Outcast")
.with_config(common::loadout_builder::LoadoutConfig::Outcast) .with_config(common::loadout_builder::LoadoutConfig::Outcast)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
0 => "common.items.weapons.axe.starter_axe", 0 => "common.items.weapons.axe.starter_axe",
1 => "common.items.weapons.sword.starter_sword", 1 => "common.items.weapons.sword.starter_sword",
@ -614,13 +618,12 @@ impl Floor {
4 => "common.items.weapons.staff.starter_staff", 4 => "common.items.weapons.staff.starter_staff",
_ => "common.items.weapons.bow.starter_bow", _ => "common.items.weapons.bow.starter_bow",
}, },
), )),
), 1 => entity
1 => entity.with_name("Highwayman") .with_name("Highwayman")
.with_config(common::loadout_builder::LoadoutConfig::Highwayman) .with_config(common::loadout_builder::LoadoutConfig::Highwayman)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
0 => "common.items.weapons.axe.worn_iron_axe-0", 0 => "common.items.weapons.axe.worn_iron_axe-0",
1 => "common.items.weapons.sword.zweihander_sword_0", 1 => "common.items.weapons.sword.zweihander_sword_0",
@ -629,13 +632,12 @@ impl Floor {
4 => "common.items.weapons.staff.bone_staff", 4 => "common.items.weapons.staff.bone_staff",
_ => "common.items.weapons.bow.wood_shortbow-1", _ => "common.items.weapons.bow.wood_shortbow-1",
}, },
), )),
), 2 => entity
2 => entity.with_name("Bandit") .with_name("Bandit")
.with_config(common::loadout_builder::LoadoutConfig::Bandit) .with_config(common::loadout_builder::LoadoutConfig::Bandit)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
0 => "common.items.weapons.axe.bronze_axe-0", 0 => "common.items.weapons.axe.bronze_axe-0",
1 => "common.items.weapons.sword.greatsword_2h_simple-0", 1 => "common.items.weapons.sword.greatsword_2h_simple-0",
@ -644,13 +646,12 @@ impl Floor {
4 => "common.items.weapons.staff.bone_staff", 4 => "common.items.weapons.staff.bone_staff",
_ => "common.items.weapons.bow.wood_longbow-0", _ => "common.items.weapons.bow.wood_longbow-0",
}, },
), )),
), 3 => entity
3 => entity.with_name("Cultist Novice") .with_name("Cultist Novice")
.with_config(common::loadout_builder::LoadoutConfig::CultistNovice) .with_config(common::loadout_builder::LoadoutConfig::CultistNovice)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
0 => "common.items.weapons.axe.steel_axe-0", 0 => "common.items.weapons.axe.steel_axe-0",
1 => "common.items.weapons.sword.long_2h_orn-0", 1 => "common.items.weapons.sword.long_2h_orn-0",
@ -659,13 +660,12 @@ impl Floor {
4 => "common.items.weapons.staff.amethyst_staff", 4 => "common.items.weapons.staff.amethyst_staff",
_ => "common.items.weapons.bow.horn_longbow-0", _ => "common.items.weapons.bow.horn_longbow-0",
}, },
), )),
), 4 => entity
4 => entity.with_name("Cultist Acolyte") .with_name("Cultist Acolyte")
.with_config(common::loadout_builder::LoadoutConfig::CultistAcolyte) .with_config(common::loadout_builder::LoadoutConfig::CultistAcolyte)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
0 => "common.items.weapons.axe.malachite_axe-0", 0 => "common.items.weapons.axe.malachite_axe-0",
1 => "common.items.weapons.sword.cultist_purp_2h-0", 1 => "common.items.weapons.sword.cultist_purp_2h-0",
@ -674,20 +674,20 @@ impl Floor {
4 => "common.items.weapons.staff.cultist_staff", 4 => "common.items.weapons.staff.cultist_staff",
_ => "common.items.weapons.bow.horn_longbow-0", _ => "common.items.weapons.bow.horn_longbow-0",
}, },
), )),
),
5 => match dynamic_rng.gen_range(0, 6) { 5 => match dynamic_rng.gen_range(0, 6) {
0 => entity.with_name("Cultist Warlock") 0 => entity
.with_name("Cultist Warlock")
.with_config(common::loadout_builder::LoadoutConfig::Warlock) .with_config(common::loadout_builder::LoadoutConfig::Warlock)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect("common.items.npc_weapons.staff.cultist_staff"), "common.items.npc_weapons.staff.cultist_staff",
), )),
_ => entity.with_name("Cultist Warlord") _ => entity
.with_name("Cultist Warlord")
.with_config(common::loadout_builder::LoadoutConfig::Warlord) .with_config(common::loadout_builder::LoadoutConfig::Warlord)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 5) { match dynamic_rng.gen_range(0, 5) {
0 => "common.items.weapons.axe.malachite_axe-0", 0 => "common.items.weapons.axe.malachite_axe-0",
1 => "common.items.weapons.sword.cultist_purp_2h-0", 1 => "common.items.weapons.sword.cultist_purp_2h-0",
@ -695,8 +695,7 @@ impl Floor {
3 => "common.items.weapons.hammer.cultist_purp_2h-0", 3 => "common.items.weapons.hammer.cultist_purp_2h-0",
_ => "common.items.weapons.bow.horn_longbow-0", _ => "common.items.weapons.bow.horn_longbow-0",
}, },
), )),
),
}, },
_ => entity.with_name("Humanoid").with_main_tool( _ => entity.with_name("Humanoid").with_main_tool(
comp::Item::new_from_asset_expect( comp::Item::new_from_asset_expect(
@ -723,64 +722,88 @@ impl Floor {
if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d { if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d {
let chosen = match room.difficulty { let chosen = match room.difficulty {
0 => Lottery::<String>::load_expect("common.loot_tables.loot_table_weapon_uncommon"), 0 => Lottery::<String>::load_expect(
1 => Lottery::<String>::load_expect("common.loot_tables.loot_table_weapon_uncommon"), "common.loot_tables.loot_table_weapon_uncommon",
2 => Lottery::<String>::load_expect("common.loot_tables.loot_table_armor_heavy"), ),
3 => Lottery::<String>::load_expect("common.loot_tables.loot_table_weapon_rare"), 1 => Lottery::<String>::load_expect(
4 => Lottery::<String>::load_expect("common.loot_tables.loot_table_boss_cultist-leader"), "common.loot_tables.loot_table_weapon_uncommon",
5 => Lottery::<String>::load_expect("common.loot_tables.loot_table_boss_cultist-leader"), ),
2 => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_armor_heavy",
),
3 => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_weapon_rare",
),
4 => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_boss_cultist-leader",
),
5 => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_boss_cultist-leader",
),
_ => Lottery::<String>::load_expect( _ => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_armor_misc", "common.loot_tables.loot_table_armor_misc",
), ),
}; };
let chosen = chosen.choose(); let chosen = chosen.choose();
let entity = let entity = match room.difficulty {
match room.difficulty { 0 => vec![
0 => EntityInfo::at(tile_wcenter.map(|e| e as f32))
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) .with_body(comp::Body::Humanoid(
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random())) comp::humanoid::Body::random(),
))
.with_name("Outcast Leader".to_string()) .with_name("Outcast Leader".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_config(common::loadout_builder::LoadoutConfig::Outcast) .with_config(
common::loadout_builder::LoadoutConfig::Outcast,
)
.with_scale(2.0) .with_scale(2.0)
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
0 => "common.items.weapons.axe.worn_iron_axe-0", 0 => "common.items.weapons.axe.worn_iron_axe-0",
1 => "common.items.weapons.sword.zweihander_sword_0", 1 => {
2 => "common.items.weapons.sword.zweihander_sword_0", "common.items.weapons.sword.zweihander_sword_0"
3 => "common.items.weapons.hammer.worn_iron_hammer-0", },
2 => {
"common.items.weapons.sword.zweihander_sword_0"
},
3 => {
"common.items.weapons.hammer.worn_iron_hammer-0"
},
4 => "common.items.weapons.staff.bone_staff", 4 => "common.items.weapons.staff.bone_staff",
_ => "common.items.weapons.bow.wood_shortbow-1", _ => "common.items.weapons.bow.wood_shortbow-1",
}, },
), )),
),
EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with( .with_body(comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::quadruped_medium::Species::Tarasque, &comp::quadruped_medium::Species::Tarasque,
))) ),
))
.with_name("Tarasque".to_string()) .with_name("Tarasque".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
1 => 1 => vec![
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::Theropod(comp::theropod::Body::random_with( .with_body(comp::Body::Theropod(
comp::theropod::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::theropod::Species::Odonto, &comp::theropod::Species::Odonto,
))) ),
))
.with_name("Odonto".to_string()) .with_name("Odonto".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
2 => 2 => vec![
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random())) .with_body(comp::Body::Humanoid(
comp::humanoid::Body::random()
))
.with_name("Bandit Captain".to_string()) .with_name("Bandit Captain".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_config(common::loadout_builder::LoadoutConfig::Bandit) .with_config(common::loadout_builder::LoadoutConfig::Bandit)
.with_scale(2.0) .with_scale(2.0)
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
0 => "common.items.weapons.axe.steel_axe-0", 0 => "common.items.weapons.axe.steel_axe-0",
1 => "common.items.weapons.sword.long_2h_orn-0", 1 => "common.items.weapons.sword.long_2h_orn-0",
@ -789,10 +812,10 @@ impl Floor {
4 => "common.items.weapons.staff.amethyst_staff", 4 => "common.items.weapons.staff.amethyst_staff",
_ => "common.items.weapons.bow.horn_longbow-0", _ => "common.items.weapons.bow.horn_longbow-0",
}, },
), ),);
) 2
; 2], ],
3 => 3 => {
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random())) .with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
.with_name("Cultist Acolyte".to_string()) .with_name("Cultist Acolyte".to_string())
@ -811,42 +834,53 @@ impl Floor {
}, },
), ),
) )
; 2], ; 2]
4 => },
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) 4 => vec![
.with_body(comp::Body::Golem(comp::golem::Body::random_with( EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::Golem(
comp::golem::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::golem::Species::StoneGolem, &comp::golem::Species::StoneGolem,
))) ),
))
.with_name("Stonework Defender".to_string()) .with_name("Stonework Defender".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
5 => 5 => vec![
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::BipedLarge(comp::biped_large::Body::random_with( .with_body(comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::biped_large::Species::Mindflayer, &comp::biped_large::Species::Mindflayer,
))) ),
))
.with_name("Mindflayer".to_string()) .with_name("Mindflayer".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
_ => _ => {
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) vec![EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_body(
.with_body(comp::Body::QuadrupedSmall(comp::quadruped_small::Body::random_with( comp::Body::QuadrupedSmall(
comp::quadruped_small::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::quadruped_small::Species::Sheep, &comp::quadruped_small::Species::Sheep,
))), ),
], ),
)]
},
}; };
for entity in entity { for entity in entity {
supplement.add_entity(entity.with_level( supplement.add_entity(
entity
.with_level(
dynamic_rng dynamic_rng
.gen_range( .gen_range(
(room.difficulty as f32).powf(1.25) + 3.0, (room.difficulty as f32).powf(1.25) + 3.0,
(room.difficulty as f32).powf(1.5) + 4.0, (room.difficulty as f32).powf(1.5) + 4.0,
) )
.round() as u32 .round()
as u32
* 5, * 5,
) )
.with_alignment(comp::Alignment::Enemy), .with_alignment(comp::Alignment::Enemy),
@ -870,115 +904,153 @@ impl Floor {
if tile_pos == miniboss_spawn_tile && tile_wcenter.xy() == wpos2d { if tile_pos == miniboss_spawn_tile && tile_wcenter.xy() == wpos2d {
let chosen = match room.difficulty { let chosen = match room.difficulty {
0 => Lottery::<String>::load_expect("common.loot_tables.loot_table_animal_parts"), 0 => Lottery::<String>::load_expect(
1 => Lottery::<String>::load_expect("common.loot_tables.loot_table_animal_parts"), "common.loot_tables.loot_table_animal_parts",
2 => Lottery::<String>::load_expect("common.loot_tables.loot_table_animal_parts"), ),
3 => Lottery::<String>::load_expect("common.loot_tables.loot_table_weapon_rare"), 1 => Lottery::<String>::load_expect(
4 => Lottery::<String>::load_expect("common.loot_tables.loot_table_weapon_rare"), "common.loot_tables.loot_table_animal_parts",
5 => Lottery::<String>::load_expect("common.loot_tables.loot_table_boss_cultist-leader"), ),
2 => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_animal_parts",
),
3 => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_weapon_rare",
),
4 => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_weapon_rare",
),
5 => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_boss_cultist-leader",
),
_ => Lottery::<String>::load_expect( _ => Lottery::<String>::load_expect(
"common.loot_tables.loot_table_armor_misc", "common.loot_tables.loot_table_armor_misc",
), ),
}; };
let chosen = chosen.choose(); let chosen = chosen.choose();
let entity = let entity = match room.difficulty {
match room.difficulty { 0 => vec![
0 => EntityInfo::at(tile_wcenter.map(|e| e as f32))
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) .with_body(comp::Body::QuadrupedMedium(
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with( comp::quadruped_medium::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::quadruped_medium::Species::Bonerattler, &comp::quadruped_medium::Species::Bonerattler,
))) ),
))
.with_name("Bonerattler".to_string()) .with_name("Bonerattler".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
1 => 1 => vec![
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with( .with_body(comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::quadruped_medium::Species::Bonerattler, &comp::quadruped_medium::Species::Bonerattler,
))) )
))
.with_name("Bonerattler".to_string()) .with_name("Bonerattler".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(
; 3], chosen
2 => ));
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) 3
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with( ],
2 => vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::quadruped_medium::Species::Tarasque, &comp::quadruped_medium::Species::Tarasque,
))) ),
))
.with_name("Tarasque".to_string()) .with_name("Tarasque".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
3 => 3 => vec![
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random())) .with_body(comp::Body::Humanoid(
comp::humanoid::Body::random(),
))
.with_name("Animal Trainer".to_string()) .with_name("Animal Trainer".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_config(common::loadout_builder::LoadoutConfig::CultistAcolyte) .with_config(
common::loadout_builder::LoadoutConfig::CultistAcolyte,
)
.with_scale(2.0) .with_scale(2.0)
.with_main_tool( .with_main_tool(comp::Item::new_from_asset_expect(
comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
0 => "common.items.weapons.axe.malachite_axe-0", 0 => "common.items.weapons.axe.malachite_axe-0",
1 => "common.items.weapons.sword.cultist_purp_2h-0", 1 => "common.items.weapons.sword.cultist_purp_2h-0",
2 => "common.items.weapons.sword.cultist_purp_2h-0", 2 => "common.items.weapons.sword.cultist_purp_2h-0",
3 => "common.items.weapons.hammer.cultist_purp_2h-0", 3 => {
"common.items.weapons.hammer.cultist_purp_2h-0"
},
4 => "common.items.weapons.staff.cultist_staff", 4 => "common.items.weapons.staff.cultist_staff",
_ => "common.items.weapons.bow.horn_longbow-0", _ => "common.items.weapons.bow.horn_longbow-0",
}, },
), )),
),
EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with( .with_body(comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::quadruped_medium::Species::Wolf, &comp::quadruped_medium::Species::Wolf,
))) ),
))
.with_name("Tamed Wolf".to_string()) .with_name("Tamed Wolf".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with( .with_body(comp::Body::QuadrupedMedium(
comp::quadruped_medium::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::quadruped_medium::Species::Wolf, &comp::quadruped_medium::Species::Wolf,
))) ),
))
.with_name("Tamed Wolf".to_string()) .with_name("Tamed Wolf".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
4 => 4 => vec![
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::BipedLarge(comp::biped_large::Body::random_with( .with_body(comp::Body::BipedLarge(
comp::biped_large::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::biped_large::Species::Dullahan, &comp::biped_large::Species::Dullahan,
))) ),
))
.with_name("Dullahan Guard".to_string()) .with_name("Dullahan Guard".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
5 => 5 => vec![
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) EntityInfo::at(tile_wcenter.map(|e| e as f32))
.with_body(comp::Body::Golem(comp::golem::Body::random_with( .with_body(comp::Body::Golem(
comp::golem::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::golem::Species::StoneGolem, &comp::golem::Species::StoneGolem,
))) ),
))
.with_name("Stonework Defender".to_string()) .with_name("Stonework Defender".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)), .with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
], ],
_ => _ => {
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32)) vec![EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_body(
.with_body(comp::Body::QuadrupedSmall(comp::quadruped_small::Body::random_with( comp::Body::QuadrupedSmall(
comp::quadruped_small::Body::random_with(
dynamic_rng, dynamic_rng,
&comp::quadruped_small::Species::Sheep, &comp::quadruped_small::Species::Sheep,
))), ),
], ),
)]
},
}; };
for entity in entity { for entity in entity {
supplement.add_entity(entity.with_level( supplement.add_entity(
entity
.with_level(
dynamic_rng dynamic_rng
.gen_range( .gen_range(
(room.difficulty as f32).powf(1.25) + 3.0, (room.difficulty as f32).powf(1.25) + 3.0,
(room.difficulty as f32).powf(1.5) + 4.0, (room.difficulty as f32).powf(1.5) + 4.0,
) )
.round() as u32 .round()
as u32
* 5, * 5,
) )
.with_alignment(comp::Alignment::Enemy), .with_alignment(comp::Alignment::Enemy),

View File

@ -1,8 +1,8 @@
mod block_mask; mod block_mask;
mod castle; mod castle;
mod dungeon; mod dungeon;
mod namegen;
pub mod economy; pub mod economy;
mod namegen;
mod settlement; mod settlement;
// Reexports // Reexports

View File

@ -17,13 +17,14 @@ impl<'a, R: Rng> NameGen<'a, R> {
pub fn generate(self) -> String { pub fn generate(self) -> String {
let cons = vec![ let cons = vec![
"d", "f", "ph", "r", "st", "t", "s", "p", "sh", "th", "br", "tr", "m", "k", "st", "w", "y", "d", "f", "ph", "r", "st", "t", "s", "p", "sh", "th", "br", "tr", "m", "k", "st", "w",
"cr", "fr", "dr", "pl", "wr", "sn", "g", "qu", "l", "y", "cr", "fr", "dr", "pl", "wr", "sn", "g", "qu", "l",
]; ];
let mut start = cons.clone(); let mut start = cons.clone();
start.extend(vec![ start.extend(vec![
"cr", "thr", "str", "br", "iv", "est", "ost", "ing", "kr", "in", "on", "tr", "tw", "wh", "cr", "thr", "str", "br", "iv", "est", "ost", "ing", "kr", "in", "on", "tr", "tw",
"eld", "ar", "or", "ear", "irr", "mi", "en", "ed", "et", "ow", "fr", "shr", "wr", "gr", "pr", "wh", "eld", "ar", "or", "ear", "irr", "mi", "en", "ed", "et", "ow", "fr", "shr", "wr",
"gr", "pr",
]); ]);
let mut middle = cons.clone(); let mut middle = cons.clone();
middle.extend(vec!["tt"]); middle.extend(vec!["tt"]);
@ -43,14 +44,9 @@ impl<'a, R: Rng> NameGen<'a, R> {
} }
name += end.choose(self.rng).unwrap(); name += end.choose(self.rng).unwrap();
name name.chars()
.chars()
.enumerate() .enumerate()
.map(|(i, c)| if i == 0 { .map(|(i, c)| if i == 0 { c.to_ascii_uppercase() } else { c })
c.to_ascii_uppercase()
} else {
c
})
.collect() .collect()
} }
} }

View File

@ -9,8 +9,8 @@ use super::SpawnRules;
use crate::{ use crate::{
column::ColumnSample, column::ColumnSample,
sim::WorldSim, sim::WorldSim,
util::{RandomField, Sampler, StructureGen2d},
site::namegen::NameGen, site::namegen::NameGen,
util::{RandomField, Sampler, StructureGen2d},
IndexRef, IndexRef,
}; };
use common::{ use common::{
@ -188,9 +188,7 @@ impl Settlement {
this this
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str { &self.name }
&self.name
}
pub fn get_origin(&self) -> Vec2<i32> { self.origin } pub fn get_origin(&self) -> Vec2<i32> { self.origin }
@ -921,13 +919,15 @@ impl Settlement {
.do_if(is_dummy, |e| e.with_name("Training Dummy")) .do_if(is_dummy, |e| e.with_name("Training Dummy"))
.do_if(is_human && dynamic_rng.gen(), |entity| { .do_if(is_human && dynamic_rng.gen(), |entity| {
match dynamic_rng.gen_range(0, 5) { match dynamic_rng.gen_range(0, 5) {
0 => entity.with_main_tool(Item::new_from_asset_expect( 0 => entity
.with_main_tool(Item::new_from_asset_expect(
"common.items.weapons.sword.greatsword_2h_simple-0", "common.items.weapons.sword.greatsword_2h_simple-0",
)) ))
.with_name("Guard") .with_name("Guard")
.with_level(dynamic_rng.gen_range(10, 15)) .with_level(dynamic_rng.gen_range(10, 15))
.with_config(common::loadout_builder::LoadoutConfig::Guard), .with_config(common::loadout_builder::LoadoutConfig::Guard),
_ => entity.with_main_tool(Item::new_from_asset_expect( _ => entity
.with_main_tool(Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 7) { match dynamic_rng.gen_range(0, 7) {
0 => "common.items.npc_weapons.tool.broom", 0 => "common.items.npc_weapons.tool.broom",
1 => "common.items.npc_weapons.tool.hoe", 1 => "common.items.npc_weapons.tool.hoe",
@ -939,7 +939,7 @@ impl Settlement {
//_ => "common.items.npc_weapons.bow.starter_bow", TODO: Re-Add this when we have a better way of distributing npc_weapons here //_ => "common.items.npc_weapons.bow.starter_bow", TODO: Re-Add this when we have a better way of distributing npc_weapons here
}, },
)) ))
.with_config(common::loadout_builder::LoadoutConfig::Villager) .with_config(common::loadout_builder::LoadoutConfig::Villager),
} }
}); });