aboutsummaryrefslogtreecommitdiff
path: root/games/rstnode/rst-core/src/data.rs
blob: d0494fdef3e22bc25b75932d344844a810c56c5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
//! Data structures for the game

#![allow(unused)]

use crate::io::Io;
use async_std::sync::Arc;
use rand::seq::SliceRandom;
use rand::thread_rng;
use serde::{Deserialize, Serialize};
use std::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<Arc<Link>>,
    /// Input buffer
    #[serde(skip)]
    pub buffer: Vec<Packet>,
}

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<Player>,
    /// 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<u16>,
}

/// An RGB color without alpha
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Color(pub u8, pub u8, pub 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<Color> {
    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<PacketType>, 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,
}