mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
buildup times and portal model update
This commit is contained in:
parent
14141ecc80
commit
25fcb04ad3
BIN
assets/voxygen/voxel/object/portal.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/object/portal.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/voxel/object/portal_active.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/portal_active.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -981,12 +981,22 @@
|
|||||||
),
|
),
|
||||||
Portal: (
|
Portal: (
|
||||||
bone0: (
|
bone0: (
|
||||||
offset: (-11.0, -1.5, 0.0),
|
offset: (-33.0, -33.0, 0.0),
|
||||||
central: ("object.portal"),
|
central: ("object.portal"),
|
||||||
),
|
),
|
||||||
bone1: (
|
bone1: (
|
||||||
offset: (0.0, 0.0, 0.0),
|
offset: (0.0, 0.0, 0.0),
|
||||||
central: ("armor.empty"),
|
central: ("armor.empty"),
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
PortalActive: (
|
||||||
|
bone0: (
|
||||||
|
offset: (-33.0, -33.0, 0.0),
|
||||||
|
central: ("object.portal_active"),
|
||||||
|
),
|
||||||
|
bone1: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
)
|
)
|
||||||
|
),
|
||||||
})
|
})
|
||||||
|
@ -625,6 +625,7 @@ impl ServerChatCommand {
|
|||||||
Float("y", 0., Required),
|
Float("y", 0., Required),
|
||||||
Float("z", 0., Required),
|
Float("z", 0., Required),
|
||||||
Boolean("requires_no_aggro", "true".to_string(), Optional),
|
Boolean("requires_no_aggro", "true".to_string(), Optional),
|
||||||
|
Float("buildup_time", 5., Optional),
|
||||||
],
|
],
|
||||||
"Spawns a portal",
|
"Spawns a portal",
|
||||||
Some(Moderator),
|
Some(Moderator),
|
||||||
|
@ -111,6 +111,7 @@ make_case_elim!(
|
|||||||
LightningBolt = 96,
|
LightningBolt = 96,
|
||||||
SpearIcicle = 97,
|
SpearIcicle = 97,
|
||||||
Portal = 98,
|
Portal = 98,
|
||||||
|
PortalActive = 99,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ impl Body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ALL_OBJECTS: [Body; 99] = [
|
pub const ALL_OBJECTS: [Body; 100] = [
|
||||||
Body::Arrow,
|
Body::Arrow,
|
||||||
Body::Bomb,
|
Body::Bomb,
|
||||||
Body::Scarecrow,
|
Body::Scarecrow,
|
||||||
@ -221,6 +222,7 @@ pub const ALL_OBJECTS: [Body; 99] = [
|
|||||||
Body::LightningBolt,
|
Body::LightningBolt,
|
||||||
Body::SpearIcicle,
|
Body::SpearIcicle,
|
||||||
Body::Portal,
|
Body::Portal,
|
||||||
|
Body::PortalActive,
|
||||||
];
|
];
|
||||||
|
|
||||||
impl From<Body> for super::Body {
|
impl From<Body> for super::Body {
|
||||||
@ -329,6 +331,7 @@ impl Body {
|
|||||||
Body::LightningBolt => "lightning_bolt",
|
Body::LightningBolt => "lightning_bolt",
|
||||||
Body::SpearIcicle => "spear_icicle",
|
Body::SpearIcicle => "spear_icicle",
|
||||||
Body::Portal => "portal",
|
Body::Portal => "portal",
|
||||||
|
Self::PortalActive => "portal_active",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +456,7 @@ impl Body {
|
|||||||
Body::AdletTrap => 10.0,
|
Body::AdletTrap => 10.0,
|
||||||
Body::Mine => 100.0,
|
Body::Mine => 100.0,
|
||||||
Body::LightningBolt | Body::SpearIcicle => 20000.0,
|
Body::LightningBolt | Body::SpearIcicle => 20000.0,
|
||||||
Body::Portal => 10., // I dont know really
|
Body::Portal | Body::PortalActive => 10., // I dont know really
|
||||||
};
|
};
|
||||||
|
|
||||||
Mass(m)
|
Mass(m)
|
||||||
|
@ -3,7 +3,6 @@ use crate::{resources::Time, uid::Uid};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use specs::{Component, DerefFlaggedStorage};
|
use specs::{Component, DerefFlaggedStorage};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use vek::Vec3;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Object {
|
pub enum Object {
|
||||||
@ -23,13 +22,3 @@ pub enum Object {
|
|||||||
impl Component for Object {
|
impl Component for Object {
|
||||||
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Teleporter {
|
|
||||||
pub target: Vec3<f32>,
|
|
||||||
pub requires_no_aggro: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Teleporter {
|
|
||||||
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
|
||||||
}
|
|
||||||
|
@ -34,6 +34,7 @@ pub mod projectile;
|
|||||||
pub mod shockwave;
|
pub mod shockwave;
|
||||||
pub mod skillset;
|
pub mod skillset;
|
||||||
mod stats;
|
mod stats;
|
||||||
|
mod teleport;
|
||||||
pub mod visual;
|
pub mod visual;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
@ -86,7 +87,7 @@ pub use self::{
|
|||||||
location::{MapMarker, MapMarkerChange, MapMarkerUpdate, Waypoint, WaypointArea},
|
location::{MapMarker, MapMarkerChange, MapMarkerUpdate, Waypoint, WaypointArea},
|
||||||
loot_owner::LootOwner,
|
loot_owner::LootOwner,
|
||||||
melee::{Melee, MeleeConstructor, MeleeConstructorKind},
|
melee::{Melee, MeleeConstructor, MeleeConstructorKind},
|
||||||
misc::{Object, Teleporter},
|
misc::Object,
|
||||||
ori::Ori,
|
ori::Ori,
|
||||||
pet::Pet,
|
pet::Pet,
|
||||||
phys::{
|
phys::{
|
||||||
@ -103,6 +104,7 @@ pub use self::{
|
|||||||
SkillGroup, SkillGroupKind, SkillSet,
|
SkillGroup, SkillGroupKind, SkillSet,
|
||||||
},
|
},
|
||||||
stats::{Stats, StatsModifier},
|
stats::{Stats, StatsModifier},
|
||||||
|
teleport::{Teleporter, Teleporting},
|
||||||
visual::{LightAnimation, LightEmitter},
|
visual::{LightAnimation, LightEmitter},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
27
common/src/comp/teleport.rs
Normal file
27
common/src/comp/teleport.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use specs::{Component, DerefFlaggedStorage, Entity};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
|
use crate::resources::{Secs, Time};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Teleporter {
|
||||||
|
pub target: Vec3<f32>,
|
||||||
|
pub requires_no_aggro: bool,
|
||||||
|
pub buildup_time: Secs,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Teleporter {
|
||||||
|
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub struct Teleporting {
|
||||||
|
pub teleport_start: Time,
|
||||||
|
pub portal: Entity,
|
||||||
|
pub end_time: Time,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Teleporting {
|
||||||
|
type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
|
||||||
|
}
|
@ -220,6 +220,7 @@ impl State {
|
|||||||
ecs.register::<comp::Admin>();
|
ecs.register::<comp::Admin>();
|
||||||
ecs.register::<comp::Stance>();
|
ecs.register::<comp::Stance>();
|
||||||
ecs.register::<comp::Teleporter>();
|
ecs.register::<comp::Teleporter>();
|
||||||
|
ecs.register::<comp::Teleporting>();
|
||||||
|
|
||||||
// Register components send from clients -> server
|
// Register components send from clients -> server
|
||||||
ecs.register::<comp::Controller>();
|
ecs.register::<comp::Controller>();
|
||||||
|
@ -2051,15 +2051,17 @@ fn handle_spawn_portal(
|
|||||||
) -> CmdResult<()> {
|
) -> CmdResult<()> {
|
||||||
let pos = position(server, target, "target")?;
|
let pos = position(server, target, "target")?;
|
||||||
|
|
||||||
if let (Some(x), Some(y), Some(z), requires_no_aggro) =
|
if let (Some(x), Some(y), Some(z), requires_no_aggro, buildup_time) =
|
||||||
parse_cmd_args!(args, f32, f32, f32, bool)
|
parse_cmd_args!(args, f32, f32, f32, bool, f64)
|
||||||
{
|
{
|
||||||
let requires_no_aggro = requires_no_aggro.unwrap_or(false);
|
let requires_no_aggro = requires_no_aggro.unwrap_or(false);
|
||||||
|
let buildup_time = Secs(buildup_time.unwrap_or(0.));
|
||||||
server
|
server
|
||||||
.state
|
.state
|
||||||
.create_teleporter(pos, comp::Teleporter {
|
.create_teleporter(pos, comp::Teleporter {
|
||||||
target: Vec3::new(x, y, z),
|
target: Vec3::new(x, y, z),
|
||||||
requires_no_aggro,
|
requires_no_aggro,
|
||||||
|
buildup_time,
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{Agent, ForceUpdate, Player, Pos, Teleporter},
|
comp::{object, Agent, Body, ForceUpdate, Player, Pos, Teleporter, Teleporting},
|
||||||
|
resources::Time,
|
||||||
CachedSpatialGrid,
|
CachedSpatialGrid,
|
||||||
};
|
};
|
||||||
use common_ecs::{Origin, Phase, System};
|
use common_ecs::{Origin, Phase, System};
|
||||||
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
|
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
|
||||||
|
use vek::Vec3;
|
||||||
|
|
||||||
const TELEPORT_RADIUS: f32 = 1.;
|
const TELEPORT_RADIUS: f32 = 3.;
|
||||||
const MAX_AGGRO_DIST: f32 = 200.; // If an entity further than this is aggroed at a player, the portal will still work
|
const MAX_AGGRO_DIST: f32 = 200.; // If an entity further than this is aggroed at a player, the portal will still work
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Sys;
|
pub struct Sys;
|
||||||
|
|
||||||
|
fn in_portal_range(player_pos: Vec3<f32>, portal_pos: Vec3<f32>) -> bool {
|
||||||
|
player_pos.distance_squared(portal_pos) <= (TELEPORT_RADIUS).powi(2)
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> System<'a> for Sys {
|
impl<'a> System<'a> for Sys {
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
@ -19,7 +25,10 @@ impl<'a> System<'a> for Sys {
|
|||||||
ReadStorage<'a, Teleporter>,
|
ReadStorage<'a, Teleporter>,
|
||||||
ReadStorage<'a, Agent>,
|
ReadStorage<'a, Agent>,
|
||||||
WriteStorage<'a, ForceUpdate>,
|
WriteStorage<'a, ForceUpdate>,
|
||||||
|
WriteStorage<'a, Teleporting>,
|
||||||
|
WriteStorage<'a, Body>,
|
||||||
Read<'a, CachedSpatialGrid>,
|
Read<'a, CachedSpatialGrid>,
|
||||||
|
Read<'a, Time>,
|
||||||
);
|
);
|
||||||
|
|
||||||
const NAME: &'static str = "teleporter";
|
const NAME: &'static str = "teleporter";
|
||||||
@ -35,47 +44,101 @@ impl<'a> System<'a> for Sys {
|
|||||||
teleporters,
|
teleporters,
|
||||||
agent,
|
agent,
|
||||||
mut forced_update,
|
mut forced_update,
|
||||||
|
mut teleporting,
|
||||||
|
mut bodies,
|
||||||
spatial_grid,
|
spatial_grid,
|
||||||
|
time,
|
||||||
): Self::SystemData,
|
): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
let mut attempt_teleport = vec![];
|
let mut attempt_teleport = vec![];
|
||||||
let mut player_data = (&entities, &positions, &players).join();
|
let mut cancel_teleport = vec![];
|
||||||
|
let mut start_teleporting = vec![];
|
||||||
|
|
||||||
for (_entity, teleporter_pos, teleporter) in (&entities, &positions, &teleporters).join() {
|
let mut player_data = (&entities, &positions, &players, teleporting.maybe()).join();
|
||||||
let nearby_entities = spatial_grid
|
|
||||||
|
let check_aggro = |entity, pos: Vec3<f32>| {
|
||||||
|
spatial_grid
|
||||||
.0
|
.0
|
||||||
.in_circle_aabr(teleporter_pos.0.xy(), TELEPORT_RADIUS);
|
.in_circle_aabr(pos.xy(), MAX_AGGRO_DIST)
|
||||||
|
|
||||||
for (entity, position, _) in nearby_entities.filter_map(|entity| {
|
|
||||||
player_data
|
|
||||||
.get(entity, &entities)
|
|
||||||
.filter(|(_, player_pos, _)| {
|
|
||||||
player_pos.0.distance_squared(teleporter_pos.0) <= (TELEPORT_RADIUS).powi(2)
|
|
||||||
})
|
|
||||||
}) {
|
|
||||||
// TODO: Check for aggro
|
|
||||||
attempt_teleport.push((entity, position.0, teleporter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (entity, origin_pos, teleporter) in attempt_teleport {
|
|
||||||
if teleporter.requires_no_aggro {
|
|
||||||
// FIXME: How does this go with performance?
|
|
||||||
let is_aggroed = spatial_grid
|
|
||||||
.0
|
|
||||||
.in_circle_aabr(origin_pos.xy(), MAX_AGGRO_DIST)
|
|
||||||
.any(|agent_entity| {
|
.any(|agent_entity| {
|
||||||
agent.get(agent_entity).map_or(false, |agent| {
|
agent.get(agent_entity).map_or(false, |agent| {
|
||||||
agent.target.map_or(false, |agent_target| {
|
agent.target.map_or(false, |agent_target| {
|
||||||
agent_target.target == entity && agent_target.aggro_on
|
agent_target.target == entity && agent_target.aggro_on
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
for (portal_entity, teleporter_pos, mut body, teleporter) in
|
||||||
|
(&entities, &positions, &mut bodies, &teleporters).join()
|
||||||
|
{
|
||||||
|
let nearby_entities = spatial_grid
|
||||||
|
.0
|
||||||
|
.in_circle_aabr(teleporter_pos.0.xy(), TELEPORT_RADIUS);
|
||||||
|
|
||||||
|
let mut is_active = false;
|
||||||
|
|
||||||
|
for (entity, pos, _, teleporting) in nearby_entities.filter_map(|entity| {
|
||||||
|
player_data
|
||||||
|
.get(entity, &entities)
|
||||||
|
.filter(|(_, player_pos, _, _)| in_portal_range(player_pos.0, teleporter_pos.0))
|
||||||
|
}) {
|
||||||
|
if teleporter.requires_no_aggro && check_aggro(entity, pos.0) {
|
||||||
|
if teleporting.is_some() {
|
||||||
|
cancel_teleport.push(entity)
|
||||||
|
};
|
||||||
|
|
||||||
if is_aggroed {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if teleporting.is_none() {
|
||||||
|
start_teleporting.push((entity, Teleporting {
|
||||||
|
teleport_start: *time,
|
||||||
|
portal: portal_entity,
|
||||||
|
end_time: Time(time.0 + teleporter.buildup_time.0),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*body == Body::Object(object::Body::PortalActive)) != is_active {
|
||||||
|
*body = Body::Object(if is_active {
|
||||||
|
object::Body::PortalActive
|
||||||
|
} else {
|
||||||
|
object::Body::Portal
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entity, teleporting_data) in start_teleporting {
|
||||||
|
let _ = teleporting.insert(entity, teleporting_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entity, position, _, teleporting) in
|
||||||
|
(&entities, &positions, &players, &teleporting).join()
|
||||||
|
{
|
||||||
|
let portal_pos = positions.get(teleporting.portal);
|
||||||
|
let Some(teleporter) = teleporters.get(teleporting.portal) else {
|
||||||
|
cancel_teleport.push(entity);
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
|
||||||
|
if portal_pos.map_or(true, |portal_pos| {
|
||||||
|
!in_portal_range(position.0, portal_pos.0)
|
||||||
|
}) {
|
||||||
|
cancel_teleport.push(entity);
|
||||||
|
} else if teleporting.end_time.0 <= time.0 {
|
||||||
|
attempt_teleport.push((entity, *teleporter));
|
||||||
|
cancel_teleport.push(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for entity in cancel_teleport {
|
||||||
|
teleporting.remove(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entity, teleporter) in attempt_teleport {
|
||||||
positions
|
positions
|
||||||
.get_mut(entity)
|
.get_mut(entity)
|
||||||
.map(|position| position.0 = teleporter.target);
|
.map(|position| position.0 = teleporter.target);
|
||||||
|
@ -3,7 +3,10 @@ use crate::{
|
|||||||
util::{RandomField, Sampler, CARDINALS},
|
util::{RandomField, Sampler, CARDINALS},
|
||||||
Land,
|
Land,
|
||||||
};
|
};
|
||||||
use common::{terrain::{BlockKind, SpriteKind}, generation::SpecialEntity};
|
use common::{
|
||||||
|
generation::SpecialEntity,
|
||||||
|
terrain::{BlockKind, SpriteKind},
|
||||||
|
};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -326,7 +329,8 @@ impl Structure for CoastalWorkshop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
painter.spawn(
|
painter.spawn(
|
||||||
EntityInfo::at((center - 2).with_z(base - 2).map(|e| e as f32 + 0.5)).into_special(SpecialEntity::Waypoint),
|
EntityInfo::at((center - 2).with_z(base - 2).map(|e| e as f32 + 0.5))
|
||||||
|
.into_special(SpecialEntity::Waypoint),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ use common::{
|
|||||||
astar::Astar,
|
astar::Astar,
|
||||||
comp::Teleporter,
|
comp::Teleporter,
|
||||||
generation::{ChunkSupplement, EntityInfo, SpecialEntity},
|
generation::{ChunkSupplement, EntityInfo, SpecialEntity},
|
||||||
|
resources::Secs,
|
||||||
store::{Id, Store},
|
store::{Id, Store},
|
||||||
terrain::{
|
terrain::{
|
||||||
BiomeKind, Block, BlockKind, SpriteKind, Structure, StructuresGroup, TerrainChunkSize,
|
BiomeKind, Block, BlockKind, SpriteKind, Structure, StructuresGroup, TerrainChunkSize,
|
||||||
@ -668,12 +669,14 @@ impl Floor {
|
|||||||
SpecialEntity::Teleporter(Teleporter {
|
SpecialEntity::Teleporter(Teleporter {
|
||||||
target: bottom_pos+ Vec3::unit_x() * 5.,
|
target: bottom_pos+ Vec3::unit_x() * 5.,
|
||||||
requires_no_aggro: false,
|
requires_no_aggro: false,
|
||||||
|
buildup_time: Secs(1.),
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
supplement.add_entity(EntityInfo::at(bottom_pos).into_special(
|
supplement.add_entity(EntityInfo::at(bottom_pos).into_special(
|
||||||
SpecialEntity::Teleporter(Teleporter {
|
SpecialEntity::Teleporter(Teleporter {
|
||||||
target: top_pos+ Vec3::unit_x() * 5.,
|
target: top_pos+ Vec3::unit_x() * 5.,
|
||||||
requires_no_aggro: true,
|
requires_no_aggro: true,
|
||||||
|
buildup_time: Secs(3.),
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user