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: (
|
||||
bone0: (
|
||||
offset: (-11.0, -1.5, 0.0),
|
||||
offset: (-33.0, -33.0, 0.0),
|
||||
central: ("object.portal"),
|
||||
),
|
||||
bone1: (
|
||||
offset: (0.0, 0.0, 0.0),
|
||||
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("z", 0., Required),
|
||||
Boolean("requires_no_aggro", "true".to_string(), Optional),
|
||||
Float("buildup_time", 5., Optional),
|
||||
],
|
||||
"Spawns a portal",
|
||||
Some(Moderator),
|
||||
|
@ -111,6 +111,7 @@ make_case_elim!(
|
||||
LightningBolt = 96,
|
||||
SpearIcicle = 97,
|
||||
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::Bomb,
|
||||
Body::Scarecrow,
|
||||
@ -221,6 +222,7 @@ pub const ALL_OBJECTS: [Body; 99] = [
|
||||
Body::LightningBolt,
|
||||
Body::SpearIcicle,
|
||||
Body::Portal,
|
||||
Body::PortalActive,
|
||||
];
|
||||
|
||||
impl From<Body> for super::Body {
|
||||
@ -329,6 +331,7 @@ impl Body {
|
||||
Body::LightningBolt => "lightning_bolt",
|
||||
Body::SpearIcicle => "spear_icicle",
|
||||
Body::Portal => "portal",
|
||||
Self::PortalActive => "portal_active",
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,7 +456,7 @@ impl Body {
|
||||
Body::AdletTrap => 10.0,
|
||||
Body::Mine => 100.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)
|
||||
|
@ -3,7 +3,6 @@ use crate::{resources::Time, uid::Uid};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Object {
|
||||
@ -23,13 +22,3 @@ pub enum Object {
|
||||
impl Component for Object {
|
||||
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 skillset;
|
||||
mod stats;
|
||||
mod teleport;
|
||||
pub mod visual;
|
||||
|
||||
// Reexports
|
||||
@ -86,7 +87,7 @@ pub use self::{
|
||||
location::{MapMarker, MapMarkerChange, MapMarkerUpdate, Waypoint, WaypointArea},
|
||||
loot_owner::LootOwner,
|
||||
melee::{Melee, MeleeConstructor, MeleeConstructorKind},
|
||||
misc::{Object, Teleporter},
|
||||
misc::Object,
|
||||
ori::Ori,
|
||||
pet::Pet,
|
||||
phys::{
|
||||
@ -103,6 +104,7 @@ pub use self::{
|
||||
SkillGroup, SkillGroupKind, SkillSet,
|
||||
},
|
||||
stats::{Stats, StatsModifier},
|
||||
teleport::{Teleporter, Teleporting},
|
||||
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::Stance>();
|
||||
ecs.register::<comp::Teleporter>();
|
||||
ecs.register::<comp::Teleporting>();
|
||||
|
||||
// Register components send from clients -> server
|
||||
ecs.register::<comp::Controller>();
|
||||
|
@ -2051,15 +2051,17 @@ fn handle_spawn_portal(
|
||||
) -> CmdResult<()> {
|
||||
let pos = position(server, target, "target")?;
|
||||
|
||||
if let (Some(x), Some(y), Some(z), requires_no_aggro) =
|
||||
parse_cmd_args!(args, f32, f32, f32, bool)
|
||||
if let (Some(x), Some(y), Some(z), requires_no_aggro, buildup_time) =
|
||||
parse_cmd_args!(args, f32, f32, f32, bool, f64)
|
||||
{
|
||||
let requires_no_aggro = requires_no_aggro.unwrap_or(false);
|
||||
let buildup_time = Secs(buildup_time.unwrap_or(0.));
|
||||
server
|
||||
.state
|
||||
.create_teleporter(pos, comp::Teleporter {
|
||||
target: Vec3::new(x, y, z),
|
||||
requires_no_aggro,
|
||||
buildup_time,
|
||||
})
|
||||
.build();
|
||||
|
||||
|
@ -1,16 +1,22 @@
|
||||
use common::{
|
||||
comp::{Agent, ForceUpdate, Player, Pos, Teleporter},
|
||||
comp::{object, Agent, Body, ForceUpdate, Player, Pos, Teleporter, Teleporting},
|
||||
resources::Time,
|
||||
CachedSpatialGrid,
|
||||
};
|
||||
use common_ecs::{Origin, Phase, System};
|
||||
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
|
||||
|
||||
#[derive(Default)]
|
||||
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 {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
@ -19,7 +25,10 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Teleporter>,
|
||||
ReadStorage<'a, Agent>,
|
||||
WriteStorage<'a, ForceUpdate>,
|
||||
WriteStorage<'a, Teleporting>,
|
||||
WriteStorage<'a, Body>,
|
||||
Read<'a, CachedSpatialGrid>,
|
||||
Read<'a, Time>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "teleporter";
|
||||
@ -35,47 +44,101 @@ impl<'a> System<'a> for Sys {
|
||||
teleporters,
|
||||
agent,
|
||||
mut forced_update,
|
||||
mut teleporting,
|
||||
mut bodies,
|
||||
spatial_grid,
|
||||
time,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
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 check_aggro = |entity, pos: Vec3<f32>| {
|
||||
spatial_grid
|
||||
.0
|
||||
.in_circle_aabr(pos.xy(), MAX_AGGRO_DIST)
|
||||
.any(|agent_entity| {
|
||||
agent.get(agent_entity).map_or(false, |agent| {
|
||||
agent.target.map_or(false, |agent_target| {
|
||||
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);
|
||||
|
||||
for (entity, position, _) in nearby_entities.filter_map(|entity| {
|
||||
let mut is_active = false;
|
||||
|
||||
for (entity, pos, _, teleporting) 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)
|
||||
})
|
||||
.filter(|(_, player_pos, _, _)| in_portal_range(player_pos.0, teleporter_pos.0))
|
||||
}) {
|
||||
// TODO: Check for aggro
|
||||
attempt_teleport.push((entity, position.0, teleporter))
|
||||
if teleporter.requires_no_aggro && check_aggro(entity, pos.0) {
|
||||
if teleporting.is_some() {
|
||||
cancel_teleport.push(entity)
|
||||
};
|
||||
|
||||
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, 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| {
|
||||
agent.get(agent_entity).map_or(false, |agent| {
|
||||
agent.target.map_or(false, |agent_target| {
|
||||
agent_target.target == entity && agent_target.aggro_on
|
||||
})
|
||||
})
|
||||
});
|
||||
for (entity, teleporting_data) in start_teleporting {
|
||||
let _ = teleporting.insert(entity, teleporting_data);
|
||||
}
|
||||
|
||||
if is_aggroed {
|
||||
continue;
|
||||
}
|
||||
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
|
||||
.get_mut(entity)
|
||||
.map(|position| position.0 = teleporter.target);
|
||||
|
@ -3,7 +3,10 @@ use crate::{
|
||||
util::{RandomField, Sampler, CARDINALS},
|
||||
Land,
|
||||
};
|
||||
use common::{terrain::{BlockKind, SpriteKind}, generation::SpecialEntity};
|
||||
use common::{
|
||||
generation::SpecialEntity,
|
||||
terrain::{BlockKind, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
@ -326,7 +329,8 @@ impl Structure for CoastalWorkshop {
|
||||
}
|
||||
|
||||
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,
|
||||
comp::Teleporter,
|
||||
generation::{ChunkSupplement, EntityInfo, SpecialEntity},
|
||||
resources::Secs,
|
||||
store::{Id, Store},
|
||||
terrain::{
|
||||
BiomeKind, Block, BlockKind, SpriteKind, Structure, StructuresGroup, TerrainChunkSize,
|
||||
@ -668,12 +669,14 @@ impl Floor {
|
||||
SpecialEntity::Teleporter(Teleporter {
|
||||
target: bottom_pos+ Vec3::unit_x() * 5.,
|
||||
requires_no_aggro: false,
|
||||
buildup_time: Secs(1.),
|
||||
}),
|
||||
));
|
||||
supplement.add_entity(EntityInfo::at(bottom_pos).into_special(
|
||||
SpecialEntity::Teleporter(Teleporter {
|
||||
target: top_pos+ Vec3::unit_x() * 5.,
|
||||
requires_no_aggro: true,
|
||||
buildup_time: Secs(3.),
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user