mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
/airship angle
command and RtSim airships.
This commit is contained in:
parent
64cc97ad59
commit
0b954f8db8
@ -224,7 +224,7 @@ impl ChatCommand {
|
||||
"Temporarily gives a player admin permissions or removes them",
|
||||
Admin,
|
||||
),
|
||||
ChatCommand::Airship => cmd(vec![Boolean("moving", "true".to_string(), Optional)], "Spawns an airship", Admin),
|
||||
ChatCommand::Airship => cmd(vec![Float("destination_degrees_ccw_of_east", 90.0, Optional)], "Spawns an airship", Admin),
|
||||
ChatCommand::Alias => cmd(vec![Any("name", Required)], "Change your alias", NoAdmin),
|
||||
ChatCommand::Ban => cmd(
|
||||
vec![Any("username", Required), Message(Optional)],
|
||||
|
@ -205,11 +205,11 @@ impl Agent {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_destination() -> Self {
|
||||
pub fn with_destination(pos: Vec3<f32>) -> Self {
|
||||
Self {
|
||||
can_speak: false,
|
||||
can_speak: true,
|
||||
psyche: Psyche { aggro: 1.0 },
|
||||
rtsim_controller: RtSimController::zero(),
|
||||
rtsim_controller: RtSimController::with_destination(pos),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -509,6 +509,16 @@ impl Body {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flying_height(&self) -> f32 {
|
||||
match self {
|
||||
Body::BirdSmall(_) => 30.0,
|
||||
Body::BirdMedium(_) => 40.0,
|
||||
Body::Dragon(_) => 60.0,
|
||||
Body::Ship(ship::Body::DefaultAirship) => 60.0,
|
||||
_ => 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn immune_to(&self, buff: BuffKind) -> bool {
|
||||
match buff {
|
||||
BuffKind::Bleeding => matches!(self, Body::Object(_) | Body::Golem(_) | Body::Ship(_)),
|
||||
|
@ -46,10 +46,10 @@ impl Default for RtSimController {
|
||||
|
||||
impl RtSimController {
|
||||
pub fn reset(&mut self) { *self = Self::default(); }
|
||||
pub fn zero() -> Self {
|
||||
pub fn with_destination(pos: Vec3<f32>) -> Self {
|
||||
Self {
|
||||
travel_to: Some((Vec3::new(0.0, 0.0, 500.0), "".to_string())),
|
||||
speed_factor: 0.05,
|
||||
travel_to: Some((pos, format!("{:0.1?}", pos))),
|
||||
speed_factor: 0.25,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -965,13 +965,16 @@ fn handle_spawn_airship(
|
||||
args: String,
|
||||
action: &ChatCommand,
|
||||
) {
|
||||
let moving = scan_fmt_some!(&args, &action.arg_fmt(), String).unwrap_or_else(|| "false".to_string()) == "true";
|
||||
let angle = scan_fmt!(&args, &action.arg_fmt(), f32).ok();
|
||||
match server.state.read_component_copied::<comp::Pos>(target) {
|
||||
Some(mut pos) => {
|
||||
pos.0.z += 50.0;
|
||||
const DESTINATION_RADIUS: f32 = 2000.0;
|
||||
let angle = angle.map(|a| a * std::f32::consts::PI / 180.0);
|
||||
let destination = angle.map(|a| pos.0 + Vec3::new(DESTINATION_RADIUS*a.cos(), DESTINATION_RADIUS*a.sin(), 200.0));
|
||||
server
|
||||
.state
|
||||
.create_ship(pos, comp::ship::Body::DefaultAirship, 1, moving)
|
||||
.create_ship(pos, comp::ship::Body::DefaultAirship, 1, destination)
|
||||
.with(comp::Scale(11.0 / 0.8))
|
||||
.with(LightEmitter {
|
||||
col: Rgb::new(1.0, 0.65, 0.2),
|
||||
|
@ -27,7 +27,7 @@ impl Entity {
|
||||
|
||||
pub fn get_body(&self) -> comp::Body {
|
||||
match self.rng(PERM_GENUS).gen::<f32>() {
|
||||
//we want 50% birds, 50% humans for now
|
||||
//we want 5% airships, 45% birds, 50% humans
|
||||
x if x < 0.05 => {
|
||||
comp::Body::Ship(comp::ship::Body::DefaultAirship)
|
||||
},
|
||||
@ -135,7 +135,7 @@ impl Entity {
|
||||
.iter()
|
||||
.filter(|s| match self.get_body() {
|
||||
comp::Body::Humanoid(_) => s.1.is_settlement() | s.1.is_castle(),
|
||||
comp::Body::Ship(_) => s.1.is_castle(),
|
||||
comp::Body::Ship(_) => s.1.is_settlement(),
|
||||
_ => s.1.is_dungeon(),
|
||||
})
|
||||
.filter(|_| thread_rng().gen_range(0i32..4) == 0)
|
||||
|
@ -121,7 +121,10 @@ impl<'a> System<'a> for Sys {
|
||||
comp::Body::Humanoid(_) => comp::Alignment::Npc,
|
||||
_ => comp::Alignment::Wild,
|
||||
},
|
||||
scale: comp::Scale(1.0),
|
||||
scale: match body {
|
||||
comp::Body::Ship(_) => comp::Scale(11.0 / 0.8),
|
||||
_ => comp::Scale(1.0),
|
||||
},
|
||||
drop_item: None,
|
||||
home_chunk: None,
|
||||
rtsim_entity: Some(RtSimEntity(id)),
|
||||
|
@ -41,7 +41,13 @@ pub trait StateExt {
|
||||
) -> EcsEntityBuilder;
|
||||
/// Build a static object entity
|
||||
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder;
|
||||
fn create_ship(&mut self, pos: comp::Pos, ship: comp::ship::Body, level: u16, moving: bool) -> EcsEntityBuilder;
|
||||
fn create_ship(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
ship: comp::ship::Body,
|
||||
level: u16,
|
||||
destination: Option<Vec3<f32>>,
|
||||
) -> EcsEntityBuilder;
|
||||
/// Build a projectile
|
||||
fn create_projectile(
|
||||
&mut self,
|
||||
@ -161,10 +167,15 @@ impl StateExt for State {
|
||||
))
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.with(comp::Collider::Box {
|
||||
radius: body.radius(),
|
||||
z_min: 0.0,
|
||||
z_max: body.height(),
|
||||
.with(match body {
|
||||
comp::Body::Ship(ship) => comp::Collider::Voxel {
|
||||
id: ship.manifest_entry().to_string(),
|
||||
},
|
||||
_ => comp::Collider::Box {
|
||||
radius: body.radius(),
|
||||
z_min: 0.0,
|
||||
z_max: body.height(),
|
||||
},
|
||||
})
|
||||
.with(comp::Controller::default())
|
||||
.with(body)
|
||||
@ -203,46 +214,38 @@ impl StateExt for State {
|
||||
.with(comp::Gravity(1.0))
|
||||
}
|
||||
|
||||
fn create_ship(&mut self, pos: comp::Pos, ship: comp::ship::Body, level: u16, moving: bool) -> EcsEntityBuilder {
|
||||
if moving {
|
||||
self.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori::default())
|
||||
.with(comp::Mass(50.0))
|
||||
.with(comp::Collider::Voxel { id: ship.manifest_entry().to_string() })
|
||||
.with(comp::Body::Ship(ship))
|
||||
.with(comp::Gravity(1.0))
|
||||
.with(comp::Controller::default())
|
||||
.with(comp::inventory::Inventory::new_empty())
|
||||
.with(comp::CharacterState::default())
|
||||
.with(comp::Energy::new(ship.into(), level))
|
||||
.with(comp::Health::new(ship.into(), level))
|
||||
.with(comp::Stats::new("Airship".to_string()))
|
||||
.with(comp::MountState::Unmounted)
|
||||
.with(comp::Buffs::default())
|
||||
.with(comp::Combo::default())
|
||||
.with(comp::Agent::with_destination())
|
||||
} else {
|
||||
self.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori::default())
|
||||
.with(comp::Mass(50.0))
|
||||
.with(comp::Collider::Voxel { id: ship.manifest_entry().to_string() })
|
||||
.with(comp::Body::Ship(ship))
|
||||
.with(comp::Gravity(1.0))
|
||||
.with(comp::Controller::default())
|
||||
.with(comp::inventory::Inventory::new_empty())
|
||||
.with(comp::CharacterState::default())
|
||||
.with(comp::Energy::new(ship.into(), level))
|
||||
.with(comp::Health::new(ship.into(), level))
|
||||
.with(comp::Stats::new("Airship".to_string()))
|
||||
.with(comp::Buffs::default())
|
||||
.with(comp::Combo::default())
|
||||
fn create_ship(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
ship: comp::ship::Body,
|
||||
level: u16,
|
||||
destination: Option<Vec3<f32>>,
|
||||
) -> EcsEntityBuilder {
|
||||
let mut builder = self
|
||||
.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori::default())
|
||||
.with(comp::Mass(50.0))
|
||||
.with(comp::Collider::Voxel {
|
||||
id: ship.manifest_entry().to_string(),
|
||||
})
|
||||
.with(comp::Body::Ship(ship))
|
||||
.with(comp::Gravity(1.0))
|
||||
.with(comp::Controller::default())
|
||||
.with(comp::inventory::Inventory::new_empty())
|
||||
.with(comp::CharacterState::default())
|
||||
.with(comp::Energy::new(ship.into(), level))
|
||||
.with(comp::Health::new(ship.into(), level))
|
||||
.with(comp::Stats::new("Airship".to_string()))
|
||||
.with(comp::Buffs::default())
|
||||
.with(comp::MountState::Unmounted)
|
||||
.with(comp::Combo::default());
|
||||
if let Some(pos) = destination {
|
||||
builder = builder.with(comp::Agent::with_destination(pos))
|
||||
}
|
||||
builder
|
||||
}
|
||||
|
||||
fn create_projectile(
|
||||
|
@ -32,7 +32,7 @@ use specs::{
|
||||
Entities, Entity as EcsEntity, Join, ParJoin, Read, ReadExpect, ReadStorage, SystemData, World,
|
||||
Write, WriteStorage,
|
||||
};
|
||||
use std::f32::consts::PI;
|
||||
use std::{f32::consts::PI, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
struct AgentData<'a> {
|
||||
@ -81,6 +81,7 @@ pub struct ReadData<'a> {
|
||||
//ReadStorage<'a, Invite>,
|
||||
time_of_day: Read<'a, TimeOfDay>,
|
||||
light_emitter: ReadStorage<'a, LightEmitter>,
|
||||
world: ReadExpect<'a, Arc<world::World>>,
|
||||
}
|
||||
|
||||
// This is 3.1 to last longer than the last damage timer (3.0 seconds)
|
||||
@ -603,6 +604,29 @@ impl<'a> AgentData<'a> {
|
||||
.cast()
|
||||
.1
|
||||
.map_or(true, |b| b.is_some())
|
||||
|| self
|
||||
.body
|
||||
.map(|body| {
|
||||
let height_approx = self.pos.0.y
|
||||
- read_data
|
||||
.world
|
||||
.sim()
|
||||
.get_alt_approx(self.pos.0.xy().map(|x: f32| x as i32))
|
||||
.unwrap_or(0.0);
|
||||
|
||||
height_approx < body.flying_height()
|
||||
|| read_data
|
||||
.terrain
|
||||
.ray(
|
||||
self.pos.0,
|
||||
self.pos.0 - body.flying_height() * Vec3::unit_z(),
|
||||
)
|
||||
.until(|b: &Block| b.is_solid() || b.is_liquid())
|
||||
.cast()
|
||||
.1
|
||||
.map_or(false, |b| b.is_some())
|
||||
})
|
||||
.unwrap_or(false)
|
||||
{
|
||||
1.0 //fly up when approaching obstacles
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user