mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Huts now have doors. Added totems.
This commit is contained in:
@ -475,7 +475,7 @@ pub fn apply_spots_to(canvas: &mut Canvas, _dynamic_rng: &mut impl Rng) {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
Spot::GnarlingTotem => SpotConfig {
|
Spot::GnarlingTotem => SpotConfig {
|
||||||
base_structures: Some("spots_grasslands.gnarling_totem"),
|
base_structures: Some("site_structures.gnarling.totem"),
|
||||||
entity_radius: 30.0,
|
entity_radius: 30.0,
|
||||||
entities: &[
|
entities: &[
|
||||||
(3..5, "common.entity.dungeon.tier-0.mugger"),
|
(3..5, "common.entity.dungeon.tier-0.mugger"),
|
||||||
|
@ -880,6 +880,14 @@ impl<'a> PrimitiveRef<'a> {
|
|||||||
pub fn repeat(self, offset: Vec3<i32>, count: i32) -> PrimitiveRef<'a> {
|
pub fn repeat(self, offset: Vec3<i32>, count: i32) -> PrimitiveRef<'a> {
|
||||||
self.painter.prim(Primitive::repeat(self, offset, count))
|
self.painter.prim(Primitive::repeat(self, offset, count))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn translate(self, trans: Vec3<i32>) -> PrimitiveRef<'a> {
|
||||||
|
self.painter.prim(Primitive::translate(self, trans))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate(self, rot: Mat3<i32>) -> PrimitiveRef<'a> {
|
||||||
|
self.painter.prim(Primitive::rotate(self, rot))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Structure {
|
pub trait Structure {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{util::attempt, Land};
|
use crate::{assets::AssetHandle, util::attempt, Land};
|
||||||
|
use common::terrain::{Structure as PrefabStructure, StructuresGroup};
|
||||||
use inline_tweak::tweak;
|
use inline_tweak::tweak;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -14,7 +16,24 @@ pub struct GnarlingFortification {
|
|||||||
// corner, and thus whether a tower gets constructed
|
// corner, and thus whether a tower gets constructed
|
||||||
ordered_wall_points: Vec<(Vec2<i32>, bool)>,
|
ordered_wall_points: Vec<(Vec2<i32>, bool)>,
|
||||||
gate_index: usize,
|
gate_index: usize,
|
||||||
hut_locations: Vec<Vec2<i32>>,
|
// Structure indicates the kind of structure it is, vec2 is relative position of a hut compared
|
||||||
|
// to origin, ori tells which way structure should face
|
||||||
|
structure_locations: Vec<(GnarlingStructure, Vec2<i32>, Ori)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GnarlingStructure {
|
||||||
|
Hut,
|
||||||
|
Totem,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GnarlingStructure {
|
||||||
|
fn required_separation(&self, other: &Self) -> i32 {
|
||||||
|
match (self, other) {
|
||||||
|
(Self::Hut, Self::Hut) => 15,
|
||||||
|
(Self::Hut, Self::Totem) | (Self::Totem, Self::Hut) => 20,
|
||||||
|
(Self::Totem, Self::Totem) => 50,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SECTIONS_PER_WALL_SEGMENT: usize = 3;
|
const SECTIONS_PER_WALL_SEGMENT: usize = 3;
|
||||||
@ -49,7 +68,7 @@ impl GnarlingFortification {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let gate_index = rng.gen_range(0..wall_corners.len()) * SECTIONS_PER_WALL_SEGMENT;
|
let gate_index = rng.gen_range(0..wall_corners.len());
|
||||||
|
|
||||||
// This adds additional points for the wall on the line between two points,
|
// This adds additional points for the wall on the line between two points,
|
||||||
// allowing the wall to better handle slopes
|
// allowing the wall to better handle slopes
|
||||||
@ -74,10 +93,16 @@ impl GnarlingFortification {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let desired_huts = wall_radius.pow(2) / 100;
|
let desired_structures = wall_radius.pow(2) / 100;
|
||||||
let mut hut_locations = Vec::new();
|
let mut structure_locations = Vec::<(GnarlingStructure, Vec2<i32>, Ori)>::new();
|
||||||
for _ in 0..desired_huts {
|
for _ in 0..desired_structures {
|
||||||
if let Some(hut_loc) = attempt(16, || {
|
if let Some((hut_loc, kind)) = attempt(16, || {
|
||||||
|
// Choose structure kind
|
||||||
|
let structure_kind = match rng.gen_range(0..10) {
|
||||||
|
0 => GnarlingStructure::Totem,
|
||||||
|
_ => GnarlingStructure::Hut,
|
||||||
|
};
|
||||||
|
|
||||||
// Choose triangle
|
// Choose triangle
|
||||||
let section = rng.gen_range(0..wall_corners.len());
|
let section = rng.gen_range(0..wall_corners.len());
|
||||||
|
|
||||||
@ -97,22 +122,36 @@ impl GnarlingFortification {
|
|||||||
let corner_1_weight = rng.gen_range(0.0..(1.0 - center_weight));
|
let corner_1_weight = rng.gen_range(0.0..(1.0 - center_weight));
|
||||||
let corner_2_weight = 1.0 - center_weight - corner_1_weight;
|
let corner_2_weight = 1.0 - center_weight - corner_1_weight;
|
||||||
|
|
||||||
let hut_center: Vec2<i32> = (center * center_weight
|
let structure_center: Vec2<i32> = (center * center_weight
|
||||||
+ corner_1.as_() * corner_1_weight
|
+ corner_1.as_() * corner_1_weight
|
||||||
+ corner_2.as_() * corner_2_weight)
|
+ corner_2.as_() * corner_2_weight)
|
||||||
.as_();
|
.as_();
|
||||||
|
|
||||||
// Check that hut center not too close to another hut
|
// Check that structure not too close to another structure
|
||||||
if hut_locations
|
if structure_locations.iter().any(|(kind, loc, _door_dir)| {
|
||||||
.iter()
|
structure_center.distance_squared(*loc)
|
||||||
.any(|loc| hut_center.distance_squared(*loc) < 15_i32.pow(2))
|
< structure_kind.required_separation(kind).pow(2)
|
||||||
{
|
}) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(hut_center)
|
Some((structure_center, structure_kind))
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
hut_locations.push(hut_loc);
|
let dir_to_center = match hut_loc {
|
||||||
|
pos if pos.x.abs() > pos.y.abs() && pos.x > 0 => Ori::West,
|
||||||
|
pos if pos.x.abs() > pos.y.abs() => Ori::East,
|
||||||
|
pos if pos.y < 0 => Ori::North,
|
||||||
|
_ => Ori::South,
|
||||||
|
};
|
||||||
|
let door_rng: u32 = rng.gen_range(0..9);
|
||||||
|
let door_dir = match door_rng {
|
||||||
|
0..=3 => dir_to_center,
|
||||||
|
4..=5 => dir_to_center.cw(),
|
||||||
|
6..=7 => dir_to_center.ccw(),
|
||||||
|
// Should only be 8
|
||||||
|
_ => dir_to_center.opposite(),
|
||||||
|
};
|
||||||
|
structure_locations.push((kind, hut_loc, door_dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +163,7 @@ impl GnarlingFortification {
|
|||||||
wall_radius,
|
wall_radius,
|
||||||
ordered_wall_points,
|
ordered_wall_points,
|
||||||
gate_index,
|
gate_index,
|
||||||
hut_locations,
|
structure_locations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +177,10 @@ impl Structure for GnarlingFortification {
|
|||||||
// Create outer wall
|
// Create outer wall
|
||||||
for (i, (point, _is_tower)) in self.ordered_wall_points.iter().enumerate() {
|
for (i, (point, _is_tower)) in self.ordered_wall_points.iter().enumerate() {
|
||||||
// If wall section is a gate, skip rendering the wall
|
// If wall section is a gate, skip rendering the wall
|
||||||
if (self.gate_index..(self.gate_index + SECTIONS_PER_WALL_SEGMENT)).contains(&i) {
|
if ((self.gate_index * SECTIONS_PER_WALL_SEGMENT)
|
||||||
|
..((self.gate_index + 1) * SECTIONS_PER_WALL_SEGMENT))
|
||||||
|
.contains(&i)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,10 +381,14 @@ impl Structure for GnarlingFortification {
|
|||||||
)));
|
)));
|
||||||
});
|
});
|
||||||
|
|
||||||
self.hut_locations.iter().for_each(|loc| {
|
self.structure_locations
|
||||||
|
.iter()
|
||||||
|
.for_each(|(kind, loc, door_dir)| {
|
||||||
let wpos = self.origin + loc;
|
let wpos = self.origin + loc;
|
||||||
let alt = land.get_alt_approx(wpos) as i32;
|
let alt = land.get_alt_approx(wpos) as i32;
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
GnarlingStructure::Hut => {
|
||||||
let hut_radius = 5.0;
|
let hut_radius = 5.0;
|
||||||
let hut_wall_height = 4.0;
|
let hut_wall_height = 4.0;
|
||||||
|
|
||||||
@ -371,6 +417,34 @@ impl Structure for GnarlingFortification {
|
|||||||
))
|
))
|
||||||
.fill(Fill::Block(Block::empty()));
|
.fill(Fill::Block(Block::empty()));
|
||||||
|
|
||||||
|
// Door
|
||||||
|
let door_height = 3;
|
||||||
|
|
||||||
|
let aabb_min = |dir| {
|
||||||
|
match dir {
|
||||||
|
Ori::North | Ori::East => wpos - Vec2::one(),
|
||||||
|
Ori::South | Ori::West => wpos + Vec2::one(),
|
||||||
|
}
|
||||||
|
.with_z(alt + 1)
|
||||||
|
};
|
||||||
|
let aabb_max = |dir| {
|
||||||
|
(match dir {
|
||||||
|
Ori::North | Ori::East => wpos + Vec2::one(),
|
||||||
|
Ori::South | Ori::West => wpos - Vec2::one(),
|
||||||
|
} + dir.dir() * hut_radius as i32)
|
||||||
|
.with_z(alt + 1 + door_height)
|
||||||
|
};
|
||||||
|
|
||||||
|
painter
|
||||||
|
.prim(Primitive::Aabb(
|
||||||
|
Aabb {
|
||||||
|
min: aabb_min(*door_dir),
|
||||||
|
max: aabb_max(*door_dir),
|
||||||
|
}
|
||||||
|
.made_valid(),
|
||||||
|
))
|
||||||
|
.fill(Fill::Block(Block::empty()));
|
||||||
|
|
||||||
// Roof
|
// Roof
|
||||||
let roof_height = 3.0;
|
let roof_height = 3.0;
|
||||||
let roof_radius = hut_radius + 1.0;
|
let roof_radius = hut_radius + 1.0;
|
||||||
@ -384,6 +458,24 @@ impl Structure for GnarlingFortification {
|
|||||||
BlockKind::Wood,
|
BlockKind::Wood,
|
||||||
Rgb::new(55, 25, 8),
|
Rgb::new(55, 25, 8),
|
||||||
)));
|
)));
|
||||||
|
},
|
||||||
|
GnarlingStructure::Totem => {
|
||||||
|
let totem_pos = wpos.with_z(alt);
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref TOTEM: AssetHandle<StructuresGroup> =
|
||||||
|
PrefabStructure::load_group("site_structures.gnarling.totem");
|
||||||
|
}
|
||||||
|
|
||||||
|
let totem = TOTEM.read();
|
||||||
|
let totem = totem[self.seed as usize % totem.len()].clone();
|
||||||
|
|
||||||
|
painter
|
||||||
|
.prim(Primitive::Prefab(Box::new(totem.clone())))
|
||||||
|
.translate(totem_pos)
|
||||||
|
.fill(Fill::Prefab(Box::new(totem), totem_pos, self.seed));
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,4 +263,31 @@ pub enum Ori {
|
|||||||
|
|
||||||
impl Ori {
|
impl Ori {
|
||||||
pub fn dir(self) -> Vec2<i32> { CARDINALS[self as u8 as usize] }
|
pub fn dir(self) -> Vec2<i32> { CARDINALS[self as u8 as usize] }
|
||||||
|
|
||||||
|
pub fn cw(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Ori::North => Ori::East,
|
||||||
|
Ori::East => Ori::South,
|
||||||
|
Ori::South => Ori::West,
|
||||||
|
Ori::West => Ori::North,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ccw(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Ori::North => Ori::West,
|
||||||
|
Ori::East => Ori::North,
|
||||||
|
Ori::South => Ori::East,
|
||||||
|
Ori::West => Ori::South,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opposite(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Ori::North => Ori::South,
|
||||||
|
Ori::East => Ori::West,
|
||||||
|
Ori::South => Ori::North,
|
||||||
|
Ori::West => Ori::East,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user