Initial Commit

This commit is contained in:
AviiNL
2023-12-19 19:16:41 +01:00
commit 15f764aae8
47 changed files with 9097 additions and 0 deletions

158
src/main.rs Normal file
View File

@@ -0,0 +1,158 @@
use bevy::{
app::{App, Update},
ecs::{
component::Component,
entity::Entity,
query::{Added, With, Without},
system::{Commands, Query},
},
};
use guardian_core::*;
use tokio::runtime::Handle;
// Every incomming (voice) message is an event
// Systems can handle the events, eg bogey dope, set tripwire or radio check
// voice responses; srs should be a resource?
// |- srs plugin adds a resource to use to send messages i guess
// |-- or spawn an entity with a message commands.spawn((VoiceMessage("Hello World"), TextMessage("Hello World!")))
// |-- srs plugin will check if these components are Added<VoiceMessage> or w/e and handle accordingly
#[tokio::main]
async fn main() {
App::new()
.insert_resource(TokioResource(Handle::current()))
.add_plugins(DefaultPlugins)
.add_systems(Update, (add_tripwire, tripwire))
.run();
}
// this will be on a tripwire command event (from srs), instead of Added<Player>, not everyone may want it; opt-in over opt-out
fn add_tripwire(mut commands: Commands, players: Query<Entity, Added<Player>>) {
for ent in players.iter() {
commands.entity(ent).insert(Tripwire {
range: 30.0,
reported: vec![],
});
}
}
fn tripwire(
mut commands: Commands,
mut players: Query<(&Id, &Callsign, &Position, &mut Tripwire), With<Player>>,
npc: Query<(&Id, &Position, &Heading, &Side), Without<Player>>,
) {
for (p_id, p_callsign, p_position, mut p_tripwire) in players.iter_mut() {
let _p_id = &p_id.0;
let _p_callsign = &p_callsign.0;
for (n_id, n_position, n_heading, side) in npc.iter() {
if side.0 != Coalition::Red {
continue;
}
let n_id = &n_id.0;
let distance = n_position.distance_to_nmi(p_position);
if distance <= p_tripwire.range && !p_tripwire.reported.contains(n_id) {
p_tripwire.reported.push(*n_id);
let bra = Braa::new(p_position, n_position, n_heading);
commands.spawn(TextMessage::new(bra.to_text()));
} else if distance > p_tripwire.range && p_tripwire.reported.contains(n_id) {
p_tripwire.reported.retain(|b| b != n_id);
}
}
}
}
#[derive(Component)]
struct Tripwire {
range: f64,
reported: Vec<u32>,
}
#[derive(Clone)]
pub enum Aspect {
Hot,
Flank,
Cold,
}
impl std::fmt::Display for Aspect {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Hot => write!(f, "Hot"),
Self::Flank => write!(f, "Flank"),
Self::Cold => write!(f, "Cold"),
}
}
}
#[derive(Clone)]
pub struct Braa {
bearing: i32,
range: i32,
angels: i32,
aspect: Aspect,
}
impl Braa {
pub fn new(unit_a: &Position, unit_b: &Position, heading_b: &Heading) -> Self {
let bearing = unit_a.get_bearing_to(unit_b);
let range = unit_a.distance_to_nmi(unit_b).round() as i32;
let angels = unit_b.angels();
let aspect = {
let bearing = unit_b.get_bearing_to(unit_a);
let angle = (bearing - heading_b.0 as i32) % 360;
if (45..135).contains(&angle) {
Aspect::Flank
} else if (135..225).contains(&angle) {
Aspect::Cold
} else if (225..315).contains(&angle) {
Aspect::Flank
} else if !(45..=315).contains(&angle) {
Aspect::Hot
} else {
Aspect::Cold
}
};
Self {
bearing,
range,
angels,
aspect,
}
}
pub fn to_text(&self) -> String {
format!(
"BRA {}° for {}NM at {} thousand {}",
self.bearing, self.range, self.angels, self.aspect
)
}
pub fn to_voice(&self) -> String {
let bearing = split(&self.bearing.to_string(), 1);
let range = split(&self.range.to_string(), 1);
format!(
"BRA <break time=\"250ms\"/> {} <break /> {} <break /> {} thousand <break /> {}",
bearing, range, self.angels, self.aspect
)
}
}
fn split(input: &str, n: usize) -> String {
input
.chars()
.enumerate()
.flat_map(|(i, c)| {
if i != 0 && i % n == 0 {
Some(' ')
} else {
None
}
.into_iter()
.chain(std::iter::once(c))
})
.collect::<String>()
}