mindustry logic execution, map- and schematic- parsing and rendering
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
use std::fmt;

use crate::content::{Content, Type};

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Team(u8);

impl Team {
    #[must_use]
    pub const fn of(id: u8) -> Self {
        Self(id)
    }

    #[must_use]
    pub const fn is_base(self) -> bool {
        self.0 < 7
    }
}

impl From<u8> for Team {
    fn from(value: u8) -> Self {
        Team::of(value)
    }
}

impl TryFrom<u16> for Team {
    type Error = TryFromU16Error;

    fn try_from(value: u16) -> Result<Self, Self::Error> {
        if u8::try_from(value).is_ok() {
            Ok(Team(value as u8))
        } else {
            Err(TryFromU16Error(value))
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, thiserror::Error)]
#[error("no content of type Team for value {0}")]
pub struct TryFromU16Error(pub u16);

impl From<Team> for u8 {
    fn from(value: Team) -> Self {
        value.0
    }
}

impl From<Team> for u16 {
    fn from(value: Team) -> Self {
        u16::from(value.0)
    }
}

impl fmt::Display for Team {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.0 {
            0 => f.write_str("Derelict"),
            1 => f.write_str("Sharded"),
            2 => f.write_str("Crux"),
            3 => f.write_str("Malis"),
            4 => f.write_str("Green"),
            5 => f.write_str("Blue"),
            6 => f.write_str("Neoplastic"),
            id => write!(f, "Team #{id}"),
        }
    }
}

const TEAM_NAMES: &str = include_str!("../res/team_names.txt");

impl Content for Team {
    fn get_type(&self) -> Type {
        Type::Team
    }

    fn get_id(&self) -> u16 {
        u16::from(self.0)
    }

    fn get_name(&self) -> &'static str {
        match self.0 {
            0 => "derelict",
            1 => "sharded",
            2 => "crux",
            3 => "malis",
            4 => "green",
            5 => "blue",
            6 => "neoplastic",
            // dark magic: offsets manually computed, then rely on the format "...|team#{i}|..."
            i @ 7..=9 => {
                // length: 7 ("team#" (5) + 1 digit + "|" (1))
                let s = ((i - 6) as usize) * 7;
                &TEAM_NAMES[s..s + 6] // exclude the trailing "|"
            }
            i @ 10..=99 => {
                // length: 8 ("team#" (5) + 2 digits + "|" (1))
                let s = 28 + ((i - 10) as usize) * 8;
                &TEAM_NAMES[s..s + 7] // exclude the trailing "|"
            }
            i @ 100..=255 => {
                // length: 9 ("team#" (5) + 3 digits + "|" (1))
                let s = 748 + ((i - 100) as usize) * 9;
                &TEAM_NAMES[s..s + 8] // exclude the trailing "|"
            }
        }
    }
}

impl Team {
    pub const fn color(self) -> (u8, u8, u8) {
        macro_rules! h {
            ($x:literal) => {{
                let v = color_hex::color_from_hex!($x);
                (v[0], v[1], v[2])
            }};
        }
        match self {
            SHARDED => h!("ffd37f"),
            DERELICT => h!("4d4e58"),
            CRUX => h!("f25555"),
            MALIS => h!("a27ce5"),
            GREEN => h!("54d67d"),
            BLUE => h!("6c87fd"),
            NEOPLASTIC => h!("e05438"),
            _ => h!("a9a9a9"),
        }
    }
}

pub const DERELICT: Team = Team(0);
pub const SHARDED: Team = Team(1);
pub const CRUX: Team = Team(2);
pub const MALIS: Team = Team(3);
pub const GREEN: Team = Team(4);
pub const BLUE: Team = Team(5);
pub const NEOPLASTIC: Team = Team(6);