mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'isse/walk-toggle' into 'master'
Roleplay stuff See merge request veloren/veloren!4171
This commit is contained in:
commit
ba02d083da
@ -38,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- A way to target non-player entities with commands. With rtsim_id: `rtsim@<id>`, with uid: `uid@<id>`.
|
- A way to target non-player entities with commands. With rtsim_id: `rtsim@<id>`, with uid: `uid@<id>`.
|
||||||
- Shorthand in voxygen for specific entities in commands, some examples `@target`, `@mount`, `@viewpoint`.
|
- Shorthand in voxygen for specific entities in commands, some examples `@target`, `@mount`, `@viewpoint`.
|
||||||
- Added hit_timing to BasicMelee abilities
|
- Added hit_timing to BasicMelee abilities
|
||||||
|
- A tavern building where npcs go to relax.
|
||||||
|
- Toggle for walking instead of running (Default: `I`).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -1880,9 +1880,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enumset"
|
name = "enumset"
|
||||||
version = "1.1.2"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e875f1719c16de097dee81ed675e2d9bb63096823ed3f0ca827b7dea3028bbbb"
|
checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enumset_derive",
|
"enumset_derive",
|
||||||
]
|
]
|
||||||
@ -7430,6 +7430,7 @@ dependencies = [
|
|||||||
"csv",
|
"csv",
|
||||||
"deflate",
|
"deflate",
|
||||||
"enum-map",
|
"enum-map",
|
||||||
|
"enumset",
|
||||||
"fallible-iterator",
|
"fallible-iterator",
|
||||||
"flate2",
|
"flate2",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
|
@ -75,3 +75,4 @@ gameinput-muteinactivemaster = Mute master volume (inactive window)
|
|||||||
gameinput-mutemusic = Mute music volume
|
gameinput-mutemusic = Mute music volume
|
||||||
gameinput-mutesfx = Mute SFX volume
|
gameinput-mutesfx = Mute SFX volume
|
||||||
gameinput-muteambience = Mute ambience volume
|
gameinput-muteambience = Mute ambience volume
|
||||||
|
gameinput-togglewalk = Toggle Walking
|
||||||
|
@ -59,6 +59,7 @@ hud-follow = Follow
|
|||||||
hud-stay= Stay
|
hud-stay= Stay
|
||||||
hud-sit = Sit
|
hud-sit = Sit
|
||||||
hud-steer = Steer
|
hud-steer = Steer
|
||||||
|
hud-lay = Lay
|
||||||
hud-portal = Portal
|
hud-portal = Portal
|
||||||
|
|
||||||
-server = Server
|
-server = Server
|
||||||
|
@ -53,6 +53,8 @@ hud-settings-invert_controller_y_axis = Invert Controller Y Axis
|
|||||||
hud-settings-enable_mouse_smoothing = Camera Smoothing
|
hud-settings-enable_mouse_smoothing = Camera Smoothing
|
||||||
hud-settings-free_look_behavior = Free look behavior
|
hud-settings-free_look_behavior = Free look behavior
|
||||||
hud-settings-auto_walk_behavior = Auto walk behavior
|
hud-settings-auto_walk_behavior = Auto walk behavior
|
||||||
|
hud-settings-walking_speed_behavior = Walking speed behavior
|
||||||
|
hud-settings-walking_speed = Walking speed
|
||||||
hud-settings-camera_clamp_behavior = Camera clamp behavior
|
hud-settings-camera_clamp_behavior = Camera clamp behavior
|
||||||
hud-settings-zoom_lock_behavior = Camera zoom lock behavior
|
hud-settings-zoom_lock_behavior = Camera zoom lock behavior
|
||||||
hud-settings-player_physics_behavior = Player physics (experimental)
|
hud-settings-player_physics_behavior = Player physics (experimental)
|
||||||
|
@ -1071,7 +1071,6 @@ impl CharacterAbility {
|
|||||||
&& match self {
|
&& match self {
|
||||||
CharacterAbility::Roll { energy_cost, .. } => {
|
CharacterAbility::Roll { energy_cost, .. } => {
|
||||||
data.physics.on_ground.is_some()
|
data.physics.on_ground.is_some()
|
||||||
&& data.inputs.move_dir.magnitude_squared() > 0.25
|
|
||||||
&& update.energy.try_change_by(-*energy_cost).is_ok()
|
&& update.energy.try_change_by(-*energy_cost).is_ok()
|
||||||
},
|
},
|
||||||
CharacterAbility::DashMelee { energy_cost, .. }
|
CharacterAbility::DashMelee { energy_cost, .. }
|
||||||
|
@ -986,6 +986,10 @@ pub struct CharacterActivity {
|
|||||||
/// `None` means that the look direction should be derived from the
|
/// `None` means that the look direction should be derived from the
|
||||||
/// orientation
|
/// orientation
|
||||||
pub look_dir: Option<Dir>,
|
pub look_dir: Option<Dir>,
|
||||||
|
/// If the character is using a Helm, this is the y direction the
|
||||||
|
/// character steering. If the character is not steering this is
|
||||||
|
/// a stale value.
|
||||||
|
pub steer_dir: f32,
|
||||||
/// If true, the owner has set this pet to stay at a fixed location and
|
/// If true, the owner has set this pet to stay at a fixed location and
|
||||||
/// to not engage in combat
|
/// to not engage in combat
|
||||||
pub is_pet_staying: bool,
|
pub is_pet_staying: bool,
|
||||||
|
@ -298,6 +298,12 @@ pub struct VolumeMounting {
|
|||||||
pub rider: Uid,
|
pub rider: Uid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VolumeMounting {
|
||||||
|
pub fn is_steering_entity(&self) -> bool {
|
||||||
|
matches!(self.pos.kind, Volume::Entity(..)) && self.block.is_controller()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Link for VolumeMounting {
|
impl Link for VolumeMounting {
|
||||||
type CreateData<'a> = (
|
type CreateData<'a> = (
|
||||||
Write<'a, VolumeRiders>,
|
Write<'a, VolumeRiders>,
|
||||||
|
@ -7,6 +7,10 @@ use std::ops::{Mul, MulAssign};
|
|||||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Default)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Default)]
|
||||||
pub struct TimeOfDay(pub f64);
|
pub struct TimeOfDay(pub f64);
|
||||||
|
|
||||||
|
impl TimeOfDay {
|
||||||
|
pub fn day(&self) -> f64 { self.0.rem_euclid(24.0 * 3600.0) }
|
||||||
|
}
|
||||||
|
|
||||||
/// A resource that stores the tick (i.e: physics) time.
|
/// A resource that stores the tick (i.e: physics) time.
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct Time(pub f64);
|
pub struct Time(pub f64);
|
||||||
|
@ -252,7 +252,7 @@ pub enum NpcActivity {
|
|||||||
HuntAnimals,
|
HuntAnimals,
|
||||||
Dance(Option<Dir>),
|
Dance(Option<Dir>),
|
||||||
Cheer(Option<Dir>),
|
Cheer(Option<Dir>),
|
||||||
Sit(Option<Dir>),
|
Sit(Option<Dir>, Option<Vec3<i32>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents event-like actions that rtsim NPCs can perform to interact with
|
/// Represents event-like actions that rtsim NPCs can perform to interact with
|
||||||
|
@ -566,22 +566,15 @@ impl SpriteKind {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn mount_offset(&self) -> Option<(Vec3<f32>, Vec3<f32>)> {
|
pub fn mount_offset(&self) -> Option<(Vec3<f32>, Vec3<f32>)> {
|
||||||
match self {
|
match self {
|
||||||
SpriteKind::ChairSingle | SpriteKind::ChairDouble | SpriteKind::Bench => Some((
|
SpriteKind::ChairSingle | SpriteKind::ChairDouble | SpriteKind::Bench => {
|
||||||
Vec3 {
|
Some((Vec3::new(0.0, 0.0, 0.5), -Vec3::unit_y()))
|
||||||
x: 0.0,
|
|
||||||
y: 0.0,
|
|
||||||
z: 0.5,
|
|
||||||
},
|
},
|
||||||
-Vec3::unit_y(),
|
SpriteKind::Helm => Some((Vec3::new(0.0, -1.0, 0.0), Vec3::unit_y())),
|
||||||
)),
|
SpriteKind::Bed => Some((Vec3::new(0.0, 0.0, 0.6), -Vec3::unit_y())),
|
||||||
SpriteKind::Helm => Some((
|
SpriteKind::BedrollSnow | SpriteKind::BedrollPirate => {
|
||||||
Vec3 {
|
Some((Vec3::new(0.0, 0.0, 0.1), -Vec3::unit_x()))
|
||||||
x: 0.0,
|
|
||||||
y: -0.6,
|
|
||||||
z: 0.2,
|
|
||||||
},
|
},
|
||||||
Vec3::unit_y(),
|
SpriteKind::Bedroll => Some((Vec3::new(0.0, 0.0, 0.1), Vec3::unit_y())),
|
||||||
)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{Body, Collider, ControlAction, Controller, InputKind, Ori, Pos, Scale, Vel},
|
comp::{
|
||||||
|
Body, CharacterActivity, Collider, ControlAction, Controller, InputKind, Ori, Pos, Scale,
|
||||||
|
Vel,
|
||||||
|
},
|
||||||
link::Is,
|
link::Is,
|
||||||
mounting::{Mount, VolumeRider},
|
mounting::{Mount, VolumeRider},
|
||||||
terrain::TerrainGrid,
|
terrain::TerrainGrid,
|
||||||
@ -24,6 +27,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
WriteStorage<'a, Pos>,
|
WriteStorage<'a, Pos>,
|
||||||
WriteStorage<'a, Vel>,
|
WriteStorage<'a, Vel>,
|
||||||
WriteStorage<'a, Ori>,
|
WriteStorage<'a, Ori>,
|
||||||
|
WriteStorage<'a, CharacterActivity>,
|
||||||
ReadStorage<'a, Body>,
|
ReadStorage<'a, Body>,
|
||||||
ReadStorage<'a, Scale>,
|
ReadStorage<'a, Scale>,
|
||||||
ReadStorage<'a, Collider>,
|
ReadStorage<'a, Collider>,
|
||||||
@ -45,6 +49,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
mut positions,
|
mut positions,
|
||||||
mut velocities,
|
mut velocities,
|
||||||
mut orientations,
|
mut orientations,
|
||||||
|
mut character_activity,
|
||||||
bodies,
|
bodies,
|
||||||
scales,
|
scales,
|
||||||
colliders,
|
colliders,
|
||||||
@ -174,6 +179,12 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
if is_volume_rider.block.is_controller() {
|
if is_volume_rider.block.is_controller() {
|
||||||
if let Some((actions, inputs)) = inputs {
|
if let Some((actions, inputs)) = inputs {
|
||||||
|
if let Some(mut character_activity) = character_activity
|
||||||
|
.get_mut(entity)
|
||||||
|
.filter(|c| c.steer_dir != inputs.move_dir.y)
|
||||||
|
{
|
||||||
|
character_activity.steer_dir = inputs.move_dir.y;
|
||||||
|
}
|
||||||
match is_volume_rider.pos.kind {
|
match is_volume_rider.pos.kind {
|
||||||
common::mounting::Volume::Entity(uid) => {
|
common::mounting::Volume::Entity(uid) => {
|
||||||
if let Some(controller) =
|
if let Some(controller) =
|
||||||
|
@ -79,7 +79,9 @@ impl Controller {
|
|||||||
|
|
||||||
pub fn do_cheer(&mut self, dir: Option<Dir>) { self.activity = Some(NpcActivity::Cheer(dir)); }
|
pub fn do_cheer(&mut self, dir: Option<Dir>) { self.activity = Some(NpcActivity::Cheer(dir)); }
|
||||||
|
|
||||||
pub fn do_sit(&mut self, dir: Option<Dir>) { self.activity = Some(NpcActivity::Sit(dir)); }
|
pub fn do_sit(&mut self, dir: Option<Dir>, pos: Option<Vec3<i32>>) {
|
||||||
|
self.activity = Some(NpcActivity::Sit(dir, pos));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn say(&mut self, target: impl Into<Option<Actor>>, content: comp::Content) {
|
pub fn say(&mut self, target: impl Into<Option<Actor>>, content: comp::Content) {
|
||||||
self.actions.push(NpcAction::Say(target.into(), content));
|
self.actions.push(NpcAction::Say(target.into(), content));
|
||||||
|
@ -113,6 +113,7 @@ impl Data {
|
|||||||
PlotKind::House(_)
|
PlotKind::House(_)
|
||||||
| PlotKind::Workshop(_)
|
| PlotKind::Workshop(_)
|
||||||
| PlotKind::AirshipDock(_)
|
| PlotKind::AirshipDock(_)
|
||||||
|
| PlotKind::Tavern(_)
|
||||||
| PlotKind::Plaza
|
| PlotKind::Plaza
|
||||||
| PlotKind::SavannahPit(_)
|
| PlotKind::SavannahPit(_)
|
||||||
| PlotKind::SavannahHut(_)
|
| PlotKind::SavannahHut(_)
|
||||||
|
@ -38,7 +38,7 @@ use vek::*;
|
|||||||
use world::{
|
use world::{
|
||||||
civ::{self, Track},
|
civ::{self, Track},
|
||||||
site::{Site as WorldSite, SiteKind},
|
site::{Site as WorldSite, SiteKind},
|
||||||
site2::{self, PlotKind, TileKind},
|
site2::{self, plot::tavern, PlotKind, TileKind},
|
||||||
util::NEIGHBORS,
|
util::NEIGHBORS,
|
||||||
IndexRef, World,
|
IndexRef, World,
|
||||||
};
|
};
|
||||||
@ -325,7 +325,9 @@ impl Rule for NpcAi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn idle<S: State>() -> impl Action<S> { just(|ctx, _| ctx.controller.do_idle()).debug(|| "idle") }
|
fn idle<S: State>() -> impl Action<S> + Clone {
|
||||||
|
just(|ctx, _| ctx.controller.do_idle()).debug(|| "idle")
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to walk toward a 3D position without caring for obstacles.
|
/// Try to walk toward a 3D position without caring for obstacles.
|
||||||
fn goto<S: State>(wpos: Vec3<f32>, speed_factor: f32, goal_dist: f32) -> impl Action<S> {
|
fn goto<S: State>(wpos: Vec3<f32>, speed_factor: f32, goal_dist: f32) -> impl Action<S> {
|
||||||
@ -578,7 +580,7 @@ fn travel_to_site<S: State>(tgt_site: SiteId, speed_factor: f32) -> impl Action<
|
|||||||
.map(|_, _| ())
|
.map(|_, _| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn talk_to<S: State>(tgt: Actor, _subject: Option<Subject>) -> impl Action<S> {
|
fn talk_to<S: State>(tgt: Actor, _subject: Option<Subject>) -> impl Action<S> + Clone {
|
||||||
now(move |ctx, _| {
|
now(move |ctx, _| {
|
||||||
if matches!(tgt, Actor::Npc(_)) && ctx.rng.gen_bool(0.2) {
|
if matches!(tgt, Actor::Npc(_)) && ctx.rng.gen_bool(0.2) {
|
||||||
// Cut off the conversation sometimes to avoid infinite conversations (but only
|
// Cut off the conversation sometimes to avoid infinite conversations (but only
|
||||||
@ -630,7 +632,7 @@ fn talk_to<S: State>(tgt: Actor, _subject: Option<Subject>) -> impl Action<S> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socialize() -> impl Action<EveryRange> {
|
fn socialize() -> impl Action<EveryRange> + Clone {
|
||||||
now(move |ctx, socialize: &mut EveryRange| {
|
now(move |ctx, socialize: &mut EveryRange| {
|
||||||
// Skip most socialising actions if we're not loaded
|
// Skip most socialising actions if we're not loaded
|
||||||
if matches!(ctx.npc.mode, SimulationMode::Loaded) && socialize.should(ctx) {
|
if matches!(ctx.npc.mode, SimulationMode::Loaded) && socialize.should(ctx) {
|
||||||
@ -758,6 +760,8 @@ fn choose_plaza(ctx: &mut NpcCtx, site: SiteId) -> Option<Vec2<f32>> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const WALKING_SPEED: f32 = 0.35;
|
||||||
|
|
||||||
fn villager(visiting_site: SiteId) -> impl Action<DefaultState> {
|
fn villager(visiting_site: SiteId) -> impl Action<DefaultState> {
|
||||||
choose(move |ctx, state: &mut DefaultState| {
|
choose(move |ctx, state: &mut DefaultState| {
|
||||||
// Consider moving home if the home site gets too full
|
// Consider moving home if the home site gets too full
|
||||||
@ -804,8 +808,9 @@ fn villager(visiting_site: SiteId) -> impl Action<DefaultState> {
|
|||||||
.then(travel_to_site(new_home, 0.5))
|
.then(travel_to_site(new_home, 0.5))
|
||||||
.then(just(move |ctx, _| ctx.controller.set_new_home(new_home))));
|
.then(just(move |ctx, _| ctx.controller.set_new_home(new_home))));
|
||||||
}
|
}
|
||||||
|
let day_period = DayPeriod::from(ctx.time_of_day.0);
|
||||||
if DayPeriod::from(ctx.time_of_day.0).is_dark()
|
let is_weekend = ctx.time_of_day.day() as u64 % 6 == 0;
|
||||||
|
if day_period.is_dark()
|
||||||
&& !matches!(ctx.npc.profession(), Some(Profession::Guard))
|
&& !matches!(ctx.npc.profession(), Some(Profession::Guard))
|
||||||
{
|
{
|
||||||
return important(
|
return important(
|
||||||
@ -845,18 +850,18 @@ fn villager(visiting_site: SiteId) -> impl Action<DefaultState> {
|
|||||||
})
|
})
|
||||||
.debug(|| "find somewhere to sleep"),
|
.debug(|| "find somewhere to sleep"),
|
||||||
);
|
);
|
||||||
// Villagers with roles should perform those roles
|
|
||||||
}
|
}
|
||||||
// Visiting villagers in DesertCity who are not Merchants should sit down in the Arena during the day
|
// Go do something fun on evenings and holidays, or on random days.
|
||||||
else if matches!(ctx.state.data().sites[visiting_site].world_site.map(|ws| &ctx.index.sites.get(ws).kind), Some(SiteKind::DesertCity(_)))
|
else if
|
||||||
&& !matches!(ctx.npc.profession(), Some(Profession::Merchant | Profession::Guard))
|
// Ain't no rest for the wicked
|
||||||
&& ctx.rng.gen_bool(1.0 / 3.0)
|
!matches!(ctx.npc.profession(), Some(Profession::Guard))
|
||||||
{
|
&& (matches!(day_period, DayPeriod::Evening) || is_weekend || ctx.rng.gen_bool(0.05)) {
|
||||||
let wait_time = ctx.rng.gen_range(100.0..300.0);
|
let mut fun_stuff = Vec::new();
|
||||||
|
|
||||||
if let Some(ws_id) = ctx.state.data().sites[visiting_site].world_site
|
if let Some(ws_id) = ctx.state.data().sites[visiting_site].world_site
|
||||||
&& let Some(ws) = ctx.index.sites.get(ws_id).site2()
|
&& let Some(ws) = ctx.index.sites.get(ws_id).site2() {
|
||||||
&& let Some(arena) = ws.plots().find_map(|p| match p.kind() { PlotKind::DesertCityArena(a) => Some(a), _ => None})
|
if let Some(arena) = ws.plots().find_map(|p| match p.kind() { PlotKind::DesertCityArena(a) => Some(a), _ => None}) {
|
||||||
{
|
let wait_time = ctx.rng.gen_range(100.0..300.0);
|
||||||
// We don't use Z coordinates for seats because they are complicated to calculate from the Ramp procedural generation
|
// We don't use Z coordinates for seats because they are complicated to calculate from the Ramp procedural generation
|
||||||
// and using goto_2d seems to work just fine. However it also means that NPC will never go seat on the stands
|
// and using goto_2d seems to work just fine. However it also means that NPC will never go seat on the stands
|
||||||
// on the first floor of the arena. This is a compromise that was made because in the current arena procedural generation
|
// on the first floor of the arena. This is a compromise that was made because in the current arena procedural generation
|
||||||
@ -874,7 +879,7 @@ fn villager(visiting_site: SiteId) -> impl Action<DefaultState> {
|
|||||||
};
|
};
|
||||||
let look_dir = Dir::from_unnormalized(arena_center - seat);
|
let look_dir = Dir::from_unnormalized(arena_center - seat);
|
||||||
// Walk to an arena seat, cheer, sit and dance
|
// Walk to an arena seat, cheer, sit and dance
|
||||||
return casual(just(move |ctx, _| ctx.controller.say(None, Content::localized("npc-speech-arena")))
|
let action = casual(just(move |ctx, _| ctx.controller.say(None, Content::localized("npc-speech-arena")))
|
||||||
.then(goto_2d(seat.xy(), 0.6, 1.0).debug(|| "go to arena"))
|
.then(goto_2d(seat.xy(), 0.6, 1.0).debug(|| "go to arena"))
|
||||||
// Turn toward the centre of the arena and watch the action!
|
// Turn toward the centre of the arena and watch the action!
|
||||||
.then(choose(move |ctx, _| if ctx.rng.gen_bool(0.3) {
|
.then(choose(move |ctx, _| if ctx.rng.gen_bool(0.3) {
|
||||||
@ -882,14 +887,105 @@ fn villager(visiting_site: SiteId) -> impl Action<DefaultState> {
|
|||||||
} else if ctx.rng.gen_bool(0.15) {
|
} else if ctx.rng.gen_bool(0.15) {
|
||||||
casual(just(move |ctx,_| ctx.controller.do_dance(look_dir)).repeat().stop_if(timeout(5.0)))
|
casual(just(move |ctx,_| ctx.controller.do_dance(look_dir)).repeat().stop_if(timeout(5.0)))
|
||||||
} else {
|
} else {
|
||||||
casual(just(move |ctx,_| ctx.controller.do_sit(look_dir)).repeat().stop_if(timeout(15.0)))
|
casual(just(move |ctx,_| ctx.controller.do_sit(look_dir, None)).repeat().stop_if(timeout(15.0)))
|
||||||
})
|
})
|
||||||
.repeat()
|
.repeat()
|
||||||
.stop_if(timeout(wait_time)))
|
.stop_if(timeout(wait_time)))
|
||||||
.map(|_, _| ())
|
.map(|_, _| ())
|
||||||
.boxed());
|
.boxed());
|
||||||
|
fun_stuff.push(action);
|
||||||
}
|
}
|
||||||
} else if matches!(ctx.npc.profession(), Some(Profession::Herbalist)) && ctx.rng.gen_bool(0.8)
|
if let Some(tavern) = ws.plots().filter_map(|p| match p.kind() { PlotKind::Tavern(a) => Some(a), _ => None }).choose(&mut ctx.rng) {
|
||||||
|
let wait_time = ctx.rng.gen_range(100.0..300.0);
|
||||||
|
|
||||||
|
let (stage_aabr, stage_z) = tavern.rooms.values().flat_map(|room| {
|
||||||
|
room.details.iter().filter_map(|detail| match detail {
|
||||||
|
tavern::Detail::Stage { aabr } => Some((*aabr, room.bounds.min.z + 1)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}).choose(&mut ctx.rng).unwrap_or((tavern.bounds, tavern.door_wpos.z));
|
||||||
|
|
||||||
|
let bar_pos = tavern.rooms.values().flat_map(|room|
|
||||||
|
room.details.iter().filter_map(|detail| match detail {
|
||||||
|
tavern::Detail::Bar { aabr } => {
|
||||||
|
let side = site2::util::Dir::from_vec2(room.bounds.center().xy() - aabr.center());
|
||||||
|
let pos = side.select_aabr_with(*aabr, aabr.center()) + side.to_vec2();
|
||||||
|
|
||||||
|
Some(pos.with_z(room.bounds.min.z))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
).choose(&mut ctx.rng).unwrap_or(stage_aabr.center().with_z(stage_z));
|
||||||
|
|
||||||
|
// Pick a chair that is theirs for the stay
|
||||||
|
let chair_pos = tavern.rooms.values().flat_map(|room| {
|
||||||
|
let z = room.bounds.min.z;
|
||||||
|
room.details.iter().filter_map(move |detail| match detail {
|
||||||
|
tavern::Detail::Table { pos, chairs } => Some(chairs.into_iter().map(move |dir| pos.with_z(z) + dir.to_vec2())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
).choose(&mut ctx.rng)
|
||||||
|
// This path is possible, but highly unlikely.
|
||||||
|
.unwrap_or(bar_pos);
|
||||||
|
|
||||||
|
let stage_aabr = stage_aabr.as_::<f32>();
|
||||||
|
let stage_z = stage_z as f32;
|
||||||
|
|
||||||
|
let action = casual(travel_to_point(tavern.door_wpos.xy().as_() + 0.5, 0.8).then(choose(move |ctx, (last_action, _)| {
|
||||||
|
let action = [0, 1, 2].into_iter().filter(|i| *last_action != Some(*i)).choose(&mut ctx.rng).expect("We have at least 2 elements");
|
||||||
|
let socialize = socialize().map_state(|(_, timer)| timer).repeat();
|
||||||
|
match action {
|
||||||
|
// Go and dance on a stage.
|
||||||
|
0 => {
|
||||||
|
casual(now(move |ctx, (last_action, _)| {
|
||||||
|
*last_action = Some(action);
|
||||||
|
goto(stage_aabr.min.map2(stage_aabr.max, |a, b| ctx.rng.gen_range(a..b)).with_z(stage_z), WALKING_SPEED, 1.0)
|
||||||
|
})
|
||||||
|
.then(just(move |ctx,_| ctx.controller.do_dance(None)).repeat().stop_if(timeout(ctx.rng.gen_range(20.0..30.0))))
|
||||||
|
.map(|_, _| ())
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// Go and sit at a table.
|
||||||
|
1 => {
|
||||||
|
casual(
|
||||||
|
now(move |ctx, (last_action, _)| {
|
||||||
|
*last_action = Some(action);
|
||||||
|
goto(chair_pos.as_() + 0.5, WALKING_SPEED, 1.0).then(just(move |ctx, _| ctx.controller.do_sit(None, Some(chair_pos)))).then(socialize.clone().stop_if(timeout(ctx.rng.gen_range(30.0..60.0)))).map(|_, _| ())
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// Go to the bar.
|
||||||
|
_ => {
|
||||||
|
casual(
|
||||||
|
now(move |ctx, (last_action, _)| {
|
||||||
|
*last_action = Some(action);
|
||||||
|
goto(bar_pos.as_() + 0.5, WALKING_SPEED, 1.0).then(socialize.clone().stop_if(timeout(ctx.rng.gen_range(10.0..25.0)))).map(|_, _| ())
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.with_state((None::<u32>, every_range(5.0..10.0)))
|
||||||
|
.repeat()
|
||||||
|
.stop_if(timeout(wait_time)))
|
||||||
|
.map(|_, _| ())
|
||||||
|
.boxed()
|
||||||
|
);
|
||||||
|
|
||||||
|
fun_stuff.push(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if !fun_stuff.is_empty() {
|
||||||
|
let i = ctx.rng.gen_range(0..fun_stuff.len());
|
||||||
|
return fun_stuff.swap_remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Villagers with roles should perform those roles
|
||||||
|
else if matches!(ctx.npc.profession(), Some(Profession::Herbalist)) && ctx.rng.gen_bool(0.8)
|
||||||
{
|
{
|
||||||
if let Some(forest_wpos) = find_forest(ctx) {
|
if let Some(forest_wpos) = find_forest(ctx) {
|
||||||
return casual(
|
return casual(
|
||||||
|
@ -254,7 +254,7 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
|||||||
| NpcActivity::HuntAnimals
|
| NpcActivity::HuntAnimals
|
||||||
| NpcActivity::Dance(_)
|
| NpcActivity::Dance(_)
|
||||||
| NpcActivity::Cheer(_)
|
| NpcActivity::Cheer(_)
|
||||||
| NpcActivity::Sit(_),
|
| NpcActivity::Sit(..),
|
||||||
) => {
|
) => {
|
||||||
// TODO: Maybe they should walk around randomly
|
// TODO: Maybe they should walk around randomly
|
||||||
// when gathering resources?
|
// when gathering resources?
|
||||||
|
@ -29,6 +29,7 @@ use common::{
|
|||||||
consts::MAX_MOUNT_RANGE,
|
consts::MAX_MOUNT_RANGE,
|
||||||
effect::{BuffEffect, Effect},
|
effect::{BuffEffect, Effect},
|
||||||
event::{Emitter, ServerEvent},
|
event::{Emitter, ServerEvent},
|
||||||
|
mounting::VolumePos,
|
||||||
path::TraversalConfig,
|
path::TraversalConfig,
|
||||||
rtsim::NpcActivity,
|
rtsim::NpcActivity,
|
||||||
states::basic_beam,
|
states::basic_beam,
|
||||||
@ -51,9 +52,7 @@ impl<'a> AgentData<'a> {
|
|||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
||||||
pub fn glider_fall(&self, controller: &mut Controller, read_data: &ReadData) {
|
pub fn glider_fall(&self, controller: &mut Controller, read_data: &ReadData) {
|
||||||
if read_data.is_riders.contains(*self.entity) {
|
self.dismount(controller, read_data);
|
||||||
controller.push_event(ControlEvent::Unmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.push_action(ControlAction::GlideWield);
|
controller.push_action(ControlAction::GlideWield);
|
||||||
|
|
||||||
@ -73,9 +72,7 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn fly_upward(&self, controller: &mut Controller, read_data: &ReadData) {
|
pub fn fly_upward(&self, controller: &mut Controller, read_data: &ReadData) {
|
||||||
if read_data.is_riders.contains(*self.entity) {
|
self.dismount(controller, read_data);
|
||||||
controller.push_event(ControlEvent::Unmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.push_basic_input(InputKind::Fly);
|
controller.push_basic_input(InputKind::Fly);
|
||||||
controller.inputs.move_z = 1.0;
|
controller.inputs.move_z = 1.0;
|
||||||
@ -96,9 +93,7 @@ impl<'a> AgentData<'a> {
|
|||||||
path: Path,
|
path: Path,
|
||||||
speed_multiplier: Option<f32>,
|
speed_multiplier: Option<f32>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if read_data.is_riders.contains(*self.entity) {
|
self.dismount(controller, read_data);
|
||||||
controller.push_event(ControlEvent::Unmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
let partial_path_tgt_pos = |pos_difference: Vec3<f32>| {
|
let partial_path_tgt_pos = |pos_difference: Vec3<f32>| {
|
||||||
self.pos.0
|
self.pos.0
|
||||||
@ -242,6 +237,14 @@ impl<'a> AgentData<'a> {
|
|||||||
'activity: {
|
'activity: {
|
||||||
match agent.rtsim_controller.activity {
|
match agent.rtsim_controller.activity {
|
||||||
Some(NpcActivity::Goto(travel_to, speed_factor)) => {
|
Some(NpcActivity::Goto(travel_to, speed_factor)) => {
|
||||||
|
if read_data
|
||||||
|
.is_volume_riders
|
||||||
|
.get(*self.entity)
|
||||||
|
.map_or(false, |r| !r.is_steering_entity())
|
||||||
|
{
|
||||||
|
controller.push_event(ControlEvent::Unmount);
|
||||||
|
}
|
||||||
|
|
||||||
// If it has an rtsim destination and can fly, then it should.
|
// If it has an rtsim destination and can fly, then it should.
|
||||||
// If it is flying and bumps something above it, then it should move down.
|
// If it is flying and bumps something above it, then it should move down.
|
||||||
if self.traversal_config.can_fly
|
if self.traversal_config.can_fly
|
||||||
@ -399,7 +402,15 @@ impl<'a> AgentData<'a> {
|
|||||||
controller.push_action(ControlAction::Talk);
|
controller.push_action(ControlAction::Talk);
|
||||||
break 'activity; // Don't fall through to idle wandering
|
break 'activity; // Don't fall through to idle wandering
|
||||||
},
|
},
|
||||||
Some(NpcActivity::Sit(dir)) => {
|
Some(NpcActivity::Sit(dir, pos)) => {
|
||||||
|
if let Some(pos) =
|
||||||
|
pos.filter(|p| read_data.terrain.get(*p).is_ok_and(|b| b.is_mountable()))
|
||||||
|
{
|
||||||
|
if !read_data.is_volume_riders.contains(*self.entity) {
|
||||||
|
controller
|
||||||
|
.push_event(ControlEvent::MountVolume(VolumePos::terrain(pos)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if let Some(look_dir) = dir {
|
if let Some(look_dir) = dir {
|
||||||
controller.inputs.look_dir = look_dir;
|
controller.inputs.look_dir = look_dir;
|
||||||
if self.ori.look_dir().dot(look_dir.to_vec()) < 0.95 {
|
if self.ori.look_dir().dot(look_dir.to_vec()) < 0.95 {
|
||||||
@ -410,6 +421,7 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
controller.push_action(ControlAction::Sit);
|
controller.push_action(ControlAction::Sit);
|
||||||
|
}
|
||||||
break 'activity; // Don't fall through to idle wandering
|
break 'activity; // Don't fall through to idle wandering
|
||||||
},
|
},
|
||||||
Some(NpcActivity::HuntAnimals) => {
|
Some(NpcActivity::HuntAnimals) => {
|
||||||
@ -581,7 +593,9 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
tgt_pos: &Pos,
|
tgt_pos: &Pos,
|
||||||
) {
|
) {
|
||||||
if read_data.is_riders.contains(*self.entity) {
|
if read_data.is_riders.contains(*self.entity)
|
||||||
|
|| read_data.is_volume_riders.contains(*self.entity)
|
||||||
|
{
|
||||||
controller.push_event(ControlEvent::Unmount);
|
controller.push_event(ControlEvent::Unmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,7 +651,9 @@ impl<'a> AgentData<'a> {
|
|||||||
// Proportion of full speed
|
// Proportion of full speed
|
||||||
const MAX_FLEE_SPEED: f32 = 0.65;
|
const MAX_FLEE_SPEED: f32 = 0.65;
|
||||||
|
|
||||||
if read_data.is_riders.contains(*self.entity) {
|
if read_data.is_riders.contains(*self.entity)
|
||||||
|
|| read_data.is_volume_riders.contains(*self.entity)
|
||||||
|
{
|
||||||
controller.push_event(ControlEvent::Unmount);
|
controller.push_event(ControlEvent::Unmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -993,9 +1009,7 @@ impl<'a> AgentData<'a> {
|
|||||||
#[cfg(feature = "be-dyn-lib")]
|
#[cfg(feature = "be-dyn-lib")]
|
||||||
let rng = &mut thread_rng();
|
let rng = &mut thread_rng();
|
||||||
|
|
||||||
if read_data.is_riders.contains(*self.entity) {
|
self.dismount(controller, read_data);
|
||||||
controller.push_event(ControlEvent::Unmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tool_tactic = |tool_kind| match tool_kind {
|
let tool_tactic = |tool_kind| match tool_kind {
|
||||||
ToolKind::Bow => Tactic::Bow,
|
ToolKind::Bow => Tactic::Bow,
|
||||||
@ -1999,4 +2013,15 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dismount(&self, controller: &mut Controller, read_data: &ReadData) {
|
||||||
|
if read_data.is_riders.contains(*self.entity)
|
||||||
|
|| read_data
|
||||||
|
.is_volume_riders
|
||||||
|
.get(*self.entity)
|
||||||
|
.map_or(false, |r| !r.is_steering_entity())
|
||||||
|
{
|
||||||
|
controller.push_event(ControlEvent::Unmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,13 @@ pub mod selfbuff;
|
|||||||
pub mod shockwave;
|
pub mod shockwave;
|
||||||
pub mod shoot;
|
pub mod shoot;
|
||||||
pub mod sit;
|
pub mod sit;
|
||||||
|
pub mod sleep;
|
||||||
pub mod sneak;
|
pub mod sneak;
|
||||||
pub mod sneakequip;
|
pub mod sneakequip;
|
||||||
pub mod sneakwield;
|
pub mod sneakwield;
|
||||||
pub mod staggered;
|
pub mod staggered;
|
||||||
pub mod stand;
|
pub mod stand;
|
||||||
|
pub mod steer;
|
||||||
pub mod stunned;
|
pub mod stunned;
|
||||||
pub mod swim;
|
pub mod swim;
|
||||||
pub mod swimwield;
|
pub mod swimwield;
|
||||||
@ -51,11 +53,11 @@ pub use self::{
|
|||||||
mount::MountAnimation, music::MusicAnimation, rapidmelee::RapidMeleeAnimation,
|
mount::MountAnimation, music::MusicAnimation, rapidmelee::RapidMeleeAnimation,
|
||||||
repeater::RepeaterAnimation, ripostemelee::RiposteMeleeAnimation, roll::RollAnimation,
|
repeater::RepeaterAnimation, ripostemelee::RiposteMeleeAnimation, roll::RollAnimation,
|
||||||
run::RunAnimation, selfbuff::SelfBuffAnimation, shockwave::ShockwaveAnimation,
|
run::RunAnimation, selfbuff::SelfBuffAnimation, shockwave::ShockwaveAnimation,
|
||||||
shoot::ShootAnimation, sit::SitAnimation, sneak::SneakAnimation,
|
shoot::ShootAnimation, sit::SitAnimation, sleep::SleepAnimation, sneak::SneakAnimation,
|
||||||
sneakequip::SneakEquipAnimation, sneakwield::SneakWieldAnimation,
|
sneakequip::SneakEquipAnimation, sneakwield::SneakWieldAnimation,
|
||||||
staggered::StaggeredAnimation, stand::StandAnimation, stunned::StunnedAnimation,
|
staggered::StaggeredAnimation, stand::StandAnimation, steer::SteerAnimation,
|
||||||
swim::SwimAnimation, swimwield::SwimWieldAnimation, talk::TalkAnimation,
|
stunned::StunnedAnimation, swim::SwimAnimation, swimwield::SwimWieldAnimation,
|
||||||
wallrun::WallrunAnimation, wield::WieldAnimation,
|
talk::TalkAnimation, wallrun::WallrunAnimation, wield::WieldAnimation,
|
||||||
};
|
};
|
||||||
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton, TrailSource};
|
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton, TrailSource};
|
||||||
use common::comp::{
|
use common::comp::{
|
||||||
@ -431,8 +433,8 @@ impl CharacterSkeleton {
|
|||||||
* ((acc_vel * lab * 1.6).sin());
|
* ((acc_vel * lab * 1.6).sin());
|
||||||
|
|
||||||
self.lantern.position = Vec3::new(s_a.lantern.0, s_a.lantern.1, s_a.lantern.2);
|
self.lantern.position = Vec3::new(s_a.lantern.0, s_a.lantern.1, s_a.lantern.2);
|
||||||
self.lantern.orientation =
|
self.lantern.orientation = Quaternion::rotation_x(shorte * 0.7 * speednorm.powi(2) + 0.4)
|
||||||
Quaternion::rotation_x(shorte * 0.7 + 0.4) * Quaternion::rotation_y(shorte * 0.4);
|
* Quaternion::rotation_y(shorte * 0.4 * speednorm.powi(2));
|
||||||
self.lantern.scale = Vec3::one() * 0.65;
|
self.lantern.scale = Vec3::one() * 0.65;
|
||||||
self.hold.scale = Vec3::one() * 0.0;
|
self.hold.scale = Vec3::one() * 0.0;
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ impl Animation for RunAnimation {
|
|||||||
next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1);
|
next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1);
|
||||||
next.back.orientation =
|
next.back.orientation =
|
||||||
Quaternion::rotation_x(-0.05 + short * 0.02 + noisea * 0.02 + noiseb * 0.02)
|
Quaternion::rotation_x(-0.05 + short * 0.02 + noisea * 0.02 + noiseb * 0.02)
|
||||||
* Quaternion::rotation_y(foothorir * 0.2);
|
* Quaternion::rotation_y(foothorir * 0.35 * speednorm.powi(2));
|
||||||
|
|
||||||
next.shorts.position = Vec3::new(0.0, 0.65 + s_a.shorts.0, 0.65 * speednorm + s_a.shorts.1);
|
next.shorts.position = Vec3::new(0.0, 0.65 + s_a.shorts.0, 0.65 * speednorm + s_a.shorts.1);
|
||||||
next.shorts.orientation = Quaternion::rotation_x(0.2 * speednorm)
|
next.shorts.orientation = Quaternion::rotation_x(0.2 * speednorm)
|
||||||
@ -163,22 +163,24 @@ impl Animation for RunAnimation {
|
|||||||
-s_a.hand.0 * 1.2 - foothorir * 1.3 * speednorm
|
-s_a.hand.0 * 1.2 - foothorir * 1.3 * speednorm
|
||||||
+ (foothoril.abs().powi(2) - 0.5) * speednorm * 4.0,
|
+ (foothoril.abs().powi(2) - 0.5) * speednorm * 4.0,
|
||||||
s_a.hand.1 * 1.3 + foothorir * -7.0 * speednorm.powi(2) * (1.0 - sideabs),
|
s_a.hand.1 * 1.3 + foothorir * -7.0 * speednorm.powi(2) * (1.0 - sideabs),
|
||||||
s_a.hand.2 - foothorir * 2.75 * speednorm + foothoril.abs().powi(3) * speednorm * 8.0,
|
s_a.hand.2 - foothorir * 2.75 * speednorm
|
||||||
|
+ foothoril.abs().powi(3) * speednorm.powi(2) * 8.0,
|
||||||
);
|
);
|
||||||
next.hand_l.orientation =
|
next.hand_l.orientation =
|
||||||
Quaternion::rotation_x(
|
Quaternion::rotation_x(
|
||||||
0.6 * speednorm + (footrotr * -1.5 + 0.5) * speednorm * (1.0 - sideabs),
|
0.6 * speednorm + (footrotr * -1.5 + 0.5) * speednorm.powi(2) * (1.0 - sideabs),
|
||||||
) * Quaternion::rotation_y(footrotr * 0.4 * speednorm + PI * 0.07);
|
) * Quaternion::rotation_y(footrotr * 0.4 * speednorm + PI * 0.07);
|
||||||
|
|
||||||
next.hand_r.position = Vec3::new(
|
next.hand_r.position = Vec3::new(
|
||||||
s_a.hand.0 * 1.2 + foothoril * 1.3 * speednorm
|
s_a.hand.0 * 1.2 + foothoril * 1.3 * speednorm
|
||||||
- (foothorir.abs().powi(2) - 0.5) * speednorm * 4.0,
|
- (foothorir.abs().powi(2) - 0.5) * speednorm * 4.0,
|
||||||
s_a.hand.1 * 1.3 + foothoril * -7.0 * speednorm.powi(2) * (1.0 - sideabs),
|
s_a.hand.1 * 1.3 + foothoril * -7.0 * speednorm.powi(2) * (1.0 - sideabs),
|
||||||
s_a.hand.2 - foothoril * 2.75 * speednorm + foothorir.abs().powi(3) * speednorm * 8.0,
|
s_a.hand.2 - foothoril * 2.75 * speednorm
|
||||||
|
+ foothorir.abs().powi(3) * speednorm.powi(2) * 8.0,
|
||||||
);
|
);
|
||||||
next.hand_r.orientation =
|
next.hand_r.orientation =
|
||||||
Quaternion::rotation_x(
|
Quaternion::rotation_x(
|
||||||
0.6 * speednorm + (footrotl * -1.5 + 0.5) * speednorm * (1.0 - sideabs),
|
0.6 * speednorm + (footrotl * -1.5 + 0.5) * speednorm.powi(2) * (1.0 - sideabs),
|
||||||
) * Quaternion::rotation_y(footrotl * -0.4 * speednorm - PI * 0.07);
|
) * Quaternion::rotation_y(footrotl * -0.4 * speednorm - PI * 0.07);
|
||||||
|
|
||||||
next.foot_l.position = Vec3::new(
|
next.foot_l.position = Vec3::new(
|
||||||
|
114
voxygen/anim/src/character/sleep.rs
Normal file
114
voxygen/anim/src/character/sleep.rs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CharacterSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::comp::item::ToolKind;
|
||||||
|
use std::{f32::consts::PI, ops::Mul};
|
||||||
|
|
||||||
|
pub struct SleepAnimation;
|
||||||
|
|
||||||
|
impl Animation for SleepAnimation {
|
||||||
|
type Dependency<'a> = (Option<ToolKind>, Option<ToolKind>, f32);
|
||||||
|
type Skeleton = CharacterSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"character_sleep\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_sleep")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(_active_tool_kind, _second_tool_kind, global_time): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
_rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
let slow = (anim_time * 1.0).sin();
|
||||||
|
let slowa = (anim_time * 1.0 + PI / 2.0).sin();
|
||||||
|
let stop = (anim_time * 3.0).min(PI / 2.0).sin();
|
||||||
|
|
||||||
|
let head_look = Vec2::new(
|
||||||
|
(global_time * 0.05 + anim_time / 15.0)
|
||||||
|
.floor()
|
||||||
|
.mul(7331.0)
|
||||||
|
.sin()
|
||||||
|
* 0.25,
|
||||||
|
(global_time * 0.05 + anim_time / 15.0)
|
||||||
|
.floor()
|
||||||
|
.mul(1337.0)
|
||||||
|
.sin()
|
||||||
|
* 0.125,
|
||||||
|
);
|
||||||
|
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1 + slow * 0.1 + stop * -0.8);
|
||||||
|
next.head.orientation = Quaternion::rotation_z(head_look.x + slow * 0.2 - slow * 0.1)
|
||||||
|
* Quaternion::rotation_x((slowa * -0.1 + slow * 0.1 + head_look.y).abs());
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(
|
||||||
|
0.0,
|
||||||
|
s_a.chest.0 + stop * -0.4,
|
||||||
|
s_a.chest.1 + slow * 0.1 + stop * -0.8,
|
||||||
|
);
|
||||||
|
next.chest.orientation = Quaternion::rotation_x(stop * 0.15 + 1.0);
|
||||||
|
|
||||||
|
next.belt.position = Vec3::new(0.0, s_a.belt.0 + stop * 1.2, s_a.belt.1);
|
||||||
|
next.belt.orientation = Quaternion::rotation_x(stop * 0.3);
|
||||||
|
|
||||||
|
next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1);
|
||||||
|
|
||||||
|
next.shorts.position = Vec3::new(0.0, s_a.shorts.0 + stop * 2.5, s_a.shorts.1 + stop * 0.6);
|
||||||
|
next.shorts.orientation = Quaternion::rotation_x(stop * 0.6);
|
||||||
|
|
||||||
|
next.hand_l.position = Vec3::new(
|
||||||
|
-s_a.hand.0 - 1.0,
|
||||||
|
s_a.hand.1 + slowa * 0.15 + 2.0,
|
||||||
|
s_a.hand.2 + slow * 0.7 + stop * -2.0,
|
||||||
|
);
|
||||||
|
next.hand_l.orientation =
|
||||||
|
Quaternion::rotation_x(slowa * -0.1 + slow * 0.1) * Quaternion::rotation_y(PI * 0.15);
|
||||||
|
|
||||||
|
next.hand_r.position = Vec3::new(
|
||||||
|
s_a.hand.0 + 1.0,
|
||||||
|
s_a.hand.1 + slowa * 0.15 + 2.0,
|
||||||
|
s_a.hand.2 + slow * 0.7 + stop * -2.0,
|
||||||
|
);
|
||||||
|
next.hand_r.orientation =
|
||||||
|
Quaternion::rotation_x(slow * -0.1 + slowa * 0.1) * Quaternion::rotation_y(PI * -0.15);
|
||||||
|
|
||||||
|
next.foot_l.position = Vec3::new(-s_a.foot.0, 6.0 + s_a.foot.1, 6.0 + s_a.foot.2);
|
||||||
|
next.foot_l.orientation = Quaternion::rotation_x(slow * 0.1 + stop * 1.2 + slow * 0.1);
|
||||||
|
|
||||||
|
next.foot_r.position = Vec3::new(s_a.foot.0, 6.0 + s_a.foot.1, 6.0 + s_a.foot.2);
|
||||||
|
next.foot_r.orientation = Quaternion::rotation_x(slowa * 0.1 + stop * 1.2 + slowa * 0.1);
|
||||||
|
|
||||||
|
next.shoulder_l.position = Vec3::new(-s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2);
|
||||||
|
next.shoulder_l.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
next.shoulder_r.position = Vec3::new(s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2);
|
||||||
|
next.shoulder_r.orientation = Quaternion::rotation_x(0.0);
|
||||||
|
|
||||||
|
next.torso.position = Vec3::new(0.0, -2.2, stop * -1.76);
|
||||||
|
|
||||||
|
if skeleton.holding_lantern {
|
||||||
|
next.hand_r.position = Vec3::new(
|
||||||
|
s_a.hand.0 + 1.0 - head_look.x * 8.0,
|
||||||
|
s_a.hand.1 + 5.0 + head_look.x * 6.0,
|
||||||
|
s_a.hand.2 + 9.0 + head_look.y * 6.0,
|
||||||
|
);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(2.25)
|
||||||
|
* Quaternion::rotation_z(0.9)
|
||||||
|
* Quaternion::rotation_y(head_look.x * 3.0)
|
||||||
|
* Quaternion::rotation_x(head_look.y * 3.0);
|
||||||
|
|
||||||
|
let fast = (anim_time * 5.0).sin();
|
||||||
|
let fast2 = (anim_time * 4.5 + 8.0).sin();
|
||||||
|
|
||||||
|
next.lantern.position = Vec3::new(-0.5, -0.5, -2.5);
|
||||||
|
next.lantern.orientation = next.hand_r.orientation.inverse()
|
||||||
|
* Quaternion::rotation_x(fast * 0.1)
|
||||||
|
* Quaternion::rotation_y(fast2 * 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
118
voxygen/anim/src/character/steer.rs
Normal file
118
voxygen/anim/src/character/steer.rs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
use super::{
|
||||||
|
super::{vek::*, Animation},
|
||||||
|
CharacterSkeleton, SkeletonAttr,
|
||||||
|
};
|
||||||
|
use common::comp::item::ToolKind;
|
||||||
|
use std::{f32::consts::PI, ops::Mul};
|
||||||
|
|
||||||
|
pub struct SteerAnimation;
|
||||||
|
|
||||||
|
impl Animation for SteerAnimation {
|
||||||
|
type Dependency<'a> = (Option<ToolKind>, Option<ToolKind>, f32, f32);
|
||||||
|
type Skeleton = CharacterSkeleton;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
|
const UPDATE_FN: &'static [u8] = b"character_steer\0";
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_steer")]
|
||||||
|
fn update_skeleton_inner(
|
||||||
|
skeleton: &Self::Skeleton,
|
||||||
|
(_active_tool_kind, _second_tool_kind, steer_dir, global_time): Self::Dependency<'_>,
|
||||||
|
anim_time: f32,
|
||||||
|
_rate: &mut f32,
|
||||||
|
s_a: &SkeletonAttr,
|
||||||
|
) -> Self::Skeleton {
|
||||||
|
let mut next = (*skeleton).clone();
|
||||||
|
|
||||||
|
let slow = (anim_time * 1.0).sin();
|
||||||
|
let head_look = Vec2::new(
|
||||||
|
(global_time + anim_time / 12.0).floor().mul(7331.0).sin() * 0.1,
|
||||||
|
(global_time + anim_time / 12.0).floor().mul(1337.0).sin() * 0.05,
|
||||||
|
);
|
||||||
|
next.head.scale = Vec3::one() * s_a.head_scale;
|
||||||
|
next.chest.scale = Vec3::one() * 1.01;
|
||||||
|
next.hand_l.scale = Vec3::one() * 1.04;
|
||||||
|
next.hand_r.scale = Vec3::one() * 1.04;
|
||||||
|
next.back.scale = Vec3::one() * 1.02;
|
||||||
|
next.hold.scale = Vec3::one() * 0.0;
|
||||||
|
next.lantern.scale = Vec3::one() * 0.65;
|
||||||
|
next.shoulder_l.scale = Vec3::one() * 1.1;
|
||||||
|
next.shoulder_r.scale = Vec3::one() * 1.1;
|
||||||
|
|
||||||
|
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1 + slow * 0.3);
|
||||||
|
next.head.orientation =
|
||||||
|
Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y.abs());
|
||||||
|
|
||||||
|
next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + slow * 0.3);
|
||||||
|
next.chest.orientation = Quaternion::rotation_z(head_look.x * 0.06);
|
||||||
|
|
||||||
|
next.belt.position = Vec3::new(0.0, s_a.belt.0, s_a.belt.1);
|
||||||
|
next.belt.orientation = Quaternion::rotation_z(head_look.x * -0.1);
|
||||||
|
|
||||||
|
next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1);
|
||||||
|
|
||||||
|
next.shorts.position = Vec3::new(0.0, s_a.shorts.0, s_a.shorts.1);
|
||||||
|
next.shorts.orientation = Quaternion::rotation_z(head_look.x * -0.2);
|
||||||
|
|
||||||
|
next.hand_l.position = Vec3::new(
|
||||||
|
-s_a.hand.0,
|
||||||
|
s_a.hand.1 + slow * 0.15,
|
||||||
|
s_a.hand.2 + slow * 0.5,
|
||||||
|
);
|
||||||
|
|
||||||
|
let helm_center = Vec3::new(0.0, 0.6, 0.75) / s_a.scaler * 11.0;
|
||||||
|
|
||||||
|
let rot = steer_dir * 0.5;
|
||||||
|
|
||||||
|
let hand_rotation = Quaternion::rotation_y(rot) * Quaternion::rotation_x(PI / 2.0);
|
||||||
|
|
||||||
|
let hand_offset = Vec3::new(rot.cos(), 0.0, -rot.sin()) * 0.4 / s_a.scaler * 11.0;
|
||||||
|
|
||||||
|
next.hand_l.position = helm_center - hand_offset;
|
||||||
|
next.hand_r.position = helm_center + hand_offset;
|
||||||
|
|
||||||
|
let ori_l = Quaternion::rotation_x(
|
||||||
|
PI / 2.0 + (next.hand_l.position.z / next.hand_l.position.x).atan(),
|
||||||
|
);
|
||||||
|
let ori_r = Quaternion::rotation_x(
|
||||||
|
PI / 2.0 - (next.hand_r.position.z / next.hand_r.position.x).atan(),
|
||||||
|
);
|
||||||
|
|
||||||
|
next.hand_l.orientation = hand_rotation * ori_l;
|
||||||
|
next.hand_r.orientation = -hand_rotation * ori_r;
|
||||||
|
|
||||||
|
next.shoulder_l.position = Vec3::new(-s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2);
|
||||||
|
next.shoulder_l.orientation = ori_r;
|
||||||
|
next.shoulder_r.position = Vec3::new(s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2);
|
||||||
|
next.shoulder_r.orientation = ori_l;
|
||||||
|
|
||||||
|
next.foot_l.position = Vec3::new(-s_a.foot.0, s_a.foot.1, s_a.foot.2);
|
||||||
|
next.foot_l.orientation = Quaternion::identity();
|
||||||
|
|
||||||
|
next.foot_r.position = Vec3::new(s_a.foot.0, s_a.foot.1, s_a.foot.2);
|
||||||
|
next.foot_r.orientation = Quaternion::identity();
|
||||||
|
|
||||||
|
next.glider.position = Vec3::new(0.0, 0.0, 10.0);
|
||||||
|
next.glider.scale = Vec3::one() * 0.0;
|
||||||
|
next.hold.position = Vec3::new(0.4, -0.3, -5.8);
|
||||||
|
|
||||||
|
if skeleton.holding_lantern {
|
||||||
|
next.hand_r.position = Vec3::new(
|
||||||
|
s_a.hand.0 - head_look.x * 6.0,
|
||||||
|
s_a.hand.1 + 5.0 - head_look.y * 10.0 + slow * 0.15,
|
||||||
|
s_a.hand.2 + 12.0 + head_look.y * 6.0 + slow * 0.5,
|
||||||
|
);
|
||||||
|
next.hand_r.orientation = Quaternion::rotation_x(2.25 + slow * -0.06)
|
||||||
|
* Quaternion::rotation_z(0.9)
|
||||||
|
* Quaternion::rotation_y(head_look.x * 1.5)
|
||||||
|
* Quaternion::rotation_x(head_look.y * 1.5);
|
||||||
|
|
||||||
|
next.lantern.position = Vec3::new(-0.5, -0.5, -2.5);
|
||||||
|
next.lantern.orientation = next.hand_r.orientation.inverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
next.torso.position = Vec3::new(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
@ -170,6 +170,8 @@ pub enum GameInput {
|
|||||||
MuteSfx,
|
MuteSfx,
|
||||||
#[strum(serialize = "gameinput-muteambience")]
|
#[strum(serialize = "gameinput-muteambience")]
|
||||||
MuteAmbience,
|
MuteAmbience,
|
||||||
|
#[strum(serialize = "gameinput-togglewalk")]
|
||||||
|
ToggleWalk,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameInput {
|
impl GameInput {
|
||||||
|
@ -342,6 +342,10 @@ widget_ids! {
|
|||||||
auto_walk_txt,
|
auto_walk_txt,
|
||||||
auto_walk_bg,
|
auto_walk_bg,
|
||||||
|
|
||||||
|
// Walking speed indicator
|
||||||
|
walking_speed_txt,
|
||||||
|
walking_speed_bg,
|
||||||
|
|
||||||
// Temporal (fading) camera zoom lock indicator
|
// Temporal (fading) camera zoom lock indicator
|
||||||
zoom_lock_txt,
|
zoom_lock_txt,
|
||||||
zoom_lock_bg,
|
zoom_lock_bg,
|
||||||
@ -2149,6 +2153,7 @@ impl Hud {
|
|||||||
BlockInteraction::Mount => {
|
BlockInteraction::Mount => {
|
||||||
let key = match block.get_sprite() {
|
let key = match block.get_sprite() {
|
||||||
Some(SpriteKind::Helm) => "hud-steer",
|
Some(SpriteKind::Helm) => "hud-steer",
|
||||||
|
Some(SpriteKind::Bed | SpriteKind::Bedroll | SpriteKind::BedrollSnow | SpriteKind::BedrollPirate) => "hud-lay",
|
||||||
_ => "hud-sit",
|
_ => "hud-sit",
|
||||||
};
|
};
|
||||||
vec![(Some(GameInput::Mount), i18n.get_msg(key).to_string())]
|
vec![(Some(GameInput::Mount), i18n.get_msg(key).to_string())]
|
||||||
|
@ -31,6 +31,9 @@ widget_ids! {
|
|||||||
camera_clamp_slider,
|
camera_clamp_slider,
|
||||||
camera_clamp_label,
|
camera_clamp_label,
|
||||||
camera_clamp_value,
|
camera_clamp_value,
|
||||||
|
walking_speed_slider,
|
||||||
|
walking_speed_label,
|
||||||
|
walking_speed_value,
|
||||||
mouse_y_invert_button,
|
mouse_y_invert_button,
|
||||||
mouse_y_invert_label,
|
mouse_y_invert_label,
|
||||||
controller_y_invert_button,
|
controller_y_invert_button,
|
||||||
@ -42,6 +45,8 @@ widget_ids! {
|
|||||||
free_look_behavior_list,
|
free_look_behavior_list,
|
||||||
auto_walk_behavior_text,
|
auto_walk_behavior_text,
|
||||||
auto_walk_behavior_list,
|
auto_walk_behavior_list,
|
||||||
|
walking_speed_behavior_text,
|
||||||
|
walking_speed_behavior_list,
|
||||||
camera_clamp_behavior_text,
|
camera_clamp_behavior_text,
|
||||||
camera_clamp_behavior_list,
|
camera_clamp_behavior_list,
|
||||||
zoom_lock_behavior_text,
|
zoom_lock_behavior_text,
|
||||||
@ -124,6 +129,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
let display_pan = self.global_state.settings.gameplay.pan_sensitivity;
|
let display_pan = self.global_state.settings.gameplay.pan_sensitivity;
|
||||||
let display_zoom = self.global_state.settings.gameplay.zoom_sensitivity;
|
let display_zoom = self.global_state.settings.gameplay.zoom_sensitivity;
|
||||||
let display_clamp = self.global_state.settings.gameplay.camera_clamp_angle;
|
let display_clamp = self.global_state.settings.gameplay.camera_clamp_angle;
|
||||||
|
let display_walking_speed = self.global_state.settings.gameplay.walking_speed;
|
||||||
|
|
||||||
// Mouse Pan Sensitivity
|
// Mouse Pan Sensitivity
|
||||||
Text::new(
|
Text::new(
|
||||||
@ -233,6 +239,38 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.set(state.ids.camera_clamp_value, ui);
|
.set(state.ids.camera_clamp_value, ui);
|
||||||
|
|
||||||
|
// Walking speed
|
||||||
|
Text::new(&self.localized_strings.get_msg("hud-settings-walking_speed"))
|
||||||
|
.down_from(state.ids.camera_clamp_slider, 10.0)
|
||||||
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.color(TEXT_COLOR)
|
||||||
|
.set(state.ids.walking_speed_label, ui);
|
||||||
|
|
||||||
|
if let Some(new_val) = ImageSlider::continuous(
|
||||||
|
display_walking_speed,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
self.imgs.slider_indicator,
|
||||||
|
self.imgs.slider,
|
||||||
|
)
|
||||||
|
.w_h(550.0, 22.0)
|
||||||
|
.down_from(state.ids.walking_speed_label, 10.0)
|
||||||
|
.track_breadth(30.0)
|
||||||
|
.slider_length(10.0)
|
||||||
|
.pad_track((5.0, 5.0))
|
||||||
|
.set(state.ids.walking_speed_slider, ui)
|
||||||
|
{
|
||||||
|
events.push(AdjustWalkingSpeed(new_val));
|
||||||
|
}
|
||||||
|
|
||||||
|
Text::new(&format!("{:.2}", display_walking_speed))
|
||||||
|
.right_from(state.ids.walking_speed_slider, 8.0)
|
||||||
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.color(TEXT_COLOR)
|
||||||
|
.set(state.ids.walking_speed_value, ui);
|
||||||
|
|
||||||
// Zoom Inversion
|
// Zoom Inversion
|
||||||
let zoom_inverted = ToggleButton::new(
|
let zoom_inverted = ToggleButton::new(
|
||||||
self.global_state.settings.gameplay.zoom_inversion,
|
self.global_state.settings.gameplay.zoom_inversion,
|
||||||
@ -240,7 +278,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
self.imgs.checkbox_checked,
|
self.imgs.checkbox_checked,
|
||||||
)
|
)
|
||||||
.w_h(18.0, 18.0)
|
.w_h(18.0, 18.0)
|
||||||
.down_from(state.ids.camera_clamp_slider, 20.0)
|
.down_from(state.ids.walking_speed_slider, 20.0)
|
||||||
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
|
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
|
||||||
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
||||||
.set(state.ids.mouse_zoom_invert_button, ui);
|
.set(state.ids.mouse_zoom_invert_button, ui);
|
||||||
@ -420,13 +458,43 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Walking speed behavior
|
||||||
|
Text::new(
|
||||||
|
&self
|
||||||
|
.localized_strings
|
||||||
|
.get_msg("hud-settings-walking_speed_behavior"),
|
||||||
|
)
|
||||||
|
.down_from(state.ids.free_look_behavior_list, 10.0)
|
||||||
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.color(TEXT_COLOR)
|
||||||
|
.set(state.ids.walking_speed_behavior_text, ui);
|
||||||
|
|
||||||
|
let walking_speed_selected =
|
||||||
|
self.global_state.settings.gameplay.walking_speed_behavior as usize;
|
||||||
|
|
||||||
|
if let Some(clicked) = DropDownList::new(&mode_label_list, Some(walking_speed_selected))
|
||||||
|
.w_h(200.0, 30.0)
|
||||||
|
.color(MENU_BG)
|
||||||
|
.label_color(TEXT_COLOR)
|
||||||
|
.label_font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.down_from(state.ids.walking_speed_behavior_text, 8.0)
|
||||||
|
.set(state.ids.walking_speed_behavior_list, ui)
|
||||||
|
{
|
||||||
|
match clicked {
|
||||||
|
0 => events.push(ChangeWalkingSpeedBehavior(PressBehavior::Toggle)),
|
||||||
|
1 => events.push(ChangeWalkingSpeedBehavior(PressBehavior::Hold)),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Camera clamp behavior
|
// Camera clamp behavior
|
||||||
Text::new(
|
Text::new(
|
||||||
&self
|
&self
|
||||||
.localized_strings
|
.localized_strings
|
||||||
.get_msg("hud-settings-camera_clamp_behavior"),
|
.get_msg("hud-settings-camera_clamp_behavior"),
|
||||||
)
|
)
|
||||||
.down_from(state.ids.free_look_behavior_list, 10.0)
|
.down_from(state.ids.auto_walk_behavior_list, 10.0)
|
||||||
.font_size(self.fonts.cyri.scale(14))
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
@ -545,7 +613,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.localized_strings
|
.localized_strings
|
||||||
.get_msg("hud-settings-zoom_lock_behavior"),
|
.get_msg("hud-settings-zoom_lock_behavior"),
|
||||||
)
|
)
|
||||||
.down_from(state.ids.auto_walk_behavior_list, 10.0)
|
.down_from(state.ids.walking_speed_behavior_list, 10.0)
|
||||||
.font_size(self.fonts.cyri.scale(14))
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
@ -599,7 +667,7 @@ impl<'a> Widget for Gameplay<'a> {
|
|||||||
.w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)
|
.w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)
|
||||||
.hover_image(self.imgs.button_hover)
|
.hover_image(self.imgs.button_hover)
|
||||||
.press_image(self.imgs.button_press)
|
.press_image(self.imgs.button_press)
|
||||||
.down_from(state.ids.camera_clamp_behavior_list, 12.0)
|
.down_from(state.ids.zoom_lock_behavior_list, 12.0)
|
||||||
.label(
|
.label(
|
||||||
&self
|
&self
|
||||||
.localized_strings
|
.localized_strings
|
||||||
|
@ -11,6 +11,7 @@ pub struct KeyState {
|
|||||||
pub swim_down: bool,
|
pub swim_down: bool,
|
||||||
pub fly: bool,
|
pub fly: bool,
|
||||||
pub auto_walk: bool,
|
pub auto_walk: bool,
|
||||||
|
pub speed_mul: f32,
|
||||||
pub trade: bool,
|
pub trade: bool,
|
||||||
pub analog_matrix: Vec2<f32>,
|
pub analog_matrix: Vec2<f32>,
|
||||||
}
|
}
|
||||||
@ -28,6 +29,7 @@ impl Default for KeyState {
|
|||||||
swim_down: false,
|
swim_down: false,
|
||||||
fly: false,
|
fly: false,
|
||||||
auto_walk: false,
|
auto_walk: false,
|
||||||
|
speed_mul: 1.0,
|
||||||
trade: false,
|
trade: false,
|
||||||
analog_matrix: Vec2::zero(),
|
analog_matrix: Vec2::zero(),
|
||||||
}
|
}
|
||||||
@ -42,9 +44,11 @@ impl KeyState {
|
|||||||
if self.up || self.auto_walk { 1.0 } else { 0.0 }
|
if self.up || self.auto_walk { 1.0 } else { 0.0 }
|
||||||
+ if self.down { -1.0 } else { 0.0 },
|
+ if self.down { -1.0 } else { 0.0 },
|
||||||
)
|
)
|
||||||
|
.try_normalized()
|
||||||
|
.unwrap_or_default()
|
||||||
} else {
|
} else {
|
||||||
self.analog_matrix
|
self.analog_matrix
|
||||||
};
|
} * self.speed_mul;
|
||||||
|
|
||||||
if dir.magnitude_squared() <= 1.0 {
|
if dir.magnitude_squared() <= 1.0 {
|
||||||
dir
|
dir
|
||||||
|
@ -1110,7 +1110,10 @@ impl FigureMgr {
|
|||||||
&& matches!(active_tool_hand, Some(Hands::One)))
|
&& matches!(active_tool_hand, Some(Hands::One)))
|
||||||
|| !character.map_or(false, |c| c.is_wield()))
|
|| !character.map_or(false, |c| c.is_wield()))
|
||||||
&& !character.map_or(false, |c| c.is_using_hands())
|
&& !character.map_or(false, |c| c.is_using_hands())
|
||||||
&& physics.in_liquid().is_none();
|
&& physics.in_liquid().is_none()
|
||||||
|
&& is_volume_rider.map_or(true, |volume_rider| {
|
||||||
|
!matches!(volume_rider.block.get_sprite(), Some(SpriteKind::Helm))
|
||||||
|
});
|
||||||
|
|
||||||
let back_carry_offset = inventory
|
let back_carry_offset = inventory
|
||||||
.and_then(|i| i.equipped(EquipSlot::Armor(ArmorSlot::Back)))
|
.and_then(|i| i.equipped(EquipSlot::Armor(ArmorSlot::Back)))
|
||||||
@ -2137,7 +2140,26 @@ impl FigureMgr {
|
|||||||
{
|
{
|
||||||
match sprite {
|
match sprite {
|
||||||
SpriteKind::Helm => {
|
SpriteKind::Helm => {
|
||||||
anim::character::DanceAnimation::update_skeleton(
|
anim::character::SteerAnimation::update_skeleton(
|
||||||
|
&target_base,
|
||||||
|
(
|
||||||
|
active_tool_kind,
|
||||||
|
second_tool_kind,
|
||||||
|
character_activity
|
||||||
|
.map(|a| a.steer_dir)
|
||||||
|
.unwrap_or(0.0),
|
||||||
|
time,
|
||||||
|
),
|
||||||
|
state.state_time,
|
||||||
|
&mut state_animation_rate,
|
||||||
|
skeleton_attr,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
SpriteKind::Bed
|
||||||
|
| SpriteKind::Bedroll
|
||||||
|
| SpriteKind::BedrollSnow
|
||||||
|
| SpriteKind::BedrollPirate => {
|
||||||
|
anim::character::SleepAnimation::update_skeleton(
|
||||||
&target_base,
|
&target_base,
|
||||||
(active_tool_kind, second_tool_kind, time),
|
(active_tool_kind, second_tool_kind, time),
|
||||||
state.state_time,
|
state.state_time,
|
||||||
|
@ -207,7 +207,9 @@ impl BlocksOfInterest {
|
|||||||
)
|
)
|
||||||
.with_z(0.0),
|
.with_z(0.0),
|
||||||
)),
|
)),
|
||||||
Some(SpriteKind::Sign) => interactables.push((pos, Interaction::Read)),
|
Some(SpriteKind::Sign | SpriteKind::HangingSign) => {
|
||||||
|
interactables.push((pos, Interaction::Read))
|
||||||
|
},
|
||||||
_ if block.is_mountable() => interactables.push((pos, Interaction::Mount)),
|
_ if block.is_mountable() => interactables.push((pos, Interaction::Mount)),
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
|
@ -101,6 +101,7 @@ pub struct SessionState {
|
|||||||
walk_right_dir: Vec2<f32>,
|
walk_right_dir: Vec2<f32>,
|
||||||
free_look: bool,
|
free_look: bool,
|
||||||
auto_walk: bool,
|
auto_walk: bool,
|
||||||
|
walking_speed: bool,
|
||||||
camera_clamp: bool,
|
camera_clamp: bool,
|
||||||
zoom_lock: bool,
|
zoom_lock: bool,
|
||||||
is_aiming: bool,
|
is_aiming: bool,
|
||||||
@ -171,6 +172,7 @@ impl SessionState {
|
|||||||
walk_right_dir,
|
walk_right_dir,
|
||||||
free_look: false,
|
free_look: false,
|
||||||
auto_walk: false,
|
auto_walk: false,
|
||||||
|
walking_speed: false,
|
||||||
camera_clamp: false,
|
camera_clamp: false,
|
||||||
zoom_lock: false,
|
zoom_lock: false,
|
||||||
is_aiming: false,
|
is_aiming: false,
|
||||||
@ -710,6 +712,7 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
match input {
|
match input {
|
||||||
GameInput::Primary => {
|
GameInput::Primary => {
|
||||||
|
self.walking_speed = false;
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
// Mine and build targets can be the same block. make building
|
// Mine and build targets can be the same block. make building
|
||||||
// take precedence.
|
// take precedence.
|
||||||
@ -728,6 +731,7 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
GameInput::Secondary => {
|
GameInput::Secondary => {
|
||||||
|
self.walking_speed = false;
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
if let Some(build_target) = build_target.filter(|bt| {
|
if let Some(build_target) = build_target.filter(|bt| {
|
||||||
state && can_build && nearest_block_dist == Some(bt.distance)
|
state && can_build && nearest_block_dist == Some(bt.distance)
|
||||||
@ -747,6 +751,7 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
GameInput::Block => {
|
GameInput::Block => {
|
||||||
|
self.walking_speed = false;
|
||||||
self.client.borrow_mut().handle_input(
|
self.client.borrow_mut().handle_input(
|
||||||
InputKind::Block,
|
InputKind::Block,
|
||||||
state,
|
state,
|
||||||
@ -755,6 +760,7 @@ impl PlayState for SessionState {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
GameInput::Roll => {
|
GameInput::Roll => {
|
||||||
|
self.walking_speed = false;
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
if can_build {
|
if can_build {
|
||||||
if state {
|
if state {
|
||||||
@ -779,12 +785,14 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
GameInput::Respawn => {
|
GameInput::Respawn => {
|
||||||
|
self.walking_speed = false;
|
||||||
self.stop_auto_walk();
|
self.stop_auto_walk();
|
||||||
if state {
|
if state {
|
||||||
self.client.borrow_mut().respawn();
|
self.client.borrow_mut().respawn();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GameInput::Jump => {
|
GameInput::Jump => {
|
||||||
|
self.walking_speed = false;
|
||||||
self.client.borrow_mut().handle_input(
|
self.client.borrow_mut().handle_input(
|
||||||
InputKind::Jump,
|
InputKind::Jump,
|
||||||
state,
|
state,
|
||||||
@ -847,6 +855,7 @@ impl PlayState for SessionState {
|
|||||||
self.key_state.right = state
|
self.key_state.right = state
|
||||||
},
|
},
|
||||||
GameInput::Glide => {
|
GameInput::Glide => {
|
||||||
|
self.walking_speed = false;
|
||||||
let is_trading = self.client.borrow().is_trading();
|
let is_trading = self.client.borrow().is_trading();
|
||||||
if state && !is_trading {
|
if state && !is_trading {
|
||||||
if global_state.settings.gameplay.stop_auto_walk_on_input {
|
if global_state.settings.gameplay.stop_auto_walk_on_input {
|
||||||
@ -877,7 +886,11 @@ impl PlayState for SessionState {
|
|||||||
},
|
},
|
||||||
GameInput::ToggleWield => {
|
GameInput::ToggleWield => {
|
||||||
if state {
|
if state {
|
||||||
self.client.borrow_mut().toggle_wield();
|
let mut client = self.client.borrow_mut();
|
||||||
|
if client.is_wielding().is_some_and(|b| !b) {
|
||||||
|
self.walking_speed = false;
|
||||||
|
}
|
||||||
|
client.toggle_wield();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GameInput::SwapLoadout => {
|
GameInput::SwapLoadout => {
|
||||||
@ -1214,6 +1227,13 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
GameInput::ToggleWalk if state => {
|
||||||
|
global_state
|
||||||
|
.settings
|
||||||
|
.gameplay
|
||||||
|
.walking_speed_behavior
|
||||||
|
.update(state, &mut self.walking_speed, |_| {});
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1423,6 +1443,12 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.walking_speed {
|
||||||
|
self.key_state.speed_mul = global_state.settings.gameplay.walking_speed;
|
||||||
|
} else {
|
||||||
|
self.key_state.speed_mul = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
// Recompute dependents just in case some input modified the camera
|
// Recompute dependents just in case some input modified the camera
|
||||||
self.scene
|
self.scene
|
||||||
.camera_mut()
|
.camera_mut()
|
||||||
|
@ -59,6 +59,7 @@ pub enum Gameplay {
|
|||||||
AdjustMousePan(u32),
|
AdjustMousePan(u32),
|
||||||
AdjustMouseZoom(u32),
|
AdjustMouseZoom(u32),
|
||||||
AdjustCameraClamp(u32),
|
AdjustCameraClamp(u32),
|
||||||
|
AdjustWalkingSpeed(f32),
|
||||||
|
|
||||||
ToggleControllerYInvert(bool),
|
ToggleControllerYInvert(bool),
|
||||||
ToggleMouseYInvert(bool),
|
ToggleMouseYInvert(bool),
|
||||||
@ -68,6 +69,7 @@ pub enum Gameplay {
|
|||||||
|
|
||||||
ChangeFreeLookBehavior(PressBehavior),
|
ChangeFreeLookBehavior(PressBehavior),
|
||||||
ChangeAutoWalkBehavior(PressBehavior),
|
ChangeAutoWalkBehavior(PressBehavior),
|
||||||
|
ChangeWalkingSpeedBehavior(PressBehavior),
|
||||||
ChangeCameraClampBehavior(PressBehavior),
|
ChangeCameraClampBehavior(PressBehavior),
|
||||||
ChangeZoomLockBehavior(AutoPressBehavior),
|
ChangeZoomLockBehavior(AutoPressBehavior),
|
||||||
ChangeStopAutoWalkOnInput(bool),
|
ChangeStopAutoWalkOnInput(bool),
|
||||||
@ -379,6 +381,9 @@ impl SettingsChange {
|
|||||||
Gameplay::AdjustCameraClamp(angle) => {
|
Gameplay::AdjustCameraClamp(angle) => {
|
||||||
settings.gameplay.camera_clamp_angle = angle;
|
settings.gameplay.camera_clamp_angle = angle;
|
||||||
},
|
},
|
||||||
|
Gameplay::AdjustWalkingSpeed(speed) => {
|
||||||
|
settings.gameplay.walking_speed = speed;
|
||||||
|
},
|
||||||
Gameplay::ToggleControllerYInvert(controller_y_inverted) => {
|
Gameplay::ToggleControllerYInvert(controller_y_inverted) => {
|
||||||
window.controller_settings.pan_invert_y = controller_y_inverted;
|
window.controller_settings.pan_invert_y = controller_y_inverted;
|
||||||
settings.controller.pan_invert_y = controller_y_inverted;
|
settings.controller.pan_invert_y = controller_y_inverted;
|
||||||
@ -400,6 +405,9 @@ impl SettingsChange {
|
|||||||
Gameplay::ChangeAutoWalkBehavior(behavior) => {
|
Gameplay::ChangeAutoWalkBehavior(behavior) => {
|
||||||
settings.gameplay.auto_walk_behavior = behavior;
|
settings.gameplay.auto_walk_behavior = behavior;
|
||||||
},
|
},
|
||||||
|
Gameplay::ChangeWalkingSpeedBehavior(behavior) => {
|
||||||
|
settings.gameplay.walking_speed_behavior = behavior;
|
||||||
|
},
|
||||||
Gameplay::ChangeCameraClampBehavior(behavior) => {
|
Gameplay::ChangeCameraClampBehavior(behavior) => {
|
||||||
settings.gameplay.camera_clamp_behavior = behavior;
|
settings.gameplay.camera_clamp_behavior = behavior;
|
||||||
},
|
},
|
||||||
|
@ -200,6 +200,7 @@ impl ControlSettings {
|
|||||||
GameInput::MuteMusic => Some(KeyMouse::Key(VirtualKeyCode::F8)),
|
GameInput::MuteMusic => Some(KeyMouse::Key(VirtualKeyCode::F8)),
|
||||||
GameInput::MuteSfx => None,
|
GameInput::MuteSfx => None,
|
||||||
GameInput::MuteAmbience => None,
|
GameInput::MuteAmbience => None,
|
||||||
|
GameInput::ToggleWalk => Some(KeyMouse::Key(VirtualKeyCode::I)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,13 @@ pub struct GameplaySettings {
|
|||||||
pub pan_sensitivity: u32,
|
pub pan_sensitivity: u32,
|
||||||
pub zoom_sensitivity: u32,
|
pub zoom_sensitivity: u32,
|
||||||
pub camera_clamp_angle: u32,
|
pub camera_clamp_angle: u32,
|
||||||
|
pub walking_speed: f32,
|
||||||
pub zoom_inversion: bool,
|
pub zoom_inversion: bool,
|
||||||
pub mouse_y_inversion: bool,
|
pub mouse_y_inversion: bool,
|
||||||
pub smooth_pan_enable: bool,
|
pub smooth_pan_enable: bool,
|
||||||
pub free_look_behavior: PressBehavior,
|
pub free_look_behavior: PressBehavior,
|
||||||
pub auto_walk_behavior: PressBehavior,
|
pub auto_walk_behavior: PressBehavior,
|
||||||
|
pub walking_speed_behavior: PressBehavior,
|
||||||
pub camera_clamp_behavior: PressBehavior,
|
pub camera_clamp_behavior: PressBehavior,
|
||||||
pub zoom_lock_behavior: AutoPressBehavior,
|
pub zoom_lock_behavior: AutoPressBehavior,
|
||||||
pub stop_auto_walk_on_input: bool,
|
pub stop_auto_walk_on_input: bool,
|
||||||
@ -27,11 +29,13 @@ impl Default for GameplaySettings {
|
|||||||
pan_sensitivity: 100,
|
pan_sensitivity: 100,
|
||||||
zoom_sensitivity: 100,
|
zoom_sensitivity: 100,
|
||||||
camera_clamp_angle: 45,
|
camera_clamp_angle: 45,
|
||||||
|
walking_speed: 0.35,
|
||||||
zoom_inversion: false,
|
zoom_inversion: false,
|
||||||
mouse_y_inversion: false,
|
mouse_y_inversion: false,
|
||||||
smooth_pan_enable: false,
|
smooth_pan_enable: false,
|
||||||
free_look_behavior: PressBehavior::Toggle,
|
free_look_behavior: PressBehavior::Toggle,
|
||||||
auto_walk_behavior: PressBehavior::Toggle,
|
auto_walk_behavior: PressBehavior::Toggle,
|
||||||
|
walking_speed_behavior: PressBehavior::Toggle,
|
||||||
camera_clamp_behavior: PressBehavior::Toggle,
|
camera_clamp_behavior: PressBehavior::Toggle,
|
||||||
zoom_lock_behavior: AutoPressBehavior::Auto,
|
zoom_lock_behavior: AutoPressBehavior::Auto,
|
||||||
stop_auto_walk_on_input: true,
|
stop_auto_walk_on_input: true,
|
||||||
|
@ -21,6 +21,7 @@ common-dynlib = {package = "veloren-common-dynlib", path = "../common/dynlib", o
|
|||||||
bincode = { workspace = true }
|
bincode = { workspace = true }
|
||||||
bitvec = "1.0.1"
|
bitvec = "1.0.1"
|
||||||
enum-map = { workspace = true }
|
enum-map = { workspace = true }
|
||||||
|
enumset = "1.1.3"
|
||||||
fxhash = { workspace = true }
|
fxhash = { workspace = true }
|
||||||
image = { workspace = true }
|
image = { workspace = true }
|
||||||
itertools = { workspace = true }
|
itertools = { workspace = true }
|
||||||
|
@ -539,6 +539,7 @@ impl Civs {
|
|||||||
let size = Lerp::lerp(0.03, 1.0, rng.gen_range(0.0..1f32).powi(5));
|
let size = Lerp::lerp(0.03, 1.0, rng.gen_range(0.0..1f32).powi(5));
|
||||||
WorldSite::refactor(site2::Site::generate_city(
|
WorldSite::refactor(site2::Site::generate_city(
|
||||||
&Land::from_sim(ctx.sim),
|
&Land::from_sim(ctx.sim),
|
||||||
|
index_ref,
|
||||||
&mut rng,
|
&mut rng,
|
||||||
wpos,
|
wpos,
|
||||||
size,
|
size,
|
||||||
|
@ -689,4 +689,168 @@ impl<'a, R: Rng> NameGen<'a, R> {
|
|||||||
];
|
];
|
||||||
self.generate_theme_from_parts(&start, &middle, &vowel, &end)
|
self.generate_theme_from_parts(&start, &middle, &vowel, &end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_tavern(&mut self) -> String {
|
||||||
|
let adjectives = [
|
||||||
|
"Crazy",
|
||||||
|
"Big",
|
||||||
|
"Tiny",
|
||||||
|
"Slimy",
|
||||||
|
"Warm",
|
||||||
|
"Rigid",
|
||||||
|
"Soft",
|
||||||
|
"Wet",
|
||||||
|
"Humid",
|
||||||
|
"Smelly",
|
||||||
|
"Hidden",
|
||||||
|
"Smart",
|
||||||
|
"Fragile",
|
||||||
|
"Strong",
|
||||||
|
"Weak",
|
||||||
|
"Happy",
|
||||||
|
"Sad",
|
||||||
|
"Glad",
|
||||||
|
"Scared",
|
||||||
|
"Embarrassed",
|
||||||
|
"Goofy",
|
||||||
|
"Spicy",
|
||||||
|
"Salty",
|
||||||
|
"Peaceful",
|
||||||
|
"Awful",
|
||||||
|
"Sweet",
|
||||||
|
"Colossal",
|
||||||
|
"Puzzled",
|
||||||
|
"Cheap",
|
||||||
|
"Valuable",
|
||||||
|
"Rich",
|
||||||
|
"Obnoxious",
|
||||||
|
"Puzzled",
|
||||||
|
"Snoring",
|
||||||
|
"Fast",
|
||||||
|
"Quick",
|
||||||
|
"Magical",
|
||||||
|
"Violet",
|
||||||
|
"Red",
|
||||||
|
"Blue",
|
||||||
|
"Green",
|
||||||
|
"Yellow",
|
||||||
|
"Golden",
|
||||||
|
"Shiny",
|
||||||
|
"Tired",
|
||||||
|
"Twin",
|
||||||
|
"Incompetent",
|
||||||
|
"Light",
|
||||||
|
"Dark",
|
||||||
|
"Glorious",
|
||||||
|
"Best",
|
||||||
|
"Free",
|
||||||
|
"Odd",
|
||||||
|
"Juicy",
|
||||||
|
"Shaking",
|
||||||
|
"Tall",
|
||||||
|
"Short",
|
||||||
|
"Precious",
|
||||||
|
"Regular",
|
||||||
|
"Slow",
|
||||||
|
"Anxious",
|
||||||
|
"Naive",
|
||||||
|
"Sore",
|
||||||
|
"Next",
|
||||||
|
"Silver",
|
||||||
|
"Secret",
|
||||||
|
"Honorable",
|
||||||
|
"Rapid",
|
||||||
|
"Sleepy",
|
||||||
|
"Lying",
|
||||||
|
"Zesty",
|
||||||
|
"Fancy",
|
||||||
|
"Stylish",
|
||||||
|
"Thirsty",
|
||||||
|
"Dry",
|
||||||
|
"Dancing",
|
||||||
|
"Singing",
|
||||||
|
"Drunken",
|
||||||
|
];
|
||||||
|
let tavern_synonyms = ["Tavern", "Bar", "Pub"];
|
||||||
|
let subjectives = [
|
||||||
|
"Apple",
|
||||||
|
"Pumpkin",
|
||||||
|
"Cucumber",
|
||||||
|
"Squash",
|
||||||
|
"Demons",
|
||||||
|
"Mango",
|
||||||
|
"Coconut",
|
||||||
|
"Cats",
|
||||||
|
"Hill",
|
||||||
|
"Mountain",
|
||||||
|
"Squirrel",
|
||||||
|
"Rabbit",
|
||||||
|
"Moose",
|
||||||
|
"Driggle",
|
||||||
|
"Iron",
|
||||||
|
"Velorite",
|
||||||
|
"Plate",
|
||||||
|
"Eagle",
|
||||||
|
"Birds",
|
||||||
|
"Drumstick",
|
||||||
|
"Dog",
|
||||||
|
"Tiger",
|
||||||
|
"Knight",
|
||||||
|
"Leader",
|
||||||
|
"Huntress",
|
||||||
|
"Hunter",
|
||||||
|
"Dwarf",
|
||||||
|
"Toad",
|
||||||
|
"Clams",
|
||||||
|
"Bell",
|
||||||
|
"Avocado",
|
||||||
|
"Egg",
|
||||||
|
"Spade",
|
||||||
|
"Stream",
|
||||||
|
"Cabbage",
|
||||||
|
"Tomato",
|
||||||
|
"Rapier",
|
||||||
|
"Katana",
|
||||||
|
"Whisper",
|
||||||
|
"Hammer",
|
||||||
|
"Axe",
|
||||||
|
"Sword",
|
||||||
|
"Saurok",
|
||||||
|
"Danari",
|
||||||
|
"Elf",
|
||||||
|
"Human",
|
||||||
|
"Draugr",
|
||||||
|
"Orc",
|
||||||
|
"Pie",
|
||||||
|
"Stick",
|
||||||
|
"Rope",
|
||||||
|
"Knife",
|
||||||
|
"Shield",
|
||||||
|
"Bow",
|
||||||
|
"Spear",
|
||||||
|
"Staff",
|
||||||
|
"Crow",
|
||||||
|
"Crown",
|
||||||
|
"Parrot",
|
||||||
|
"Parrots",
|
||||||
|
"Pelican",
|
||||||
|
"Whale",
|
||||||
|
"Cube",
|
||||||
|
"Minotaur",
|
||||||
|
"Oni",
|
||||||
|
"Monster",
|
||||||
|
];
|
||||||
|
let kind = self.rng.gen_range(0..10);
|
||||||
|
let mut choose = |slice: &[&'static str]| *slice.choose(self.rng).unwrap();
|
||||||
|
match kind {
|
||||||
|
0 => format!("The {} {}", choose(&adjectives), choose(&tavern_synonyms)),
|
||||||
|
1..=7 => format!("The {} {}", choose(&adjectives), choose(&subjectives)),
|
||||||
|
_ => format!(
|
||||||
|
"The {} {} {}",
|
||||||
|
choose(&adjectives),
|
||||||
|
choose(&subjectives),
|
||||||
|
choose(&tavern_synonyms)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,7 +573,13 @@ impl Site {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size is 0..1
|
// Size is 0..1
|
||||||
pub fn generate_city(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>, size: f32) -> Self {
|
pub fn generate_city(
|
||||||
|
land: &Land,
|
||||||
|
index: IndexRef,
|
||||||
|
rng: &mut impl Rng,
|
||||||
|
origin: Vec2<i32>,
|
||||||
|
size: f32,
|
||||||
|
) -> Self {
|
||||||
let mut rng = reseed(rng);
|
let mut rng = reseed(rng);
|
||||||
|
|
||||||
let mut site = Site {
|
let mut site = Site {
|
||||||
@ -593,6 +599,7 @@ impl Site {
|
|||||||
(5.0, 4),
|
(5.0, 4),
|
||||||
(5.0, 5),
|
(5.0, 5),
|
||||||
(15.0, 6),
|
(15.0, 6),
|
||||||
|
(15.0, 7),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut castles = 0;
|
let mut castles = 0;
|
||||||
@ -600,6 +607,8 @@ impl Site {
|
|||||||
let mut workshops = 0;
|
let mut workshops = 0;
|
||||||
|
|
||||||
let mut airship_docks = 0;
|
let mut airship_docks = 0;
|
||||||
|
|
||||||
|
let mut taverns = 0;
|
||||||
for _ in 0..(size * 200.0) as i32 {
|
for _ in 0..(size * 200.0) as i32 {
|
||||||
match *build_chance.choose_seeded(rng.gen()) {
|
match *build_chance.choose_seeded(rng.gen()) {
|
||||||
// Workshop
|
// Workshop
|
||||||
@ -917,6 +926,43 @@ impl Site {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
7 if (size > 0.125 && taverns < 2) => {
|
||||||
|
let size = (3.5 + rng.gen::<f32>().powf(5.0) * 2.0).round() as u32;
|
||||||
|
if let Some((aabr, door_tile, door_dir)) = attempt(32, || {
|
||||||
|
site.find_roadside_aabr(
|
||||||
|
&mut rng,
|
||||||
|
7..(size + 1).pow(2),
|
||||||
|
Extent2::broadcast(size),
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
let tavern = plot::Tavern::generate(
|
||||||
|
land,
|
||||||
|
index,
|
||||||
|
&mut reseed(&mut rng),
|
||||||
|
&site,
|
||||||
|
door_tile,
|
||||||
|
Dir::from_vec2(door_dir),
|
||||||
|
aabr,
|
||||||
|
);
|
||||||
|
let tavern_alt = tavern.door_wpos.z;
|
||||||
|
let plot = site.create_plot(Plot {
|
||||||
|
kind: PlotKind::Tavern(tavern),
|
||||||
|
root_tile: aabr.center(),
|
||||||
|
tiles: aabr_tiles(aabr).collect(),
|
||||||
|
seed: rng.gen(),
|
||||||
|
});
|
||||||
|
|
||||||
|
site.blit_aabr(aabr, Tile {
|
||||||
|
kind: TileKind::Building,
|
||||||
|
plot: Some(plot),
|
||||||
|
hard_alt: Some(tavern_alt),
|
||||||
|
});
|
||||||
|
|
||||||
|
taverns += 1;
|
||||||
|
} else {
|
||||||
|
site.make_plaza(land, &mut rng);
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1824,6 +1870,7 @@ impl Site {
|
|||||||
let (prim_tree, fills, mut entities) = match &self.plots[plot].kind {
|
let (prim_tree, fills, mut entities) = match &self.plots[plot].kind {
|
||||||
PlotKind::House(house) => house.render_collect(self, canvas),
|
PlotKind::House(house) => house.render_collect(self, canvas),
|
||||||
PlotKind::AirshipDock(airship_dock) => airship_dock.render_collect(self, canvas),
|
PlotKind::AirshipDock(airship_dock) => airship_dock.render_collect(self, canvas),
|
||||||
|
PlotKind::Tavern(tavern) => tavern.render_collect(self, canvas),
|
||||||
PlotKind::CoastalHouse(coastal_house) => coastal_house.render_collect(self, canvas),
|
PlotKind::CoastalHouse(coastal_house) => coastal_house.render_collect(self, canvas),
|
||||||
PlotKind::CoastalWorkshop(coastal_workshop) => {
|
PlotKind::CoastalWorkshop(coastal_workshop) => {
|
||||||
coastal_workshop.render_collect(self, canvas)
|
coastal_workshop.render_collect(self, canvas)
|
||||||
@ -1963,7 +2010,19 @@ impl Site {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_site() -> Site {
|
pub fn test_site() -> Site {
|
||||||
Site::generate_city(&Land::empty(), &mut thread_rng(), Vec2::zero(), 0.5)
|
let index = crate::index::Index::new(0);
|
||||||
|
let index_ref = IndexRef {
|
||||||
|
colors: &index.colors(),
|
||||||
|
features: &index.features(),
|
||||||
|
index: &index,
|
||||||
|
};
|
||||||
|
Site::generate_city(
|
||||||
|
&Land::empty(),
|
||||||
|
index_ref,
|
||||||
|
&mut thread_rng(),
|
||||||
|
Vec2::zero(),
|
||||||
|
0.5,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wpos_is_hazard(land: &Land, wpos: Vec2<i32>) -> Option<HazardKind> {
|
fn wpos_is_hazard(land: &Land, wpos: Vec2<i32>) -> Option<HazardKind> {
|
||||||
|
@ -22,6 +22,7 @@ mod savannah_hut;
|
|||||||
mod savannah_pit;
|
mod savannah_pit;
|
||||||
mod savannah_workshop;
|
mod savannah_workshop;
|
||||||
mod sea_chapel;
|
mod sea_chapel;
|
||||||
|
pub mod tavern;
|
||||||
mod troll_cave;
|
mod troll_cave;
|
||||||
mod workshop;
|
mod workshop;
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ pub use self::{
|
|||||||
gnarling::GnarlingFortification, house::House, jungle_ruin::JungleRuin,
|
gnarling::GnarlingFortification, house::House, jungle_ruin::JungleRuin,
|
||||||
pirate_hideout::PirateHideout, rock_circle::RockCircle, savannah_hut::SavannahHut,
|
pirate_hideout::PirateHideout, rock_circle::RockCircle, savannah_hut::SavannahHut,
|
||||||
savannah_pit::SavannahPit, savannah_workshop::SavannahWorkshop, sea_chapel::SeaChapel,
|
savannah_pit::SavannahPit, savannah_workshop::SavannahWorkshop, sea_chapel::SeaChapel,
|
||||||
troll_cave::TrollCave, workshop::Workshop,
|
tavern::Tavern, troll_cave::TrollCave, workshop::Workshop,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -77,6 +78,7 @@ impl Plot {
|
|||||||
pub enum PlotKind {
|
pub enum PlotKind {
|
||||||
House(House),
|
House(House),
|
||||||
AirshipDock(AirshipDock),
|
AirshipDock(AirshipDock),
|
||||||
|
Tavern(Tavern),
|
||||||
CoastalHouse(CoastalHouse),
|
CoastalHouse(CoastalHouse),
|
||||||
CoastalWorkshop(CoastalWorkshop),
|
CoastalWorkshop(CoastalWorkshop),
|
||||||
Workshop(Workshop),
|
Workshop(Workshop),
|
||||||
|
@ -129,7 +129,7 @@ impl AdletStronghold {
|
|||||||
|
|
||||||
let mut outer_structures = Vec::<(AdletStructure, Vec2<i32>, Dir)>::new();
|
let mut outer_structures = Vec::<(AdletStructure, Vec2<i32>, Dir)>::new();
|
||||||
|
|
||||||
let entrance_dir = Dir::from_vector(entrance - cavern_center);
|
let entrance_dir = Dir::from_vec2(entrance - cavern_center);
|
||||||
outer_structures.push((AdletStructure::TunnelEntrance, Vec2::zero(), entrance_dir));
|
outer_structures.push((AdletStructure::TunnelEntrance, Vec2::zero(), entrance_dir));
|
||||||
|
|
||||||
let desired_structures = surface_radius.pow(2) / 100;
|
let desired_structures = surface_radius.pow(2) / 100;
|
||||||
@ -176,7 +176,7 @@ impl AdletStronghold {
|
|||||||
Some((structure_center, structure_kind))
|
Some((structure_center, structure_kind))
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
let dir_to_wall = Dir::from_vector(rpos);
|
let dir_to_wall = Dir::from_vec2(rpos);
|
||||||
let door_rng: u32 = rng.gen_range(0..9);
|
let door_rng: u32 = rng.gen_range(0..9);
|
||||||
let door_dir = match door_rng {
|
let door_dir = match door_rng {
|
||||||
0..=3 => dir_to_wall,
|
0..=3 => dir_to_wall,
|
||||||
@ -352,7 +352,7 @@ impl AdletStronghold {
|
|||||||
.then_some((structure, rpos))
|
.then_some((structure, rpos))
|
||||||
}) {
|
}) {
|
||||||
// Direction facing the central bonfire
|
// Direction facing the central bonfire
|
||||||
let dir = Dir::from_vector(rpos).opposite();
|
let dir = Dir::from_vec2(rpos).opposite();
|
||||||
cavern_structures.push((structure, rpos, dir));
|
cavern_structures.push((structure, rpos, dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -493,7 +493,7 @@ impl Structure for AdletStronghold {
|
|||||||
|
|
||||||
// Tunnel
|
// Tunnel
|
||||||
let dist: f32 = self.cavern_center.as_().distance(self.entrance.as_());
|
let dist: f32 = self.cavern_center.as_().distance(self.entrance.as_());
|
||||||
let dir = Dir::from_vector(self.entrance - self.cavern_center);
|
let dir = Dir::from_vec2(self.entrance - self.cavern_center);
|
||||||
let tunnel_start: Vec3<f32> = match dir {
|
let tunnel_start: Vec3<f32> = match dir {
|
||||||
Dir::X => Vec2::new(self.entrance.x + 7, self.entrance.y),
|
Dir::X => Vec2::new(self.entrance.x + 7, self.entrance.y),
|
||||||
Dir::Y => Vec2::new(self.entrance.x, self.entrance.y + 7),
|
Dir::Y => Vec2::new(self.entrance.x, self.entrance.y + 7),
|
||||||
|
@ -227,7 +227,7 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
|
|||||||
}
|
}
|
||||||
.made_valid();
|
.made_valid();
|
||||||
|
|
||||||
let [ramp_aabr, aabr] = bridge.dir.split_aabr(aabr, height);
|
let [ramp_aabr, aabr] = bridge.dir.split_aabr_offset(aabr, height);
|
||||||
|
|
||||||
let ramp_prim = |ramp_aabr: Aabr<i32>, offset: i32| {
|
let ramp_prim = |ramp_aabr: Aabr<i32>, offset: i32| {
|
||||||
painter
|
painter
|
||||||
@ -254,7 +254,7 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
|
|||||||
let vault_offset = 5;
|
let vault_offset = 5;
|
||||||
let bridge_thickness = 4;
|
let bridge_thickness = 4;
|
||||||
|
|
||||||
let [vault, _] = bridge.dir.split_aabr(aabr, vault_width);
|
let [vault, _] = bridge.dir.split_aabr_offset(aabr, vault_width);
|
||||||
|
|
||||||
let len = bridge.dir.select(aabr.size());
|
let len = bridge.dir.select(aabr.size());
|
||||||
let true_offset = vault_width + vault_offset;
|
let true_offset = vault_width + vault_offset;
|
||||||
@ -321,8 +321,11 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
|||||||
}
|
}
|
||||||
.made_valid();
|
.made_valid();
|
||||||
|
|
||||||
let [_start_aabr, rest] = bridge.dir.split_aabr(aabr, bridge_start_z - bridge.start.z);
|
let [_start_aabr, rest] = bridge
|
||||||
let [_end_aabr, bridge_aabr] = (-bridge.dir).split_aabr(rest, bridge_start_z - bridge.end.z);
|
.dir
|
||||||
|
.split_aabr_offset(aabr, bridge_start_z - bridge.start.z);
|
||||||
|
let [_end_aabr, bridge_aabr] =
|
||||||
|
(-bridge.dir).split_aabr_offset(rest, bridge_start_z - bridge.end.z);
|
||||||
let under = bridge.center.z - 15;
|
let under = bridge.center.z - 15;
|
||||||
|
|
||||||
let bridge_prim = |bridge_width: i32| {
|
let bridge_prim = |bridge_width: i32| {
|
||||||
@ -334,11 +337,14 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
|||||||
}
|
}
|
||||||
.made_valid();
|
.made_valid();
|
||||||
|
|
||||||
let [start_aabr, rest] = bridge.dir.split_aabr(aabr, bridge_start_z - bridge.start.z);
|
let [start_aabr, rest] = bridge
|
||||||
let [end_aabr, bridge_aabr] = (-bridge.dir).split_aabr(rest, bridge_start_z - bridge.end.z);
|
.dir
|
||||||
|
.split_aabr_offset(aabr, bridge_start_z - bridge.start.z);
|
||||||
|
let [end_aabr, bridge_aabr] =
|
||||||
|
(-bridge.dir).split_aabr_offset(rest, bridge_start_z - bridge.end.z);
|
||||||
let [bridge_start, bridge_end] = bridge
|
let [bridge_start, bridge_end] = bridge
|
||||||
.dir
|
.dir
|
||||||
.split_aabr(bridge_aabr, bridge.dir.select(bridge_aabr.size()) / 2);
|
.split_aabr_offset(bridge_aabr, bridge.dir.select(bridge_aabr.size()) / 2);
|
||||||
|
|
||||||
let ramp_in_aabr = |aabr: Aabr<i32>, dir: Dir, zmin, zmax| {
|
let ramp_in_aabr = |aabr: Aabr<i32>, dir: Dir, zmin, zmax| {
|
||||||
let inset = dir.select(aabr.size());
|
let inset = dir.select(aabr.size());
|
||||||
@ -592,7 +598,7 @@ fn render_tower(bridge: &Bridge, painter: &Painter, roof_kind: &RoofKind) {
|
|||||||
let aabr = bridge
|
let aabr = bridge
|
||||||
.dir
|
.dir
|
||||||
.rotated_cw()
|
.rotated_cw()
|
||||||
.split_aabr(tower_aabr, stair_thickness + 1)[1];
|
.split_aabr_offset(tower_aabr, stair_thickness + 1)[1];
|
||||||
|
|
||||||
painter
|
painter
|
||||||
.aabb(aabb(
|
.aabb(aabb(
|
||||||
@ -748,7 +754,7 @@ fn render_hang(bridge: &Bridge, painter: &Painter) {
|
|||||||
let top_offset = 4;
|
let top_offset = 4;
|
||||||
let top = bridge.end.z + top_offset;
|
let top = bridge.end.z + top_offset;
|
||||||
|
|
||||||
let [ramp_f, aabr] = bridge.dir.split_aabr(aabr, top - bridge.start.z + 1);
|
let [ramp_f, aabr] = bridge.dir.split_aabr_offset(aabr, top - bridge.start.z + 1);
|
||||||
|
|
||||||
painter
|
painter
|
||||||
.aabb(aabb(
|
.aabb(aabb(
|
||||||
@ -764,7 +770,7 @@ fn render_hang(bridge: &Bridge, painter: &Painter) {
|
|||||||
)
|
)
|
||||||
.fill(rock.clone());
|
.fill(rock.clone());
|
||||||
|
|
||||||
let [ramp_b, aabr] = (-bridge.dir).split_aabr(aabr, top_offset + 1);
|
let [ramp_b, aabr] = (-bridge.dir).split_aabr_offset(aabr, top_offset + 1);
|
||||||
painter
|
painter
|
||||||
.aabb(aabb(
|
.aabb(aabb(
|
||||||
ramp_b.min.with_z(bridge.end.z - 10),
|
ramp_b.min.with_z(bridge.end.z - 10),
|
||||||
@ -878,7 +884,7 @@ impl Bridge {
|
|||||||
let min_water_dist = 5;
|
let min_water_dist = 5;
|
||||||
let find_edge = |start: Vec2<i32>, end: Vec2<i32>| {
|
let find_edge = |start: Vec2<i32>, end: Vec2<i32>| {
|
||||||
let mut test_start = start;
|
let mut test_start = start;
|
||||||
let dir = Dir::from_vector(end - start).to_vec2();
|
let dir = Dir::from_vec2(end - start).to_vec2();
|
||||||
let mut last_alt = if let Some(col) = land.column_sample(start, index) {
|
let mut last_alt = if let Some(col) = land.column_sample(start, index) {
|
||||||
col.alt as i32
|
col.alt as i32
|
||||||
} else {
|
} else {
|
||||||
@ -932,7 +938,7 @@ impl Bridge {
|
|||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
center,
|
center,
|
||||||
dir: Dir::from_vector(end.xy() - start.xy()),
|
dir: Dir::from_vec2(end.xy() - start.xy()),
|
||||||
kind: bridge,
|
kind: bridge,
|
||||||
biome: land
|
biome: land
|
||||||
.get_chunk_wpos(center.xy())
|
.get_chunk_wpos(center.xy())
|
||||||
|
@ -237,7 +237,7 @@ impl GnarlingFortification {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
let dir_to_center = Dir::from_vector(hut_loc.xy()).opposite();
|
let dir_to_center = Dir::from_vec2(hut_loc.xy()).opposite();
|
||||||
let door_rng: u32 = rng.gen_range(0..9);
|
let door_rng: u32 = rng.gen_range(0..9);
|
||||||
let door_dir = match door_rng {
|
let door_dir = match door_rng {
|
||||||
0..=3 => dir_to_center,
|
0..=3 => dir_to_center,
|
||||||
@ -262,7 +262,7 @@ impl GnarlingFortification {
|
|||||||
let chieftain_hut_loc = ((inner_tower_locs[0] + inner_tower_locs[1])
|
let chieftain_hut_loc = ((inner_tower_locs[0] + inner_tower_locs[1])
|
||||||
+ 2 * outer_wall_corners[chieftain_indices[1]])
|
+ 2 * outer_wall_corners[chieftain_indices[1]])
|
||||||
/ 4;
|
/ 4;
|
||||||
let chieftain_hut_ori = Dir::from_vector(chieftain_hut_loc).opposite();
|
let chieftain_hut_ori = Dir::from_vec2(chieftain_hut_loc).opposite();
|
||||||
structure_locations.push((
|
structure_locations.push((
|
||||||
GnarlingStructure::ChieftainHut,
|
GnarlingStructure::ChieftainHut,
|
||||||
chieftain_hut_loc.with_z(rpos_height(chieftain_hut_loc)),
|
chieftain_hut_loc.with_z(rpos_height(chieftain_hut_loc)),
|
||||||
|
1588
world/src/site2/plot/tavern.rs
Normal file
1588
world/src/site2/plot/tavern.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@ use rand::Rng;
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
/// A 2d direction.
|
/// A 2d direction.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Debug, enum_map::Enum, strum::EnumIter, enumset::EnumSetType)]
|
||||||
pub enum Dir {
|
pub enum Dir {
|
||||||
X,
|
X,
|
||||||
Y,
|
Y,
|
||||||
@ -26,7 +26,7 @@ impl Dir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_vector(vec: Vec2<i32>) -> Dir {
|
pub fn from_vec2(vec: Vec2<i32>) -> Dir {
|
||||||
if vec.x.abs() > vec.y.abs() {
|
if vec.x.abs() > vec.y.abs() {
|
||||||
if vec.x > 0 { Dir::X } else { Dir::NegX }
|
if vec.x > 0 { Dir::X } else { Dir::NegX }
|
||||||
} else if vec.y > 0 {
|
} else if vec.y > 0 {
|
||||||
@ -110,6 +110,17 @@ impl Dir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a vec2 where x is in the direction of `self`, and y is anti
|
||||||
|
/// clockwise of `self`.
|
||||||
|
pub fn vec2(self, x: i32, y: i32) -> Vec2<i32> {
|
||||||
|
match self {
|
||||||
|
Dir::X => Vec2::new(x, y),
|
||||||
|
Dir::NegX => Vec2::new(-x, -y),
|
||||||
|
Dir::Y => Vec2::new(y, x),
|
||||||
|
Dir::NegY => Vec2::new(-y, -x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a 3x3 matrix that rotates Vec3(1, 0, 0) to the direction you get
|
/// Returns a 3x3 matrix that rotates Vec3(1, 0, 0) to the direction you get
|
||||||
/// in to_vec3. Inteded to be used with Primitive::Rotate.
|
/// in to_vec3. Inteded to be used with Primitive::Rotate.
|
||||||
///
|
///
|
||||||
@ -223,7 +234,7 @@ impl Dir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_aabr<T>(self, aabr: Aabr<T>, offset: T) -> [Aabr<T>; 2]
|
pub fn split_aabr_offset<T>(self, aabr: Aabr<T>, offset: T) -> [Aabr<T>; 2]
|
||||||
where
|
where
|
||||||
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
|
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
|
||||||
{
|
{
|
||||||
@ -241,6 +252,29 @@ impl Dir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to split an aabr in a certain direction
|
||||||
|
pub fn try_split_aabr<T>(self, aabr: Aabr<T>, sp: T) -> Option<[Aabr<T>; 2]>
|
||||||
|
where
|
||||||
|
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Dir::NegX | Dir::X => {
|
||||||
|
if aabr.min.x <= sp && sp <= aabr.max.x {
|
||||||
|
Some(aabr.split_at_x(sp))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Dir::NegY | Dir::Y => {
|
||||||
|
if aabr.min.y <= sp && sp <= aabr.max.y {
|
||||||
|
Some(aabr.split_at_y(sp))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn trim_aabr(self, aabr: Aabr<i32>, offset: i32) -> Aabr<i32> {
|
pub fn trim_aabr(self, aabr: Aabr<i32>, offset: i32) -> Aabr<i32> {
|
||||||
Aabr {
|
Aabr {
|
||||||
min: aabr.min + self.abs().to_vec2() * offset,
|
min: aabr.min + self.abs().to_vec2() * offset,
|
||||||
|
@ -15,6 +15,15 @@ impl RandomField {
|
|||||||
pub fn get_f32(&self, pos: Vec3<i32>) -> f32 {
|
pub fn get_f32(&self, pos: Vec3<i32>) -> f32 {
|
||||||
(self.get(pos) % (1 << 16)) as f32 / ((1 << 16) as f32)
|
(self.get(pos) % (1 << 16)) as f32 / ((1 << 16) as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn choose<'a, T>(&self, pos: Vec3<i32>, slice: &'a [T]) -> Option<&'a T> {
|
||||||
|
if slice.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = self.get(pos) as usize;
|
||||||
|
slice.get(i % slice.len())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sampler<'static> for RandomField {
|
impl Sampler<'static> for RandomField {
|
||||||
|
Loading…
Reference in New Issue
Block a user