//! Data structures for the game use crate::io::Io; use async_std::sync::Arc; use rand::seq::SliceRandom; use rand::thread_rng; use serde::{Deserialize, Serialize}; use std::{ collections::BTreeMap, sync::atomic::{AtomicBool, AtomicU16, AtomicU32}, }; pub type NodeId = usize; /// A node is a computer on the network graph /// /// It's owned by a player, and has some upgrade state, as well as /// base stats. #[derive(Serialize, Deserialize)] pub struct Node { /// Each node has a unique ID by which it's addressed pub id: NodeId, /// The current health pub health: AtomicU32, /// The max health pub max_health: AtomicU32, /// The owner of this node pub owner: Owner, /// Upgrade state pub type_: Upgrade, /// Number of links on the map pub links: u8, /// Active link states pub link_states: Vec>, /// Input buffer #[serde(skip)] pub buffer: Vec, } pub type LinkId = usize; /// A one-to-one link between two nodes #[derive(Serialize, Deserialize)] pub struct Link { /// This link ID id: LinkId, /// Node 1 a: NodeId, /// Node 2 b: NodeId, /// The step length length: usize, /// Packets present on this link #[serde(skip)] pp: Vec<(Packet, AtomicU32)>, /// Actual Rx, Tx pair #[serde(skip)] io: Io, } pub type PacketId = usize; /// A packet going across the network pub struct Packet { /// The packet ID id: PacketId, /// Declare this packet to be removed dead: AtomicBool, /// Each packet is owned by a player owner: Arc, /// What type of packet this is data_: PacketType, } pub type PlayerId = usize; /// A player who's having fun #[derive(Serialize, Deserialize)] pub struct Player { /// A unique player ID (per match) pub id: PlayerId, /// The player name pub name: String, /// Player color pub color: Color, /// The player's money pub money: AtomicU16, } /// Optionally, players can create teams #[derive(Serialize, Deserialize)] pub struct Team { /// Name of the team name: String, /// Unified color of the team color: Color, /// All team members by their ID roster: Vec, } /// An RGB color without alpha #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Color(u8, u8, u8); impl Color { pub fn black() -> Self { Self(50, 50, 50) } pub fn red() -> Self { Self(250, 50, 50) } pub fn green() -> Self { Self(100, 250, 100) } pub fn blue() -> Self { Self(100, 100, 250) } pub fn teal() -> Self { Self(150, 250, 250) } pub fn purple() -> Self { Self(150, 100, 250) } pub fn orange() -> Self { Self(250, 200, 100) } pub fn yellow() -> Self { Self(250, 250, 100) } pub fn white() -> Self { Self(225, 225, 225) } } pub trait ColorPalette { /// Create a new color palette fn palette() -> Self; /// Get a palette without a certain colour fn without(&mut self, b: &Color); /// Mix a color back into the available palette fn remix(&mut self, new: Color); } impl ColorPalette for Vec { fn palette() -> Self { let mut rng = thread_rng(); let mut pal = vec![ Color::black(), Color::red(), Color::green(), Color::blue(), Color::teal(), Color::purple(), Color::orange(), Color::yellow(), Color::white(), ]; pal.shuffle(&mut rng); pal } /// Drop a colour from the palette fn without(&mut self, b: &Color) { if let Some(pos) = self.into_iter().rposition(|a| a == b) { self.remove(pos); } } fn remix(&mut self, new: Color) { let mut rng = thread_rng(); self.push(new); self.shuffle(&mut rng); } } /// Describes ownership state #[derive(Serialize, Deserialize)] pub enum Owner { /// Nobody owns this Neutral, /// A player owns this Player(Player), } /// Encodes upgrade level without numbers #[derive(Copy, Clone, Serialize, Deserialize)] pub enum Level { /// 1 One, /// 2 Two, /// 3 (wow) Three, } /// Describes upgrade state #[derive(Copy, Clone, Serialize, Deserialize)] pub enum Upgrade { /// A basic node Base, /// Battle (attack/defence) nodes Guard(Level), /// These nodes make money Compute(Level), /// Good at packet switching Relay(Level), } /// Possible types of packets pub enum PacketType { /// A keepalive packet /// /// These are sent by all nodes if their neighbours are either /// friendly or neutral, and used to keep the network alive. /// Sending them costs nothing, and when they are received, they /// yield a small amount of funds, and restoring health of a node. Ping, /// A non exploit capture /// /// This is a packet that can be sent out by any node (except a /// switch) to claim a neutral node on the network. The path to /// the node needs to consist only of friendlies, and if an enemy /// node processes this type, nothing happens. Capture, /// A compute packet /// /// The first value is the target compute value, which each /// compute node adds on to. The second value is the current. If /// a compute packet passes through a compromised or enemy node, /// it might subtract from the second value, before palling it on. Compute { max: u16, curr: AtomicU16, step: u16, }, /// A special wrapper packet generated by guards /// /// Sometimes, when a hostily attack packet encounters a guard, it /// manages to capture the attack, and forwards it to a random /// compute node. If the node manages to handle the packet, /// without it getting dropped in the meantime), it yields a /// specified reward, like a computation would. Payload { inner: Box, reward: u16 }, /// A reset attack packet /// /// When encountering a hostile node, it will make that node drop /// all packets in it's buffers. Reset, /// Cross-node-scripting attack /// /// Decreases the strength of a node, also having a small chance /// of spawning a new packet into a random output buffer. When /// applied to a neutral node, it makes capturing nodes go faster. CNS, /// Node-in-the-middle attack /// /// Infect the routing behaviour of a node to route all traffic to /// a specified enemy node instead Nitm, /// Virus infection attack /// /// Infects a node to capture it's earnings, both active and /// passive, for a short time, without taking on it's costs. Virus, /// A total control exploit /// /// This is very hard to do, and a node will basically always /// resist it, but if successful, transforms the node into a guard /// node and yields control to the attackinng player. TakeOver, }