wip
This commit is contained in:
commit
ac5ff9301b
|
@ -0,0 +1,3 @@
|
|||
/target
|
||||
/Cargo.lock
|
||||
/.idea/
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "game-engine"
|
||||
version = "0.1.0"
|
||||
authors = ["Max Bradbury <max@tinybird.info>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
toml = "^0.5.6"
|
||||
serde = "^1.0.114"
|
||||
serde_derive = "^1.0.114"
|
|
@ -0,0 +1,504 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Colour {
|
||||
red: u8,
|
||||
green: u8,
|
||||
blue: u8,
|
||||
alpha: u8,
|
||||
}
|
||||
|
||||
impl Colour {
|
||||
pub fn from(colours: Vec<u8>) -> Colour {
|
||||
const ZERO: u8 = 0;
|
||||
Colour {
|
||||
red: *colours.get(0).unwrap_or(&ZERO),
|
||||
green: *colours.get(1).unwrap_or(&ZERO),
|
||||
blue: *colours.get(2).unwrap_or(&ZERO),
|
||||
alpha: *colours.get(3).unwrap_or(&255),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
vec![self.red, self.green, self.blue, self.alpha]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Palette {
|
||||
name: String,
|
||||
colours: Vec<Colour>,
|
||||
}
|
||||
|
||||
impl Palette {
|
||||
pub fn from(name: &str, toml: &str) -> Self {
|
||||
let intermediate: IntermediatePalette = toml::from_str(toml).unwrap();
|
||||
|
||||
println!("palette name: {}", name);
|
||||
|
||||
for colour in &intermediate.colours {
|
||||
println!("palette colour: {}{}{}", colour[0], colour[1], colour[2]);
|
||||
}
|
||||
|
||||
Palette {
|
||||
name: name.to_string(),
|
||||
colours: intermediate.colours.iter().map(|vec| {
|
||||
Colour::from(vec.clone())
|
||||
}).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_file(path: String) -> Self {
|
||||
// todo get name without extension
|
||||
let name = "blah";
|
||||
let toml = fs::read_to_string(path).unwrap();
|
||||
Self::from(name, &toml)
|
||||
}
|
||||
}
|
||||
|
||||
/// for toml purposes
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct IntermediatePalette {
|
||||
colours: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
/// for toml purposes
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct IntermediatePalettes {
|
||||
/// singular so each palette section is named "palette" instead of "palettes" in toml
|
||||
palette: Vec<IntermediatePalette>,
|
||||
}
|
||||
|
||||
impl IntermediatePalettes {
|
||||
pub fn from_dir() -> Self {
|
||||
Self {
|
||||
palette: vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq)]
|
||||
pub struct Position {
|
||||
x: u8,
|
||||
y: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Image {
|
||||
name: String,
|
||||
/// colour indexes
|
||||
pixels: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
fn from(intermediate: IntermediateImage) -> Image {
|
||||
Image {
|
||||
name: intermediate.name.to_owned(),
|
||||
pixels: intermediate.pixels.split_whitespace().collect::<String>().chars().map(
|
||||
|char|char as u8
|
||||
).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// for toml purposes
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct IntermediateImages {
|
||||
/// singular so each image is named "image" instead of "images" in toml
|
||||
image: Vec<IntermediateImage>,
|
||||
}
|
||||
|
||||
impl IntermediateImages {
|
||||
fn to_images(&self) -> Vec<Image> {
|
||||
self.image.iter().map(|intermediate|
|
||||
Image::from(intermediate.clone())
|
||||
).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
struct IntermediateImage {
|
||||
name: String,
|
||||
pixels: String,
|
||||
}
|
||||
|
||||
impl IntermediateImage {
|
||||
// todo refactor
|
||||
fn from(image: Image) -> IntermediateImage {
|
||||
let mut string = "\n".to_string();
|
||||
|
||||
let sqrt = (image.pixels.len() as f64).sqrt() as usize;
|
||||
for line in image.pixels.chunks(sqrt) {
|
||||
for pixel in line {
|
||||
string.push_str(&format!("{}", *pixel));
|
||||
}
|
||||
string.push('\n');
|
||||
}
|
||||
|
||||
IntermediateImage {
|
||||
name: image.name.to_owned(),
|
||||
/// todo wtf? I guess this crate doesn't handle multiline strings correctly
|
||||
pixels: format!("\"\"{}\"\"", string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct Thing {
|
||||
// name: Option<String>,
|
||||
// /// image name
|
||||
// image: String,
|
||||
// }
|
||||
//
|
||||
|
||||
pub struct Room {
|
||||
name: String,
|
||||
width: u8,
|
||||
height: u8,
|
||||
/// thing names and their positions
|
||||
background: HashMap<Position, String>,
|
||||
foreground: HashMap<Position, String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct IntermediateRoom {
|
||||
name: String,
|
||||
background: Vec<String>,
|
||||
foreground: Vec<String>,
|
||||
}
|
||||
|
||||
impl IntermediateRoom {
|
||||
fn from(room: Room) -> IntermediateRoom {
|
||||
fn hashmap_to_vec(hash: HashMap<Position, String>, width: u8, height: u8) -> Vec<String> {
|
||||
let mut thing_ids = Vec::new();
|
||||
|
||||
while thing_ids.len() < (width * height) as usize {
|
||||
thing_ids.push(String::new());
|
||||
}
|
||||
|
||||
thing_ids
|
||||
}
|
||||
|
||||
IntermediateRoom {
|
||||
name: "".to_string(),
|
||||
background: vec![],
|
||||
foreground: vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub enum DataType {
|
||||
// Image,
|
||||
// Integer,
|
||||
// Palette,
|
||||
// Room,
|
||||
// Script,
|
||||
// String,
|
||||
// Thing,
|
||||
// Variable,
|
||||
// }
|
||||
//
|
||||
// /// todo refactor, this is stupid
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct Value {
|
||||
// data_type: DataType,
|
||||
// image: Option<String>,
|
||||
// integer: Option<u64>,
|
||||
// palette: Option<String>,
|
||||
// room: Option<String>,
|
||||
// script: Option<String>,
|
||||
// string: Option<String>,
|
||||
// thing: Option<String>,
|
||||
// variable: Option<String>,
|
||||
// }
|
||||
//
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct Variable {
|
||||
// name: String,
|
||||
// data_type: DataType,
|
||||
// default: Value,
|
||||
// }
|
||||
//
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct Parameter {
|
||||
// name: String,
|
||||
// data_type: DataType,
|
||||
// default: Value,
|
||||
// }
|
||||
//
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct Script {
|
||||
// name: Option<String>,
|
||||
// params: Vec<Parameter>,
|
||||
// script: String,
|
||||
// }
|
||||
//
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct ScriptInstance {
|
||||
// script: String,
|
||||
// params: HashMap<String, Value>,
|
||||
// }
|
||||
//
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct ScriptCollection {
|
||||
// scripts: Vec<ScriptInstance>,
|
||||
// /// as well as many named scripts, a trigger can have one anonymous script
|
||||
// anonymous: Option<String>,
|
||||
// }
|
||||
//
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct Version {
|
||||
// major: u8,
|
||||
// minor: u8,
|
||||
// }
|
||||
//
|
||||
// impl Version {
|
||||
// pub fn default() -> Version {
|
||||
// Version { major: 0, minor: 1 }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
/// used in the window title bar
|
||||
name: Option<String>,
|
||||
width: u8,
|
||||
height: u8,
|
||||
/// animation rate in milliseconds
|
||||
tick: u64,
|
||||
/// if this is not specified, the game will pick the first room it finds
|
||||
starting_room: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Game {
|
||||
config: Config,
|
||||
// palettes: Vec<Palette>,
|
||||
// variables: Vec<Variable>,
|
||||
// triggers: HashMap<String, ScriptCollection>,
|
||||
}
|
||||
//
|
||||
// #[derive(Debug)]
|
||||
// pub struct GameParseError;
|
||||
//
|
||||
// impl Game {
|
||||
// pub fn from(s: &str) -> Result<Game, GameParseError> {
|
||||
// let result = toml::from_str(s);
|
||||
// if result.is_ok() {
|
||||
// Ok(result.unwrap())
|
||||
// } else {
|
||||
// Err(GameParseError)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
mod mock {
|
||||
pub(crate) mod image {
|
||||
use crate::Image;
|
||||
|
||||
pub fn bg() -> Image {
|
||||
Image {
|
||||
name: "bg".to_string(),
|
||||
pixels: vec![
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block() -> Image {
|
||||
Image {
|
||||
name: "block".to_string(),
|
||||
pixels: vec![
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,0,0,1,1,0,0,1,
|
||||
1,0,0,1,1,0,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn avatar() -> Image {
|
||||
Image {
|
||||
name: "avatar".to_string(),
|
||||
pixels: vec![
|
||||
0,0,0,2,2,0,0,0,
|
||||
0,0,0,2,2,0,0,0,
|
||||
0,0,0,2,2,0,0,0,
|
||||
0,0,2,2,2,2,0,0,
|
||||
0,2,2,2,2,2,2,0,
|
||||
2,0,2,2,2,2,0,2,
|
||||
0,0,2,0,0,2,0,0,
|
||||
0,0,2,0,0,2,0,0,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cat() -> Image {
|
||||
Image {
|
||||
name: "cat".to_string(),
|
||||
pixels: vec![
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,2,0,2,0,0,0,2,
|
||||
0,2,2,2,0,0,0,2,
|
||||
0,2,2,2,0,0,2,0,
|
||||
0,2,2,2,2,2,0,0,
|
||||
0,0,2,2,2,2,0,0,
|
||||
0,0,2,0,0,2,0,0,
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod palette {
|
||||
use crate::{Palette, Colour, IntermediatePalette};
|
||||
|
||||
pub(crate) fn intermediate() -> IntermediatePalette {
|
||||
IntermediatePalette {
|
||||
colours: vec![
|
||||
vec![0,0,0,0],
|
||||
vec![0,81,104,255],
|
||||
vec![118,159,155,255],
|
||||
vec![155,155,155,255],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default() -> Palette {
|
||||
Palette {
|
||||
name: "blueprint".to_string(),
|
||||
colours: vec![
|
||||
Colour { red: 0, green: 0, blue: 0, alpha: 0 },
|
||||
Colour { red: 0, green: 81, blue: 104, alpha: 255 },
|
||||
Colour { red: 118, green: 159, blue: 155, alpha: 255 },
|
||||
Colour { red: 155, green: 155, blue: 155, alpha: 255 },
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{Game, Config, Palette, Colour, Image, IntermediatePalettes, IntermediateImage, IntermediateImages};
|
||||
|
||||
#[test]
|
||||
fn test_config_from_toml() {
|
||||
let output: Config = toml::from_str(include_str!("test-resources/basic/game.toml")).unwrap();
|
||||
let expected = Config {
|
||||
name: Some("Write your game's title here".to_string()),
|
||||
width: 16,
|
||||
height: 9,
|
||||
tick: 400,
|
||||
starting_room: Some("example room".to_string())
|
||||
};
|
||||
assert_eq!(output, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_to_toml() {
|
||||
let output = toml::to_string(&Config {
|
||||
name: Some("Write your game's title here".to_string()),
|
||||
width: 16,
|
||||
height: 9,
|
||||
tick: 400,
|
||||
starting_room: Some("example room".to_string())
|
||||
}).unwrap();
|
||||
let expected = include_str!("test-resources/basic/game.toml");
|
||||
assert_eq!(&output, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_palette_from_toml() {
|
||||
let output = Palette::from(
|
||||
"blueprint",
|
||||
include_str!("test-resources/basic/palettes/blueprint.toml")
|
||||
);
|
||||
let expected = crate::mock::palette::default();
|
||||
assert_eq!(output, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_palette_to_toml() {
|
||||
let intermediate = crate::mock::palette::intermediate();
|
||||
let output = toml::to_string(&intermediate).unwrap();
|
||||
let expected = include_str!("test-resources/basic/palettes/blueprint.toml");
|
||||
assert_eq!(&output, expected);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_image_from_toml() {
|
||||
// let str = include_str!("test-resources/basic/images.toml");
|
||||
// let output: Image = toml::from_str(str).unwrap();
|
||||
// let expected = crate::mock::image::avatar();
|
||||
// assert_eq!(output, expected);
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_colour_from_intermediate() {
|
||||
let output = Colour::from(vec![64, 128, 192, 255]);
|
||||
let expected = Colour { red: 64, green: 128, blue: 192, alpha: 255 };
|
||||
assert_eq!(output, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_colour_to_intermediate() {
|
||||
let output = Colour { red: 64, green: 128, blue: 192, alpha: 255 }.to_vec();
|
||||
let expected = vec![64, 128, 192, 255];
|
||||
assert_eq!(output, expected);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_images_from_intermediate() {
|
||||
// let str = include_str!("test-resources/basic/images.toml");
|
||||
// let output: Vec<IntermediateImage> = toml::from_str(str).unwrap();
|
||||
// print!("{}", output.len());
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_images_to_toml() {
|
||||
// let images = IntermediateImages {
|
||||
// image: vec![
|
||||
// IntermediateImage::from(crate::mock::image::bg()),
|
||||
// IntermediateImage::from(crate::mock::image::block()),
|
||||
// IntermediateImage::from(crate::mock::image::avatar()),
|
||||
// IntermediateImage::from(crate::mock::image::cat()),
|
||||
// ]
|
||||
// };
|
||||
//
|
||||
// let output = toml::to_string(&images).unwrap();
|
||||
// let expected = include_str!("test-resources/basic/images.toml");
|
||||
//
|
||||
// // I think this is failing because one has escaped quotation marks and one has normal ones(??)
|
||||
// assert_eq!(output, expected);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_images_from_toml() {
|
||||
// let str = include_str!("test-resources/basic/images.toml");
|
||||
// let output: IntermediateImages = toml::from_str(str).unwrap();
|
||||
// let output = output.to_images();
|
||||
// let expected = vec![
|
||||
// crate::mock::image::bg(),
|
||||
// crate::mock::image::block(),
|
||||
// crate::mock::image::avatar(),
|
||||
// crate::mock::image::cat(),
|
||||
// ];
|
||||
// assert_eq!(output, expected);
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
[image]
|
||||
name = "bg"
|
||||
pixels = [
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
]
|
||||
|
||||
[image]
|
||||
name = "block"
|
||||
pixels = [
|
||||
2,2,2,2,2,2,2,2,
|
||||
2,1,1,1,1,1,1,2,
|
||||
2,1,1,1,1,1,1,2,
|
||||
2,1,1,2,2,1,1,2,
|
||||
2,1,1,2,2,1,1,2,
|
||||
2,1,1,1,1,1,1,2,
|
||||
2,1,1,1,1,1,1,2,
|
||||
2,2,2,2,2,2,2,2,
|
||||
]
|
||||
|
||||
[image]
|
||||
name = "avatar"
|
||||
pixels = [
|
||||
0,0,0,3,3,0,0,0,
|
||||
0,0,0,3,3,0,0,0,
|
||||
0,0,0,3,3,0,0,0,
|
||||
0,0,3,3,3,3,0,0,
|
||||
0,3,3,3,3,3,3,0,
|
||||
3,0,3,3,3,3,0,3,
|
||||
0,0,3,0,0,3,0,0,
|
||||
0,0,3,0,0,3,0,0,
|
||||
]
|
||||
|
||||
[image]
|
||||
name = "cat"
|
||||
pixels = [
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,3,0,3,0,0,0,3,
|
||||
0,3,3,3,0,0,0,3,
|
||||
0,3,3,3,0,0,3,0,
|
||||
0,3,3,3,3,3,0,0,
|
||||
0,0,3,3,3,3,0,0,
|
||||
0,0,3,0,0,3,0,0,
|
||||
]
|
||||
|
||||
[thing]
|
||||
name = "avatar"
|
||||
image = "avatar"
|
||||
input = ["movement-wasd", "movement-arrow-keys"]
|
||||
|
||||
[thing]
|
||||
name = "cat"
|
||||
image = "cat"
|
||||
bumped = """
|
||||
say "I'm a cat"
|
||||
"""
|
||||
|
||||
[variable]
|
||||
name = "a"
|
||||
type = "int"
|
||||
default = 42
|
|
@ -0,0 +1,5 @@
|
|||
name = "Write your game's title here"
|
||||
width = 16
|
||||
height = 9
|
||||
tick = 400
|
||||
starting_room = "example room"
|
|
@ -0,0 +1,10 @@
|
|||
pixels = """
|
||||
00022000
|
||||
00022000
|
||||
00022000
|
||||
00222200
|
||||
02222220
|
||||
20222202
|
||||
00200200
|
||||
00200200
|
||||
"""
|
|
@ -0,0 +1,10 @@
|
|||
pixels = """
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
"""
|
|
@ -0,0 +1,10 @@
|
|||
pixels = """
|
||||
11111111
|
||||
10000001
|
||||
10000001
|
||||
10011001
|
||||
10011001
|
||||
10000001
|
||||
10000001
|
||||
11111111
|
||||
"""
|
|
@ -0,0 +1,10 @@
|
|||
pixels = """
|
||||
00000000
|
||||
00000000
|
||||
02020002
|
||||
02220002
|
||||
02220020
|
||||
02222200
|
||||
00222200
|
||||
00200200
|
||||
"""
|
|
@ -0,0 +1 @@
|
|||
colours = [[0, 0, 0, 0], [0, 81, 104, 255], [118, 159, 155, 255], [155, 155, 155, 255]]
|
|
@ -0,0 +1,37 @@
|
|||
background = [
|
||||
"bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg",
|
||||
"bg","block","block","block","block","block","block","block","block","block","block","block","block","block","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","block","bg",
|
||||
"bg","block","block","block","block","block","block","block","block","block","block","block","block","block","block","bg",
|
||||
"bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg","bg",
|
||||
]
|
||||
foreground = [
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","avatar","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","cat","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
"","","","","","","","","","","","","","","","",
|
||||
]
|
||||
palette = "blueprint"
|
Loading…
Reference in New Issue