mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Fmt, make clippy happy
This commit is contained in:
parent
6215682619
commit
26fd40c0e3
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
comp::{humanoid, quadruped_low, quadruped_medium, quadruped_small, Body},
|
||||
path::Chaser,
|
||||
sync::Uid,
|
||||
rtsim::RtSimController,
|
||||
sync::Uid,
|
||||
};
|
||||
use specs::{Component, Entity as EcsEntity};
|
||||
use specs_idvs::IdvStorage;
|
||||
|
@ -1,11 +1,4 @@
|
||||
use crate::{
|
||||
character::CharacterId,
|
||||
sync::Uid,
|
||||
util::Dir,
|
||||
comp,
|
||||
Explosion,
|
||||
rtsim::RtSimEntity,
|
||||
};
|
||||
use crate::{character::CharacterId, comp, rtsim::RtSimEntity, sync::Uid, util::Dir, Explosion};
|
||||
use comp::{
|
||||
item::{Item, Reagent},
|
||||
Ori, Pos,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{self, humanoid, Alignment, Body, Item},
|
||||
npc::{self, NPC_NAMES},
|
||||
loadout_builder::LoadoutConfig,
|
||||
npc::{self, NPC_NAMES},
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
|
@ -88,7 +88,7 @@ impl LoadoutBuilder {
|
||||
#[allow(clippy::single_match)]
|
||||
pub fn build_loadout(
|
||||
body: Body,
|
||||
alignment: Alignment,
|
||||
_alignment: Alignment,
|
||||
mut main_tool: Option<Item>,
|
||||
is_giant: bool,
|
||||
map: &AbilityMap,
|
||||
@ -410,13 +410,11 @@ impl LoadoutBuilder {
|
||||
back: None,
|
||||
ring: None,
|
||||
neck: None,
|
||||
lantern: Some(Item::new_from_asset_expect(
|
||||
"common.items.lantern.black_0",
|
||||
)),
|
||||
lantern: Some(Item::new_from_asset_expect("common.items.lantern.black_0")),
|
||||
glider: None,
|
||||
head: None,
|
||||
tabard: None,
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
match body {
|
||||
|
@ -130,7 +130,8 @@ impl Route {
|
||||
|
||||
// Determine whether we're close enough to the next to to consider it completed
|
||||
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 < 2.9 && vel.z < -0.05))
|
||||
&& vel.z <= 0.0
|
||||
@ -142,7 +143,9 @@ impl Route {
|
||||
.0
|
||||
> pos.distance(closest_tgt) * 0.9 || dist_sqrd < 0.5)
|
||||
&& 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
|
||||
self.next_idx += 1;
|
||||
@ -438,15 +441,14 @@ fn walkable<V>(vol: &V, pos: Vec3<i32>) -> bool
|
||||
where
|
||||
V: BaseVol<Vox = Block> + ReadVol,
|
||||
{
|
||||
let below = vol.get(pos - Vec3::unit_z())
|
||||
let below = vol
|
||||
.get(pos - Vec3::unit_z())
|
||||
.ok()
|
||||
.copied()
|
||||
.unwrap_or_else(Block::empty);
|
||||
let a = vol.get(pos)
|
||||
.ok()
|
||||
.copied()
|
||||
.unwrap_or_else(Block::empty);
|
||||
let b = vol.get(pos + Vec3::unit_z())
|
||||
let a = vol.get(pos).ok().copied().unwrap_or_else(Block::empty);
|
||||
let b = vol
|
||||
.get(pos + Vec3::unit_z())
|
||||
.ok()
|
||||
.copied()
|
||||
.unwrap_or_else(Block::empty);
|
||||
@ -513,10 +515,10 @@ where
|
||||
];
|
||||
|
||||
const JUMPS: [Vec3<i32>; 4] = [
|
||||
Vec3::new(0, 1, 2), // Forward Upwardx2
|
||||
Vec3::new(1, 0, 2), // Right Upwardx2
|
||||
Vec3::new(0, -1, 2), // Backward Upwardx2
|
||||
Vec3::new(-1, 0, 2), // Left Upwardx2
|
||||
Vec3::new(0, 1, 2), // Forward Upwardx2
|
||||
Vec3::new(1, 0, 2), // Right Upwardx2
|
||||
Vec3::new(0, -1, 2), // Backward Upwardx2
|
||||
Vec3::new(-1, 0, 2), // Left Upwardx2
|
||||
];
|
||||
|
||||
// let walkable = [
|
||||
@ -538,13 +540,15 @@ where
|
||||
// ];
|
||||
|
||||
DIRS.iter()
|
||||
.chain(Some(JUMPS.iter())
|
||||
.filter(|_| vol
|
||||
.get(pos)
|
||||
.map(|b| !b.is_liquid())
|
||||
.unwrap_or(true) || traversal_cfg.can_climb)
|
||||
.into_iter()
|
||||
.flatten())
|
||||
.chain(
|
||||
Some(JUMPS.iter())
|
||||
.filter(|_| {
|
||||
vol.get(pos).map(|b| !b.is_liquid()).unwrap_or(true)
|
||||
|| traversal_cfg.can_climb
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
.map(move |dir| (pos, dir))
|
||||
.filter(move |(pos, dir)| {
|
||||
is_walkable(pos)
|
||||
|
@ -3,8 +3,8 @@
|
||||
// `Agent`). When possible, this should be moved to the `rtsim`
|
||||
// module in `server`.
|
||||
|
||||
use specs_idvs::IdvStorage;
|
||||
use specs::Component;
|
||||
use specs_idvs::IdvStorage;
|
||||
use vek::*;
|
||||
|
||||
pub type RtSimId = usize;
|
||||
@ -16,20 +16,20 @@ impl Component for RtSimEntity {
|
||||
type Storage = IdvStorage<Self>;
|
||||
}
|
||||
|
||||
/// This type is the map route through which the rtsim (real-time simulation) aspect
|
||||
/// of the game communicates with the rest of the game. It is analagous to
|
||||
/// `comp::Controller` in that it provides a consistent interface for simulation NPCs
|
||||
/// to control their actions. Unlike `comp::Controller`, it is very abstract and is
|
||||
/// intended for consumption by both the agent code and the internal rtsim simulation
|
||||
/// code (depending on whether the entity is loaded into the game as a physical entity
|
||||
/// or not). Agent code should attempt to act upon its instructions where reasonable
|
||||
/// although deviations for various reasons (obstacle avoidance, counter-attacking,
|
||||
/// etc.) are expected.
|
||||
/// This type is the map route through which the rtsim (real-time simulation)
|
||||
/// aspect of the game communicates with the rest of the game. It is analagous
|
||||
/// to `comp::Controller` in that it provides a consistent interface for
|
||||
/// simulation NPCs to control their actions. Unlike `comp::Controller`, it is
|
||||
/// very abstract and is intended for consumption by both the agent code and the
|
||||
/// internal rtsim simulation code (depending on whether the entity is loaded
|
||||
/// into the game as a physical entity or not). Agent code should attempt to act
|
||||
/// upon its instructions where reasonable although deviations for various
|
||||
/// reasons (obstacle avoidance, counter-attacking, etc.) are expected.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RtSimController {
|
||||
/// When this field is `Some(..)`, the agent should attempt to make progress
|
||||
/// toward the given location, accounting for obstacles and other high-priority
|
||||
/// situations like being attacked.
|
||||
/// toward the given location, accounting for obstacles and other
|
||||
/// high-priority situations like being attacked.
|
||||
pub travel_to: Option<Vec3<f32>>,
|
||||
/// Proportion of full speed to move
|
||||
pub speed_factor: f32,
|
||||
@ -45,7 +45,5 @@ impl Default for RtSimController {
|
||||
}
|
||||
|
||||
impl RtSimController {
|
||||
pub fn reset(&mut self) {
|
||||
*self = Self::default();
|
||||
}
|
||||
pub fn reset(&mut self) { *self = Self::default(); }
|
||||
}
|
||||
|
@ -5,7 +5,10 @@ use crate::{
|
||||
},
|
||||
event::LocalEvent,
|
||||
states::*,
|
||||
sys::{character_behavior::JoinData, phys::{GRAVITY, FRIC_GROUND}},
|
||||
sys::{
|
||||
character_behavior::JoinData,
|
||||
phys::{FRIC_GROUND, GRAVITY},
|
||||
},
|
||||
util::Dir,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -95,6 +98,7 @@ impl Body {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::match_like_matches_macro)]
|
||||
pub fn can_climb(&self) -> bool {
|
||||
match self {
|
||||
Body::Humanoid(_) => true,
|
||||
|
@ -223,24 +223,18 @@ impl<'a> System<'a> for Sys {
|
||||
match &mut agent.activity {
|
||||
Activity::Idle { bearing, chaser } => {
|
||||
if let Some(travel_to) = agent.rtsim_controller.travel_to {
|
||||
if let Some((bearing, speed)) = chaser.chase(
|
||||
&*terrain,
|
||||
pos.0,
|
||||
vel.0,
|
||||
travel_to,
|
||||
TraversalConfig {
|
||||
if let Some((bearing, speed)) =
|
||||
chaser.chase(&*terrain, pos.0, vel.0, travel_to, TraversalConfig {
|
||||
min_tgt_dist: 1.25,
|
||||
..traversal_config
|
||||
},
|
||||
) {
|
||||
inputs.move_dir = bearing
|
||||
.xy()
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::zero())
|
||||
* speed.min(agent.rtsim_controller.speed_factor);
|
||||
})
|
||||
{
|
||||
inputs.move_dir =
|
||||
bearing.xy().try_normalized().unwrap_or(Vec2::zero())
|
||||
* speed.min(agent.rtsim_controller.speed_factor);
|
||||
inputs.jump.set_state(bearing.z > 1.5);
|
||||
inputs.climb = Some(comp::Climb::Up);
|
||||
//.filter(|_| bearing.z > 0.1 || physics_state.in_liquid.is_some());
|
||||
//.filter(|_| bearing.z > 0.1 || physics_state.in_liquid.is_some());
|
||||
inputs.move_z = bearing.z + 0.05;
|
||||
}
|
||||
} else {
|
||||
|
@ -19,7 +19,7 @@ use roots::find_roots_cubic;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
vol::{RectVolSize, ReadVol},
|
||||
vol::{ReadVol, RectVolSize},
|
||||
volumes::vol_grid_2d::VolGrid2d,
|
||||
};
|
||||
use vek::*;
|
||||
|
@ -437,14 +437,15 @@ fn handle_time(
|
||||
// Accept `u12345`, seconds since midnight day 0
|
||||
Err(_) => match n
|
||||
.get(1..)
|
||||
.filter(|_| n.chars().next() == Some('u'))
|
||||
.and_then(|n| n.trim_left_matches('u').parse::<u64>().ok())
|
||||
.filter(|_| n.starts_with('u'))
|
||||
.and_then(|n| n.trim_start_matches('u').parse::<u64>().ok())
|
||||
{
|
||||
Some(n) => n as f64,
|
||||
None => {
|
||||
server.notify_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;
|
||||
},
|
||||
@ -454,9 +455,49 @@ fn handle_time(
|
||||
None => {
|
||||
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(
|
||||
// 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,
|
||||
);
|
||||
let msg = match current_time {
|
||||
@ -470,14 +511,14 @@ fn handle_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(
|
||||
client,
|
||||
ChatType::CommandInfo.server_msg(format!(
|
||||
"Time changed to: {}",
|
||||
new_time
|
||||
.format("%H:%M")
|
||||
.to_string(),
|
||||
new_time.format("%H:%M").to_string(),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ use common::{
|
||||
LightEmitter, Loadout, Ori, Pos, Projectile, Scale, Stats, Vel, WaypointArea,
|
||||
},
|
||||
outcome::Outcome,
|
||||
util::Dir,
|
||||
rtsim::RtSimEntity,
|
||||
util::Dir,
|
||||
};
|
||||
use comp::group;
|
||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
client::Client,
|
||||
comp::{biped_large, quadruped_medium, quadruped_small, PhysicsState},
|
||||
Server, SpawnPoint, StateExt,
|
||||
rtsim::RtSim,
|
||||
Server, SpawnPoint, StateExt,
|
||||
};
|
||||
use common::{
|
||||
assets::Asset,
|
||||
@ -16,12 +16,12 @@ use common::{
|
||||
lottery::Lottery,
|
||||
msg::{PlayerListUpdate, ServerGeneral},
|
||||
outcome::Outcome,
|
||||
rtsim::RtSimEntity,
|
||||
state::BlockChange,
|
||||
sync::{Uid, UidAllocator, WorldSyncExt},
|
||||
terrain::{Block, TerrainGrid},
|
||||
vol::ReadVol,
|
||||
Damage, DamageSource, Explosion, GroupTarget, RadiusEffect,
|
||||
rtsim::RtSimEntity,
|
||||
};
|
||||
use comp::item::Reagent;
|
||||
use rand::prelude::*;
|
||||
@ -462,8 +462,16 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
|
||||
};
|
||||
|
||||
if should_delete {
|
||||
if let Some(rtsim_entity) = state.ecs().read_storage::<RtSimEntity>().get(entity).copied() {
|
||||
state.ecs().write_resource::<RtSim>().destroy_entity(rtsim_entity.0);
|
||||
if let Some(rtsim_entity) = state
|
||||
.ecs()
|
||||
.read_storage::<RtSimEntity>()
|
||||
.get(entity)
|
||||
.copied()
|
||||
{
|
||||
state
|
||||
.ecs()
|
||||
.write_resource::<RtSim>()
|
||||
.destroy_entity(rtsim_entity.0);
|
||||
}
|
||||
|
||||
let _ = state
|
||||
|
@ -8,8 +8,8 @@ use entity_creation::{
|
||||
handle_loaded_character_data, handle_shockwave, handle_shoot,
|
||||
};
|
||||
use entity_manipulation::{
|
||||
handle_buff, handle_damage, handle_destroy, handle_delete, handle_energy_change, handle_explosion,
|
||||
handle_knockback, handle_land_on_ground, handle_level_up, handle_respawn,
|
||||
handle_buff, handle_damage, handle_delete, handle_destroy, handle_energy_change,
|
||||
handle_explosion, handle_knockback, handle_land_on_ground, handle_level_up, handle_respawn,
|
||||
};
|
||||
use group_manip::handle_group;
|
||||
use interaction::{handle_lantern, handle_mount, handle_possess, handle_unmount};
|
||||
@ -120,8 +120,18 @@ impl Server {
|
||||
drop_item,
|
||||
rtsim_entity,
|
||||
} => handle_create_npc(
|
||||
self, pos, stats, health, loadout, body, agent, alignment, scale, drop_item,
|
||||
home_chunk, rtsim_entity,
|
||||
self,
|
||||
pos,
|
||||
stats,
|
||||
health,
|
||||
loadout,
|
||||
body,
|
||||
agent,
|
||||
alignment,
|
||||
scale,
|
||||
drop_item,
|
||||
home_chunk,
|
||||
rtsim_entity,
|
||||
),
|
||||
ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos),
|
||||
ServerEvent::ClientDisconnect(entity) => {
|
||||
|
@ -52,9 +52,7 @@ use common::{
|
||||
comp::{self, ChatType},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{
|
||||
world_msg::{SiteInfo, SiteKind},
|
||||
ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg,
|
||||
WorldMapMsg,
|
||||
ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg,
|
||||
},
|
||||
outcome::Outcome,
|
||||
recipe::default_recipe_book,
|
||||
@ -62,7 +60,7 @@ use common::{
|
||||
state::{State, TimeOfDay},
|
||||
sync::WorldSyncExt,
|
||||
terrain::TerrainChunkSize,
|
||||
vol::{ReadVol, RectVolSize},
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use futures_executor::block_on;
|
||||
use metrics::{PhysicsMetrics, ServerMetrics, StateTickMetrics, TickMetrics};
|
||||
@ -327,7 +325,7 @@ impl Server {
|
||||
|
||||
// Insert the world into the ECS (todo: Maybe not an Arc?)
|
||||
let world = Arc::new(world);
|
||||
state.ecs_mut().insert(world.clone());
|
||||
state.ecs_mut().insert(Arc::clone(&world));
|
||||
state.ecs_mut().insert(index.clone());
|
||||
|
||||
// Set starting time for the server.
|
||||
|
@ -10,9 +10,7 @@ pub struct Chunks {
|
||||
impl Chunks {
|
||||
pub fn new(size: Vec2<u32>) -> Self {
|
||||
Chunks {
|
||||
chunks: Grid::populate_from(size.map(|e| e as i32), |_| Chunk {
|
||||
is_loaded: false,
|
||||
}),
|
||||
chunks: Grid::populate_from(size.map(|e| e as i32), |_| Chunk { is_loaded: false }),
|
||||
chunks_to_load: 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_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)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
use super::*;
|
||||
use common::event::{EventBus, ServerEvent};
|
||||
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect};
|
||||
use specs::{Read, System, WriteExpect};
|
||||
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
);
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (Read<'a, EventBus<ServerEvent>>, WriteExpect<'a, RtSim>);
|
||||
|
||||
fn run(&mut self, (server_event_bus, mut rtsim): Self::SystemData) {
|
||||
for chunk in std::mem::take(&mut rtsim.chunks.chunks_to_load) {
|
||||
fn run(&mut self, (_server_event_bus, mut rtsim): Self::SystemData) {
|
||||
for _chunk in std::mem::take(&mut rtsim.chunks.chunks_to_load) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,23 @@
|
||||
mod load_chunks;
|
||||
mod unload_chunks;
|
||||
mod tick;
|
||||
mod entity;
|
||||
mod chunks;
|
||||
#![allow(dead_code)] // TODO: Remove this when rtsim is fleshed out
|
||||
|
||||
use vek::*;
|
||||
mod chunks;
|
||||
mod entity;
|
||||
mod load_chunks;
|
||||
mod tick;
|
||||
mod unload_chunks;
|
||||
|
||||
use self::{chunks::Chunks, entity::Entity};
|
||||
use common::{
|
||||
comp,
|
||||
rtsim::{RtSimController, RtSimEntity, RtSimId},
|
||||
state::State,
|
||||
terrain::TerrainChunk,
|
||||
rtsim::{RtSimEntity, RtSimId, RtSimController},
|
||||
vol::RectRasterableVol,
|
||||
comp,
|
||||
};
|
||||
use specs::{DispatcherBuilder, WorldExt};
|
||||
use specs_idvs::IdvStorage;
|
||||
use slab::Slab;
|
||||
use rand::prelude::*;
|
||||
use self::{
|
||||
entity::Entity,
|
||||
chunks::Chunks,
|
||||
};
|
||||
use slab::Slab;
|
||||
use specs::{DispatcherBuilder, WorldExt};
|
||||
use vek::*;
|
||||
|
||||
pub struct RtSim {
|
||||
tick: u64,
|
||||
@ -88,12 +86,14 @@ pub fn init(state: &mut State, world: &world::World) {
|
||||
let mut rtsim = RtSim::new(world.sim().get_size());
|
||||
|
||||
for _ in 0..2500 {
|
||||
let pos = rtsim.chunks.size().map2(
|
||||
TerrainChunk::RECT_SIZE,
|
||||
|sz, chunk_sz| thread_rng().gen_range(0, sz * chunk_sz) as i32,
|
||||
);
|
||||
let pos = rtsim
|
||||
.chunks
|
||||
.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,
|
||||
pos: Vec3::from(pos.map(|e| e as f32)),
|
||||
seed: thread_rng().gen(),
|
||||
@ -101,8 +101,6 @@ pub fn init(state: &mut State, world: &world::World) {
|
||||
last_tick: 0,
|
||||
brain: Default::default(),
|
||||
});
|
||||
|
||||
// tracing::info!("Spawned rtsim NPC {} at {:?}", id, pos);
|
||||
}
|
||||
|
||||
state.ecs_mut().insert(rtsim);
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)] // TODO: Remove this when rtsim is fleshed out
|
||||
|
||||
use super::*;
|
||||
use common::{
|
||||
comp,
|
||||
@ -12,6 +14,7 @@ const ENTITY_TICK_PERIOD: u64 = 30;
|
||||
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Read<'a, DeltaTime>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
@ -33,7 +36,7 @@ impl<'a> System<'a> for Sys {
|
||||
mut rtsim,
|
||||
terrain,
|
||||
world,
|
||||
index,
|
||||
_index,
|
||||
positions,
|
||||
rtsim_entities,
|
||||
mut agents,
|
||||
|
@ -4,10 +4,11 @@ use common::{
|
||||
event::{EventBus, ServerEvent},
|
||||
terrain::TerrainGrid,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteExpect};
|
||||
use specs::{Entities, Read, ReadExpect, ReadStorage, System, WriteExpect};
|
||||
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
@ -20,17 +21,17 @@ impl<'a> System<'a> for Sys {
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
server_event_bus,
|
||||
_server_event_bus,
|
||||
mut rtsim,
|
||||
terrain_grid,
|
||||
entities,
|
||||
rtsim_entities,
|
||||
positions,
|
||||
_terrain_grid,
|
||||
_entities,
|
||||
_rtsim_entities,
|
||||
_positions,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let chunks = std::mem::take(&mut rtsim.chunks.chunks_to_unload);
|
||||
|
||||
for chunk in chunks {
|
||||
for _chunk in chunks {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use common::{
|
||||
use criterion::{black_box, criterion_group, criterion_main, Benchmark, Criterion};
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
use veloren_voxygen::mesh::Meshable;
|
||||
use veloren_voxygen::{mesh::Meshable, scene::terrain::BlocksOfInterest};
|
||||
use world::{sim, World};
|
||||
|
||||
const CENTER: Vec2<i32> = Vec2 { x: 512, y: 512 };
|
||||
@ -133,7 +133,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
c.bench(
|
||||
"meshing",
|
||||
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
|
||||
.sample_size(15),
|
||||
|
@ -489,15 +489,11 @@ impl<'a> Widget for Map<'a> {
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let title =
|
||||
site.name
|
||||
.as_ref()
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or_else(|| match &site.kind {
|
||||
SiteKind::Town => i18n.get("hud.map.town"),
|
||||
SiteKind::Dungeon { .. } => i18n.get("hud.map.dungeon"),
|
||||
SiteKind::Castle => i18n.get("hud.map.castle"),
|
||||
});
|
||||
let title = site.name.as_deref().unwrap_or_else(|| match &site.kind {
|
||||
SiteKind::Town => i18n.get("hud.map.town"),
|
||||
SiteKind::Dungeon { .. } => i18n.get("hud.map.dungeon"),
|
||||
SiteKind::Castle => i18n.get("hud.map.castle"),
|
||||
});
|
||||
let (difficulty, desc) = match &site.kind {
|
||||
SiteKind::Town => (0, i18n.get("hud.map.town").to_string()),
|
||||
SiteKind::Dungeon { difficulty } => (
|
||||
@ -656,10 +652,9 @@ impl<'a> Widget for Map<'a> {
|
||||
Vec2::new(32.0, 37.0) * scale
|
||||
};
|
||||
// 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
|
||||
.map2(map_size, |e, sz| {
|
||||
e.abs() + arrow_sz.map(|e| e as f32 / 2.0).magnitude() > sz as f32 / 2.0
|
||||
})
|
||||
.map2(map_size, |e, sz| e.abs() + arrow_mag > sz as f32 / 2.0)
|
||||
.reduce_or()
|
||||
{
|
||||
Image::new(self.rot_imgs.indicator_mmap_small.target_north)
|
||||
|
@ -2291,7 +2291,7 @@ impl Hud {
|
||||
// Reset the map position when it's not showing
|
||||
let drag = &global_state.settings.gameplay.map_drag;
|
||||
if drag.x != 0.0 || drag.y != 0.0 {
|
||||
events.push(Event::MapDrag(drag - drag))
|
||||
events.push(Event::MapDrag(Vec2::zero()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -586,16 +586,15 @@ fn draw_col_lights<D>(
|
||||
0.0
|
||||
}
|
||||
) / 4.0;
|
||||
let glowiness = (
|
||||
get_glow(data, light_pos)
|
||||
+ get_glow(data, light_pos - uv.x)
|
||||
+ get_glow(data, light_pos - uv.y)
|
||||
+ if direct_u_opacity || direct_v_opacity {
|
||||
get_glow(data, light_pos - uv.x - uv.y)
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
) / 4.0;
|
||||
let glowiness = (get_glow(data, light_pos)
|
||||
+ get_glow(data, light_pos - uv.x)
|
||||
+ get_glow(data, light_pos - uv.y)
|
||||
+ if direct_u_opacity || direct_v_opacity {
|
||||
get_glow(data, light_pos - uv.x - uv.y)
|
||||
} else {
|
||||
0.0
|
||||
})
|
||||
/ 4.0;
|
||||
let col = get_color(data, pos);
|
||||
let light = (darkness * 31.5) as u8;
|
||||
let glow = (glowiness * 31.5) as u8;
|
||||
|
@ -77,7 +77,7 @@ where
|
||||
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>| {
|
||||
vol.get(pos)
|
||||
.ok()
|
||||
|
@ -250,6 +250,7 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + 'static>
|
||||
Meshable<TerrainPipeline, FluidPipeline> for &'a VolGrid2d<V>
|
||||
{
|
||||
type Pipeline = TerrainPipeline;
|
||||
#[allow(clippy::type_complexity)]
|
||||
type Result = (
|
||||
Aabb<f32>,
|
||||
ColLightInfo,
|
||||
@ -468,7 +469,12 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + 'static>
|
||||
opaque_mesh,
|
||||
fluid_mesh,
|
||||
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),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,14 @@ impl Vertex {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
let mat_arr = mat.into_col_arrays();
|
||||
|
@ -107,23 +107,25 @@ impl Vertex {
|
||||
) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType
|
||||
{
|
||||
//[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.
|
||||
// We can do this because both `light` and `glow` go from 0 to 31, meaning that they
|
||||
// can both fit into 5 bits. If we steal a bit from red and blue each (not green,
|
||||
// human eyes are more sensitive to changes in green) then we get just enough to
|
||||
// expand the nibbles of the alpha field enough to fit both `light` and `glow`.
|
||||
// It would be nice for this to be cleaner, but we want to squeeze 5 fields into
|
||||
// 4. We can do this because both `light` and `glow` go from 0 to 31,
|
||||
// meaning that they can both fit into 5 bits. If we steal a bit from
|
||||
// red and blue each (not green, human eyes are more sensitive to
|
||||
// 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
|
||||
// get at the `light` and `glow` attributes (but not colour, that remains constant
|
||||
// across a block). How do we resolve this if we're twiddling bits? The answer is to
|
||||
// very carefully manipulate 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
|
||||
// However, we now have a problem. In the shader code with use hardware
|
||||
// filtering to get at the `light` and `glow` attributes (but not
|
||||
// colour, that remains constant across a block). How do we resolve this
|
||||
// if we're twiddling bits? The answer is to very carefully manipulate
|
||||
// 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
|
||||
// unfiltered texture access (i.e: `texelFetch`) to access the colours, plus a little
|
||||
// bit-fiddling.
|
||||
// unfiltered texture access (i.e: `texelFetch`) to access the colours, plus a
|
||||
// little bit-fiddling.
|
||||
//
|
||||
// TODO: This isn't currently working (no idea why). See `srgb.glsl` for current impl
|
||||
// that intead does manual bit-twiddling and filtering.
|
||||
// TODO: This isn't currently working (no idea why). See `srgb.glsl` for current
|
||||
// impl that intead does manual bit-twiddling and filtering.
|
||||
[
|
||||
(light.min(31) << 3) | ((col.r & 0b1110) >> 1),
|
||||
(glow.min(31) << 3) | ((col.r & 0b1110) >> 1),
|
||||
|
@ -33,7 +33,8 @@ use tracing::{error, warn};
|
||||
use vek::*;
|
||||
|
||||
/// 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;
|
||||
/// Represents the format of the pre-processed depth and stencil target.
|
||||
pub type TgtDepthStencilFmt = gfx::format::Depth;
|
||||
@ -1001,10 +1002,10 @@ impl Renderer {
|
||||
size: [u16; 2],
|
||||
data: &[<<T as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType],
|
||||
) -> Result<(), RenderError>
|
||||
where
|
||||
<T as gfx::format::Formatted>::Surface: gfx::format::TextureSurface,
|
||||
<T as gfx::format::Formatted>::Channel: gfx::format::TextureChannel,
|
||||
<<T as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType: Copy,
|
||||
where
|
||||
<T as gfx::format::Formatted>::Surface: gfx::format::TextureSurface,
|
||||
<T as gfx::format::Formatted>::Channel: gfx::format::TextureChannel,
|
||||
<<T as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType: Copy,
|
||||
{
|
||||
texture.update(&mut self.encoder, offset, size, data)
|
||||
}
|
||||
|
@ -12,8 +12,9 @@ use crate::{
|
||||
},
|
||||
scene::{
|
||||
camera::{Camera, CameraMode, Dependents},
|
||||
math, LodData, SceneData,
|
||||
math,
|
||||
terrain::Terrain,
|
||||
LodData, SceneData,
|
||||
},
|
||||
};
|
||||
use anim::{
|
||||
@ -3486,7 +3487,8 @@ impl<S: Skeleton> FigureState<S> {
|
||||
})
|
||||
.unwrap_or((1.0, 0.0));
|
||||
// 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_glow = vek::Lerp::lerp(self.last_glow, glow, 16.0 * dt);
|
||||
|
||||
|
@ -540,7 +540,8 @@ impl Scene {
|
||||
lights.clear();
|
||||
|
||||
// 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
|
||||
lights.extend(
|
||||
|
@ -2,8 +2,8 @@ use super::{terrain::BlocksOfInterest, SceneData, Terrain};
|
||||
use crate::{
|
||||
mesh::{greedy::GreedyMesh, Meshable},
|
||||
render::{
|
||||
pipelines::particle::ParticleMode, GlobalModel, Instances, LodData, Model,
|
||||
ParticleInstance, ParticlePipeline, Renderer, Light,
|
||||
pipelines::particle::ParticleMode, GlobalModel, Instances, Light, LodData, Model,
|
||||
ParticleInstance, ParticlePipeline, Renderer,
|
||||
},
|
||||
};
|
||||
use common::{
|
||||
@ -73,7 +73,8 @@ impl ParticleMgr {
|
||||
ParticleMode::EnergyNature,
|
||||
*pos + Vec3::<f32>::zero()
|
||||
.map(|_| rng.gen_range(-1.0, 1.0))
|
||||
.normalized() * *radius,
|
||||
.normalized()
|
||||
* *radius,
|
||||
)
|
||||
},
|
||||
);
|
||||
@ -87,7 +88,8 @@ impl ParticleMgr {
|
||||
ParticleMode::CampfireFire,
|
||||
*pos + Vec3::<f32>::zero()
|
||||
.map(|_| rng.gen_range(-1.0, 1.0))
|
||||
.normalized() * *radius,
|
||||
.normalized()
|
||||
* *radius,
|
||||
)
|
||||
},
|
||||
);
|
||||
@ -121,7 +123,8 @@ impl ParticleMgr {
|
||||
ParticleMode::CampfireSmoke,
|
||||
*pos + Vec3::<f32>::zero()
|
||||
.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.static_data.base_hps > 0 {
|
||||
// Emit a light when using healing
|
||||
lights.push(Light::new(
|
||||
pos.0 + b.offset,
|
||||
Rgb::new(0.1, 1.0, 0.15),
|
||||
1.0,
|
||||
));
|
||||
lights.push(Light::new(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)) {
|
||||
self.particles.push(Particle::new_beam(
|
||||
b.static_data.beam_duration,
|
||||
|
@ -144,7 +144,11 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + '
|
||||
span!(_guard, "mesh_worker");
|
||||
let blocks_of_interest = BlocksOfInterest::from_chunk(&chunk);
|
||||
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 {
|
||||
pos,
|
||||
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.
|
||||
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));
|
||||
self.chunks.get(&chunk_pos).map(|c| (c.light_map)(wpos)).unwrap_or(1.0)
|
||||
let chunk_pos = Vec2::from(wpos).map2(TerrainChunk::RECT_SIZE, |e: i32, sz| {
|
||||
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.
|
||||
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));
|
||||
self.chunks.get(&chunk_pos).map(|c| (c.glow_map)(wpos)).unwrap_or(0.0)
|
||||
let chunk_pos = Vec2::from(wpos).map2(TerrainChunk::RECT_SIZE, |e: i32, sz| {
|
||||
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.
|
||||
|
@ -6,6 +6,7 @@ use common::{
|
||||
use rand::prelude::*;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BlocksOfInterest {
|
||||
pub leaves: Vec<Vec3<i32>>,
|
||||
pub grass: Vec<Vec3<i32>>,
|
||||
@ -22,8 +23,6 @@ pub struct BlocksOfInterest {
|
||||
pub lights: Vec<(Vec3<i32>, u8)>,
|
||||
}
|
||||
|
||||
use inline_tweak::*;
|
||||
|
||||
impl BlocksOfInterest {
|
||||
pub fn from_chunk(chunk: &TerrainChunk) -> Self {
|
||||
span!(_guard, "from_chunk", "BlocksOfInterest::from_chunk");
|
||||
@ -73,8 +72,10 @@ impl BlocksOfInterest {
|
||||
// Offset positions to account for block height.
|
||||
// TODO: Is this a good idea?
|
||||
Some(SpriteKind::StreetLamp) => fire_bowls.push(pos + Vec3::unit_z() * 2),
|
||||
Some(SpriteKind::FireBowlGround) => fire_bowls.push(pos + Vec3::unit_z() * 1),
|
||||
Some(SpriteKind::StreetLampTall) => fire_bowls.push(pos + Vec3::unit_z() * 4),
|
||||
Some(SpriteKind::FireBowlGround) => fire_bowls.push(pos + Vec3::unit_z()),
|
||||
Some(SpriteKind::StreetLampTall) => {
|
||||
fire_bowls.push(pos + Vec3::unit_z() * 4)
|
||||
},
|
||||
Some(SpriteKind::Beehive) => beehives.push(pos),
|
||||
Some(SpriteKind::Reed) => reeds.push(pos),
|
||||
Some(SpriteKind::PinkFlower) => flowers.push(pos),
|
||||
|
@ -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 noise::NoiseFn;
|
||||
use rand::prelude::*;
|
||||
|
@ -31,6 +31,7 @@ static MODEL_RAND: RandomPerm = RandomPerm::new(0xDB21C052);
|
||||
static UNIT_CHOOSER: UnitChooser = UnitChooser::new(0x700F4EC7);
|
||||
static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F);
|
||||
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
pub fn apply_trees_to(canvas: &mut Canvas) {
|
||||
struct Tree {
|
||||
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);
|
||||
|
||||
// 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
|
||||
|| col.spawn_rate < 0.9
|
||||
|| col.water_dist.map(|d| d < 8.0).unwrap_or(false)
|
||||
|| col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -182,10 +182,20 @@ impl World {
|
||||
};
|
||||
|
||||
let meta = TerrainChunkMeta::new(
|
||||
sim_chunk.sites
|
||||
sim_chunk
|
||||
.sites
|
||||
.iter()
|
||||
.filter(|id| 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))
|
||||
.filter(|id| {
|
||||
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()),
|
||||
sim_chunk.get_biome(),
|
||||
sim_chunk.alt,
|
||||
|
@ -1,11 +1,9 @@
|
||||
use crate::sim::WorldSim;
|
||||
use common::{
|
||||
astar::Astar,
|
||||
path::Path,
|
||||
};
|
||||
use hashbrown::hash_map::DefaultHashBuilder;
|
||||
use common::path::Path;
|
||||
//use hashbrown::hash_map::DefaultHashBuilder;
|
||||
use vek::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct SearchCfg {
|
||||
// 0.0 = no discount, 1.0 = free travel
|
||||
path_discount: f32,
|
||||
@ -14,15 +12,19 @@ pub struct SearchCfg {
|
||||
gradient_aversion: f32,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Searcher<'a> {
|
||||
land: &'a WorldSim,
|
||||
pub cfg: SearchCfg,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<'a> Searcher<'a> {
|
||||
/// Attempt to find a path between two chunks on the map.
|
||||
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();
|
||||
pub fn search(self, _a: Vec2<i32>, _b: Vec2<i32>) -> Option<Path<i32>> {
|
||||
// TODO: implement this function
|
||||
|
||||
//let heuristic = |pos: &Vec2<i32>| (pos - b).map(|e| e as f32).magnitude();
|
||||
// Astar::new(
|
||||
// 100_000,
|
||||
// a,
|
||||
|
@ -103,7 +103,7 @@ pub fn sample_pos(
|
||||
spline_derivative,
|
||||
is_path,
|
||||
is_cave,
|
||||
near_site,
|
||||
_near_site,
|
||||
) = sampler
|
||||
.get(pos)
|
||||
.map(|sample| {
|
||||
|
@ -3,11 +3,11 @@ use crate::{
|
||||
column::ColumnSample,
|
||||
sim::WorldSim,
|
||||
site::{
|
||||
namegen::NameGen,
|
||||
settlement::building::{
|
||||
archetype::keep::{Attr, FlagColor, Keep as KeepArchetype, StoneColor},
|
||||
Archetype, Ori,
|
||||
},
|
||||
namegen::NameGen,
|
||||
},
|
||||
IndexRef,
|
||||
};
|
||||
@ -156,9 +156,7 @@ impl Castle {
|
||||
this
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
pub fn name(&self) -> &str { &self.name }
|
||||
|
||||
pub fn contains_point(&self, wpos: Vec2<i32>) -> bool {
|
||||
let lpos = wpos - self.origin;
|
||||
|
@ -48,8 +48,6 @@ pub struct Colors {
|
||||
|
||||
const ALT_OFFSET: i32 = -2;
|
||||
|
||||
const LEVELS: usize = 5;
|
||||
|
||||
impl Dungeon {
|
||||
#[allow(clippy::let_and_return)] // TODO: Pending review in #587
|
||||
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!
|
||||
miniboss: false,
|
||||
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,
|
||||
pillars: Some(2),
|
||||
difficulty,
|
||||
@ -482,6 +483,8 @@ impl Floor {
|
||||
origin: Vec3<i32>,
|
||||
supplement: &mut ChunkSupplement,
|
||||
) {
|
||||
/*
|
||||
// Add stair waypoint
|
||||
let stair_rcenter =
|
||||
Vec3::from((self.stair_tile + self.tile_offset).map(|e| e * TILE_SIZE + TILE_SIZE / 2));
|
||||
|
||||
@ -493,13 +496,14 @@ impl Floor {
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y)
|
||||
* (TILE_SIZE as f32 / 2.0 - 4.0);
|
||||
// if !self.final_level {
|
||||
// supplement.add_entity(
|
||||
// EntityInfo::at((origin + stair_rcenter).map(|e| e as f32)
|
||||
// + Vec3::from(offs)) .into_waypoint(),
|
||||
// );
|
||||
// }
|
||||
if !self.final_level {
|
||||
supplement.add_entity(
|
||||
EntityInfo::at((origin + stair_rcenter).map(|e| e as f32)
|
||||
+ Vec3::from(offs)) .into_waypoint(),
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
for x in area.min.x..area.max.x {
|
||||
for y in area.min.y..area.max.y {
|
||||
@ -601,11 +605,11 @@ impl Floor {
|
||||
(room.difficulty as f32).powf(1.5) + 4.0,
|
||||
).round() as u32);
|
||||
let entity = match room.difficulty {
|
||||
0 => entity.with_name("Outcast")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Outcast)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
0 => entity
|
||||
.with_name("Outcast")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Outcast)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.starter_axe",
|
||||
1 => "common.items.weapons.sword.starter_sword",
|
||||
@ -614,13 +618,12 @@ impl Floor {
|
||||
4 => "common.items.weapons.staff.starter_staff",
|
||||
_ => "common.items.weapons.bow.starter_bow",
|
||||
},
|
||||
),
|
||||
),
|
||||
1 => entity.with_name("Highwayman")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Highwayman)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
)),
|
||||
1 => entity
|
||||
.with_name("Highwayman")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Highwayman)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.worn_iron_axe-0",
|
||||
1 => "common.items.weapons.sword.zweihander_sword_0",
|
||||
@ -629,13 +632,12 @@ impl Floor {
|
||||
4 => "common.items.weapons.staff.bone_staff",
|
||||
_ => "common.items.weapons.bow.wood_shortbow-1",
|
||||
},
|
||||
),
|
||||
),
|
||||
2 => entity.with_name("Bandit")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Bandit)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
)),
|
||||
2 => entity
|
||||
.with_name("Bandit")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Bandit)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.bronze_axe-0",
|
||||
1 => "common.items.weapons.sword.greatsword_2h_simple-0",
|
||||
@ -644,13 +646,12 @@ impl Floor {
|
||||
4 => "common.items.weapons.staff.bone_staff",
|
||||
_ => "common.items.weapons.bow.wood_longbow-0",
|
||||
},
|
||||
),
|
||||
),
|
||||
3 => entity.with_name("Cultist Novice")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::CultistNovice)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
)),
|
||||
3 => entity
|
||||
.with_name("Cultist Novice")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::CultistNovice)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.steel_axe-0",
|
||||
1 => "common.items.weapons.sword.long_2h_orn-0",
|
||||
@ -659,13 +660,12 @@ impl Floor {
|
||||
4 => "common.items.weapons.staff.amethyst_staff",
|
||||
_ => "common.items.weapons.bow.horn_longbow-0",
|
||||
},
|
||||
),
|
||||
),
|
||||
4 => entity.with_name("Cultist Acolyte")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::CultistAcolyte)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
)),
|
||||
4 => entity
|
||||
.with_name("Cultist Acolyte")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::CultistAcolyte)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.malachite_axe-0",
|
||||
1 => "common.items.weapons.sword.cultist_purp_2h-0",
|
||||
@ -674,20 +674,20 @@ impl Floor {
|
||||
4 => "common.items.weapons.staff.cultist_staff",
|
||||
_ => "common.items.weapons.bow.horn_longbow-0",
|
||||
},
|
||||
),
|
||||
),
|
||||
)),
|
||||
5 => match dynamic_rng.gen_range(0, 6) {
|
||||
0 => entity.with_name("Cultist Warlock")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Warlock)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect("common.items.npc_weapons.staff.cultist_staff"),
|
||||
),
|
||||
_ => entity.with_name("Cultist Warlord")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Warlord)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
0 => entity
|
||||
.with_name("Cultist Warlock")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Warlock)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.staff.cultist_staff",
|
||||
)),
|
||||
_ => entity
|
||||
.with_name("Cultist Warlord")
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Warlord)
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 5) {
|
||||
0 => "common.items.weapons.axe.malachite_axe-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",
|
||||
_ => "common.items.weapons.bow.horn_longbow-0",
|
||||
},
|
||||
),
|
||||
),
|
||||
)),
|
||||
},
|
||||
_ => entity.with_name("Humanoid").with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
@ -723,77 +722,101 @@ impl Floor {
|
||||
|
||||
if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d {
|
||||
let chosen = match room.difficulty {
|
||||
0 => Lottery::<String>::load_expect("common.loot_tables.loot_table_weapon_uncommon"),
|
||||
1 => Lottery::<String>::load_expect("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"),
|
||||
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"),
|
||||
0 => Lottery::<String>::load_expect(
|
||||
"common.loot_tables.loot_table_weapon_uncommon",
|
||||
),
|
||||
1 => Lottery::<String>::load_expect(
|
||||
"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",
|
||||
),
|
||||
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(
|
||||
"common.loot_tables.loot_table_armor_misc",
|
||||
),
|
||||
};
|
||||
let chosen = chosen.choose();
|
||||
let entity =
|
||||
match room.difficulty {
|
||||
0 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
|
||||
.with_name("Outcast Leader".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Outcast)
|
||||
.with_scale(2.0)
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.worn_iron_axe-0",
|
||||
1 => "common.items.weapons.sword.zweihander_sword_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",
|
||||
_ => "common.items.weapons.bow.wood_shortbow-1",
|
||||
},
|
||||
),
|
||||
),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Tarasque,
|
||||
)))
|
||||
.with_name("Tarasque".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
let entity = match room.difficulty {
|
||||
0 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Humanoid(
|
||||
comp::humanoid::Body::random(),
|
||||
))
|
||||
.with_name("Outcast Leader".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_config(
|
||||
common::loadout_builder::LoadoutConfig::Outcast,
|
||||
)
|
||||
.with_scale(2.0)
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.worn_iron_axe-0",
|
||||
1 => {
|
||||
"common.items.weapons.sword.zweihander_sword_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",
|
||||
_ => "common.items.weapons.bow.wood_shortbow-1",
|
||||
},
|
||||
)),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(
|
||||
comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Tarasque,
|
||||
),
|
||||
))
|
||||
.with_name("Tarasque".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
1 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Theropod(comp::theropod::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::theropod::Species::Odonto,
|
||||
)))
|
||||
.with_name("Odonto".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
1 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Theropod(
|
||||
comp::theropod::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::theropod::Species::Odonto,
|
||||
),
|
||||
))
|
||||
.with_name("Odonto".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
2 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
|
||||
.with_name("Bandit Captain".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Bandit)
|
||||
.with_scale(2.0)
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.steel_axe-0",
|
||||
1 => "common.items.weapons.sword.long_2h_orn-0",
|
||||
2 => "common.items.weapons.sword.long_2h_orn-0",
|
||||
3 => "common.items.weapons.hammer.cobalt_hammer-0",
|
||||
4 => "common.items.weapons.staff.amethyst_staff",
|
||||
_ => "common.items.weapons.bow.horn_longbow-0",
|
||||
},
|
||||
),
|
||||
)
|
||||
; 2],
|
||||
3 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
2 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Humanoid(
|
||||
comp::humanoid::Body::random()
|
||||
))
|
||||
.with_name("Bandit Captain".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Bandit)
|
||||
.with_scale(2.0)
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.steel_axe-0",
|
||||
1 => "common.items.weapons.sword.long_2h_orn-0",
|
||||
2 => "common.items.weapons.sword.long_2h_orn-0",
|
||||
3 => "common.items.weapons.hammer.cobalt_hammer-0",
|
||||
4 => "common.items.weapons.staff.amethyst_staff",
|
||||
_ => "common.items.weapons.bow.horn_longbow-0",
|
||||
},
|
||||
),);
|
||||
2
|
||||
],
|
||||
3 => {
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
|
||||
.with_name("Cultist Acolyte".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
@ -811,46 +834,57 @@ impl Floor {
|
||||
},
|
||||
),
|
||||
)
|
||||
; 2],
|
||||
4 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Golem(comp::golem::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::golem::Species::StoneGolem,
|
||||
)))
|
||||
.with_name("Stonework Defender".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
; 2]
|
||||
},
|
||||
4 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Golem(
|
||||
comp::golem::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::golem::Species::StoneGolem,
|
||||
),
|
||||
))
|
||||
.with_name("Stonework Defender".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
5 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::BipedLarge(comp::biped_large::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::biped_large::Species::Mindflayer,
|
||||
)))
|
||||
.with_name("Mindflayer".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
_ =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedSmall(comp::quadruped_small::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_small::Species::Sheep,
|
||||
))),
|
||||
5 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::BipedLarge(
|
||||
comp::biped_large::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::biped_large::Species::Mindflayer,
|
||||
),
|
||||
))
|
||||
.with_name("Mindflayer".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
_ => {
|
||||
vec![EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_body(
|
||||
comp::Body::QuadrupedSmall(
|
||||
comp::quadruped_small::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_small::Species::Sheep,
|
||||
),
|
||||
),
|
||||
)]
|
||||
},
|
||||
};
|
||||
|
||||
for entity in entity {
|
||||
supplement.add_entity(entity.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(room.difficulty as f32).powf(1.25) + 3.0,
|
||||
(room.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round() as u32
|
||||
* 5,
|
||||
)
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
);
|
||||
supplement.add_entity(
|
||||
entity
|
||||
.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(room.difficulty as f32).powf(1.25) + 3.0,
|
||||
(room.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round()
|
||||
as u32
|
||||
* 5,
|
||||
)
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -868,123 +902,161 @@ impl Floor {
|
||||
let miniboss_spawn_tile =
|
||||
miniboss_spawn_tile + if miniboss_tile_is_pillar { 1 } else { 0 };
|
||||
|
||||
if tile_pos == miniboss_spawn_tile && tile_wcenter.xy() == wpos2d {
|
||||
let chosen = match room.difficulty {
|
||||
0 => Lottery::<String>::load_expect("common.loot_tables.loot_table_animal_parts"),
|
||||
1 => Lottery::<String>::load_expect("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"),
|
||||
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(
|
||||
"common.loot_tables.loot_table_armor_misc",
|
||||
),
|
||||
};
|
||||
let chosen = chosen.choose();
|
||||
let entity =
|
||||
match room.difficulty {
|
||||
0 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Bonerattler,
|
||||
)))
|
||||
.with_name("Bonerattler".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
1 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Bonerattler,
|
||||
)))
|
||||
.with_name("Bonerattler".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
; 3],
|
||||
2 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Tarasque,
|
||||
)))
|
||||
.with_name("Tarasque".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
3 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
|
||||
.with_name("Animal Trainer".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_config(common::loadout_builder::LoadoutConfig::CultistAcolyte)
|
||||
.with_scale(2.0)
|
||||
.with_main_tool(
|
||||
comp::Item::new_from_asset_expect(
|
||||
if tile_pos == miniboss_spawn_tile && tile_wcenter.xy() == wpos2d {
|
||||
let chosen = match room.difficulty {
|
||||
0 => Lottery::<String>::load_expect(
|
||||
"common.loot_tables.loot_table_animal_parts",
|
||||
),
|
||||
1 => Lottery::<String>::load_expect(
|
||||
"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",
|
||||
),
|
||||
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(
|
||||
"common.loot_tables.loot_table_armor_misc",
|
||||
),
|
||||
};
|
||||
let chosen = chosen.choose();
|
||||
let entity = match room.difficulty {
|
||||
0 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(
|
||||
comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Bonerattler,
|
||||
),
|
||||
))
|
||||
.with_name("Bonerattler".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
1 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(
|
||||
comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Bonerattler,
|
||||
)
|
||||
))
|
||||
.with_name("Bonerattler".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(
|
||||
chosen
|
||||
));
|
||||
3
|
||||
],
|
||||
2 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(
|
||||
comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Tarasque,
|
||||
),
|
||||
))
|
||||
.with_name("Tarasque".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
3 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Humanoid(
|
||||
comp::humanoid::Body::random(),
|
||||
))
|
||||
.with_name("Animal Trainer".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen))
|
||||
.with_config(
|
||||
common::loadout_builder::LoadoutConfig::CultistAcolyte,
|
||||
)
|
||||
.with_scale(2.0)
|
||||
.with_main_tool(comp::Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 6) {
|
||||
0 => "common.items.weapons.axe.malachite_axe-0",
|
||||
1 => "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",
|
||||
_ => "common.items.weapons.bow.horn_longbow-0",
|
||||
},
|
||||
)),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(
|
||||
comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Wolf,
|
||||
),
|
||||
))
|
||||
.with_name("Tamed Wolf".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(
|
||||
comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Wolf,
|
||||
),
|
||||
))
|
||||
.with_name("Tamed Wolf".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
4 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::BipedLarge(
|
||||
comp::biped_large::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::biped_large::Species::Dullahan,
|
||||
),
|
||||
))
|
||||
.with_name("Dullahan Guard".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
5 => vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Golem(
|
||||
comp::golem::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::golem::Species::StoneGolem,
|
||||
),
|
||||
))
|
||||
.with_name("Stonework Defender".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
_ => {
|
||||
vec![EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_body(
|
||||
comp::Body::QuadrupedSmall(
|
||||
comp::quadruped_small::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_small::Species::Sheep,
|
||||
),
|
||||
),
|
||||
),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Wolf,
|
||||
)))
|
||||
.with_name("Tamed Wolf".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedMedium(comp::quadruped_medium::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_medium::Species::Wolf,
|
||||
)))
|
||||
.with_name("Tamed Wolf".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
4 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::BipedLarge(comp::biped_large::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::biped_large::Species::Dullahan,
|
||||
)))
|
||||
.with_name("Dullahan Guard".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
5 =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::Golem(comp::golem::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::golem::Species::StoneGolem,
|
||||
)))
|
||||
.with_name("Stonework Defender".to_string())
|
||||
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)),
|
||||
],
|
||||
_ =>
|
||||
vec![ EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
.with_body(comp::Body::QuadrupedSmall(comp::quadruped_small::Body::random_with(
|
||||
dynamic_rng,
|
||||
&comp::quadruped_small::Species::Sheep,
|
||||
))),
|
||||
],
|
||||
};
|
||||
)]
|
||||
},
|
||||
};
|
||||
|
||||
for entity in entity {
|
||||
supplement.add_entity(entity.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(room.difficulty as f32).powf(1.25) + 3.0,
|
||||
(room.difficulty as f32).powf(1.5) + 4.0,
|
||||
for entity in entity {
|
||||
supplement.add_entity(
|
||||
entity
|
||||
.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(room.difficulty as f32).powf(1.25) + 3.0,
|
||||
(room.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round()
|
||||
as u32
|
||||
* 5,
|
||||
)
|
||||
.round() as u32
|
||||
* 5,
|
||||
)
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
mod block_mask;
|
||||
mod castle;
|
||||
mod dungeon;
|
||||
mod namegen;
|
||||
pub mod economy;
|
||||
mod namegen;
|
||||
mod settlement;
|
||||
|
||||
// Reexports
|
||||
|
@ -17,13 +17,14 @@ impl<'a, R: Rng> NameGen<'a, R> {
|
||||
|
||||
pub fn generate(self) -> String {
|
||||
let cons = vec![
|
||||
"d", "f", "ph", "r", "st", "t", "s", "p", "sh", "th", "br", "tr", "m", "k", "st", "w", "y",
|
||||
"cr", "fr", "dr", "pl", "wr", "sn", "g", "qu", "l",
|
||||
"d", "f", "ph", "r", "st", "t", "s", "p", "sh", "th", "br", "tr", "m", "k", "st", "w",
|
||||
"y", "cr", "fr", "dr", "pl", "wr", "sn", "g", "qu", "l",
|
||||
];
|
||||
let mut start = cons.clone();
|
||||
start.extend(vec![
|
||||
"cr", "thr", "str", "br", "iv", "est", "ost", "ing", "kr", "in", "on", "tr", "tw", "wh",
|
||||
"eld", "ar", "or", "ear", "irr", "mi", "en", "ed", "et", "ow", "fr", "shr", "wr", "gr", "pr",
|
||||
"cr", "thr", "str", "br", "iv", "est", "ost", "ing", "kr", "in", "on", "tr", "tw",
|
||||
"wh", "eld", "ar", "or", "ear", "irr", "mi", "en", "ed", "et", "ow", "fr", "shr", "wr",
|
||||
"gr", "pr",
|
||||
]);
|
||||
let mut middle = cons.clone();
|
||||
middle.extend(vec!["tt"]);
|
||||
@ -43,14 +44,9 @@ impl<'a, R: Rng> NameGen<'a, R> {
|
||||
}
|
||||
name += end.choose(self.rng).unwrap();
|
||||
|
||||
name
|
||||
.chars()
|
||||
name.chars()
|
||||
.enumerate()
|
||||
.map(|(i, c)| if i == 0 {
|
||||
c.to_ascii_uppercase()
|
||||
} else {
|
||||
c
|
||||
})
|
||||
.map(|(i, c)| if i == 0 { c.to_ascii_uppercase() } else { c })
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ use super::SpawnRules;
|
||||
use crate::{
|
||||
column::ColumnSample,
|
||||
sim::WorldSim,
|
||||
util::{RandomField, Sampler, StructureGen2d},
|
||||
site::namegen::NameGen,
|
||||
util::{RandomField, Sampler, StructureGen2d},
|
||||
IndexRef,
|
||||
};
|
||||
use common::{
|
||||
@ -188,9 +188,7 @@ impl Settlement {
|
||||
this
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
pub fn name(&self) -> &str { &self.name }
|
||||
|
||||
pub fn get_origin(&self) -> Vec2<i32> { self.origin }
|
||||
|
||||
@ -921,14 +919,16 @@ impl Settlement {
|
||||
.do_if(is_dummy, |e| e.with_name("Training Dummy"))
|
||||
.do_if(is_human && dynamic_rng.gen(), |entity| {
|
||||
match dynamic_rng.gen_range(0, 5) {
|
||||
0 => entity.with_main_tool(Item::new_from_asset_expect(
|
||||
"common.items.weapons.sword.greatsword_2h_simple-0",
|
||||
))
|
||||
.with_name("Guard")
|
||||
.with_level(dynamic_rng.gen_range(10, 15))
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Guard),
|
||||
_ => entity.with_main_tool(Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 7) {
|
||||
0 => entity
|
||||
.with_main_tool(Item::new_from_asset_expect(
|
||||
"common.items.weapons.sword.greatsword_2h_simple-0",
|
||||
))
|
||||
.with_name("Guard")
|
||||
.with_level(dynamic_rng.gen_range(10, 15))
|
||||
.with_config(common::loadout_builder::LoadoutConfig::Guard),
|
||||
_ => entity
|
||||
.with_main_tool(Item::new_from_asset_expect(
|
||||
match dynamic_rng.gen_range(0, 7) {
|
||||
0 => "common.items.npc_weapons.tool.broom",
|
||||
1 => "common.items.npc_weapons.tool.hoe",
|
||||
2 => "common.items.npc_weapons.tool.pickaxe",
|
||||
@ -938,9 +938,9 @@ impl Settlement {
|
||||
_ => "common.items.npc_weapons.tool.shovel-1",
|
||||
//_ => "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),
|
||||
}
|
||||
});
|
||||
|
||||
supplement.add_entity(entity);
|
||||
|
Loading…
Reference in New Issue
Block a user