/airship angle command and RtSim airships.

This commit is contained in:
Avi Weinstock 2021-03-12 13:53:06 -05:00
parent 64cc97ad59
commit 0b954f8db8
9 changed files with 100 additions and 57 deletions

View File

@ -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)],

View File

@ -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()
}
}

View File

@ -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(_)),

View File

@ -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,
}
}
}

View File

@ -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),

View File

@ -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)

View File

@ -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)),

View File

@ -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(

View File

@ -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 {