mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-16 11:41:50 +00:00
Rewrite color creation model
This commit is contained in:
parent
e3f05aae45
commit
ef43022f19
@ -1,3 +1,5 @@
|
|||||||
|
import { customColors } from "./custom/colors";
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
export const enumColors = {
|
export const enumColors = {
|
||||||
red: "red",
|
red: "red",
|
||||||
@ -5,7 +7,7 @@ export const enumColors = {
|
|||||||
blue: "blue",
|
blue: "blue",
|
||||||
|
|
||||||
yellow: "yellow",
|
yellow: "yellow",
|
||||||
purple: "purple",
|
magenta: "magenta",
|
||||||
cyan: "cyan",
|
cyan: "cyan",
|
||||||
|
|
||||||
white: "white",
|
white: "white",
|
||||||
@ -19,7 +21,7 @@ export const enumColorToShortcode = {
|
|||||||
[enumColors.blue]: "b",
|
[enumColors.blue]: "b",
|
||||||
|
|
||||||
[enumColors.yellow]: "y",
|
[enumColors.yellow]: "y",
|
||||||
[enumColors.purple]: "p",
|
[enumColors.magenta]: "p",
|
||||||
[enumColors.cyan]: "c",
|
[enumColors.cyan]: "c",
|
||||||
|
|
||||||
[enumColors.white]: "w",
|
[enumColors.white]: "w",
|
||||||
@ -28,140 +30,234 @@ export const enumColorToShortcode = {
|
|||||||
|
|
||||||
/** @enum {enumColors} */
|
/** @enum {enumColors} */
|
||||||
export const enumShortcodeToColor = {};
|
export const enumShortcodeToColor = {};
|
||||||
for (const key in enumColorToShortcode) {
|
|
||||||
enumShortcodeToColor[enumColorToShortcode[key]] = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
export const enumColorsToHexCode = {
|
export const enumColorsToHexCode = {};
|
||||||
[enumColors.red]: "#ff666a",
|
|
||||||
[enumColors.green]: "#78ff66",
|
|
||||||
[enumColors.blue]: "#66a7ff",
|
|
||||||
|
|
||||||
// red + green
|
|
||||||
[enumColors.yellow]: "#fcf52a",
|
|
||||||
|
|
||||||
// red + blue
|
|
||||||
[enumColors.purple]: "#dd66ff",
|
|
||||||
|
|
||||||
// blue + green
|
|
||||||
[enumColors.cyan]: "#00fcff",
|
|
||||||
|
|
||||||
// blue + green + red
|
|
||||||
[enumColors.white]: "#ffffff",
|
|
||||||
|
|
||||||
[enumColors.uncolored]: "#aaaaaa",
|
|
||||||
};
|
|
||||||
|
|
||||||
const c = enumColors;
|
const c = enumColors;
|
||||||
/** @enum {Object.<string, string>} */
|
/** @enum {Object.<string, Object>} */
|
||||||
export const enumColorMixingResults = {
|
export const enumColorMixingResults = {};
|
||||||
// 255, 0, 0
|
|
||||||
[c.red]: {
|
|
||||||
[c.green]: c.yellow,
|
|
||||||
[c.blue]: c.purple,
|
|
||||||
|
|
||||||
[c.yellow]: c.yellow,
|
/**
|
||||||
[c.purple]: c.purple,
|
* @typedef {Object} ColorData
|
||||||
[c.cyan]: c.white,
|
* @property {string} id
|
||||||
|
* @property {string} code
|
||||||
|
* @property {string} hex
|
||||||
|
* @property {string[][] | string[]} [mixingFrom]
|
||||||
|
* @property {Object.<string, string>} [mixing]
|
||||||
|
* @property {boolean} [spawnable]
|
||||||
|
* @property {number} [minDistance]
|
||||||
|
*/
|
||||||
|
|
||||||
[c.white]: c.white,
|
/** @enum {ColorData} */
|
||||||
|
export const allColorData = {
|
||||||
|
uncolored: {
|
||||||
|
id: "uncolored",
|
||||||
|
code: "u",
|
||||||
|
hex: "#aaaaaa",
|
||||||
|
mixing: {
|
||||||
|
any: "any",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
red: {
|
||||||
// 0, 255, 0
|
id: "red",
|
||||||
[c.green]: {
|
code: "r",
|
||||||
[c.blue]: c.cyan,
|
hex: "#ff666a",
|
||||||
|
// no recipes
|
||||||
[c.yellow]: c.yellow,
|
spawnable: true,
|
||||||
[c.purple]: c.white,
|
|
||||||
[c.cyan]: c.cyan,
|
|
||||||
|
|
||||||
[c.white]: c.white,
|
|
||||||
},
|
},
|
||||||
|
green: {
|
||||||
// 0, 255, 0
|
id: "green",
|
||||||
[c.blue]: {
|
code: "g",
|
||||||
[c.yellow]: c.white,
|
hex: "#78ff66",
|
||||||
[c.purple]: c.purple,
|
// no recipes
|
||||||
[c.cyan]: c.cyan,
|
spawnable: true,
|
||||||
|
|
||||||
[c.white]: c.white,
|
|
||||||
},
|
},
|
||||||
|
blue: {
|
||||||
// 255, 255, 0
|
id: "blue",
|
||||||
[c.yellow]: {
|
code: "b",
|
||||||
[c.purple]: c.white,
|
hex: "#66a7ff",
|
||||||
[c.cyan]: c.white,
|
// no recipes
|
||||||
|
spawnable: true,
|
||||||
|
minDistance: 3,
|
||||||
},
|
},
|
||||||
|
cyan: {
|
||||||
// 255, 0, 255
|
id: "cyan",
|
||||||
[c.purple]: {
|
code: "c",
|
||||||
[c.cyan]: c.white,
|
hex: "#00fcff",
|
||||||
|
mixingFrom: ["green", "blue"],
|
||||||
|
mixing: {
|
||||||
|
green: "this",
|
||||||
|
blue: "this",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
magenta: {
|
||||||
// 0, 255, 255
|
id: "magenta",
|
||||||
[c.cyan]: {},
|
code: "p",
|
||||||
|
hex: "#dd66ff",
|
||||||
//// SPECIAL COLORS
|
mixingFrom: ["red", "blue"],
|
||||||
|
mixing: {
|
||||||
// 255, 255, 255
|
red: "this",
|
||||||
[c.white]: {
|
blue: "this",
|
||||||
// auto
|
},
|
||||||
},
|
},
|
||||||
|
yellow: {
|
||||||
// X, X, X
|
id: "yellow",
|
||||||
[c.uncolored]: {
|
code: "y",
|
||||||
// auto
|
hex: "#fcf52a",
|
||||||
|
mixingFrom: ["red", "green"],
|
||||||
|
mixing: {
|
||||||
|
red: "this",
|
||||||
|
green: "this",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
white: {
|
||||||
|
id: "white",
|
||||||
|
code: "w",
|
||||||
|
hex: "#ffffff",
|
||||||
|
mixing: {
|
||||||
|
any: "white",
|
||||||
|
},
|
||||||
|
mixingFrom: [
|
||||||
|
["red", "cyan"],
|
||||||
|
["green", "magenta"],
|
||||||
|
["blue", "yellow"],
|
||||||
|
["cyan", "magenta"],
|
||||||
|
["cyan", "yellow"],
|
||||||
|
["magenta", "yellow"],
|
||||||
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create same color lookups
|
/**
|
||||||
for (const color in enumColors) {
|
* @param {Object} colorData
|
||||||
enumColorMixingResults[color][color] = color;
|
* @property {string} colorData.id
|
||||||
|
* @property {string} colorData.code
|
||||||
// Anything with white is white again
|
* @property {string} colorData.hex
|
||||||
enumColorMixingResults[color][c.white] = c.white;
|
* @property {Object.<string, string>} [colorData.mixing]
|
||||||
|
* @property {string[2][] | string[2]} [colorData.mixingFrom]
|
||||||
// Anything with uncolored is the same color
|
*/
|
||||||
enumColorMixingResults[color][c.uncolored] = color;
|
function registerColor(colorData) {
|
||||||
|
allColorData[colorData.id] = colorData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create reverse lookup and check color mixing lookups
|
export let allowColorMixingMismatch = false;
|
||||||
for (const colorA in enumColorMixingResults) {
|
export let allowColorMixingOverride = false;
|
||||||
for (const colorB in enumColorMixingResults[colorA]) {
|
export let allowColorMixingMissingSource = false;
|
||||||
const resultColor = enumColorMixingResults[colorA][colorB];
|
export let allowColorMixingMissingTarget = false;
|
||||||
if (!enumColorMixingResults[colorB]) {
|
|
||||||
enumColorMixingResults[colorB] = {
|
for (let data of customColors) {
|
||||||
[colorA]: resultColor,
|
registerColor(data);
|
||||||
};
|
}
|
||||||
} else {
|
|
||||||
const existingResult = enumColorMixingResults[colorB][colorA];
|
const mix = enumColorMixingResults;
|
||||||
if (existingResult && existingResult !== resultColor) {
|
|
||||||
assertAlways(
|
initColors();
|
||||||
false,
|
|
||||||
"invalid color mixing configuration, " +
|
export function initColors() {
|
||||||
colorA +
|
|
||||||
" + " +
|
for (let c1 in allColorData) {
|
||||||
colorB +
|
let data = allColorData[c1];
|
||||||
" is " +
|
assert(data);
|
||||||
resultColor +
|
assert(data.id == c1);
|
||||||
" but " +
|
assert(data.code.toLowerCase() == data.code);
|
||||||
colorB +
|
if (data.disabled) {
|
||||||
" + " +
|
continue;
|
||||||
colorA +
|
}
|
||||||
" is " +
|
if (data.spawnable && !data.minDistance) {
|
||||||
existingResult
|
data.minDistance = 0;
|
||||||
);
|
}
|
||||||
|
enumColors[c1] = c1;
|
||||||
|
enumColorToShortcode[c1] = data.code;
|
||||||
|
enumShortcodeToColor[data.code] = c1;
|
||||||
|
enumColorsToHexCode[c1] = data.hex;
|
||||||
|
if (!mix[c1]) {
|
||||||
|
mix[c1] = {};
|
||||||
|
}
|
||||||
|
let mixing = mix[c1];
|
||||||
|
if (data.mixing) {
|
||||||
|
for (let c2 in data.mixing) {
|
||||||
|
if (c2 == "any") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let result = data.mixing[c2] == "this" ? c1 : data.mixing[c2] == "any" ? c2 : data.mixing[c2];
|
||||||
|
if (mixing[c2] && mixing[c2] != result) {
|
||||||
|
if (!allowColorMixingOverride) {
|
||||||
|
assertAlways(
|
||||||
|
false,
|
||||||
|
`Color mixing recipe overrides are not implemented (${c1}+${c2}=${mixing[c2]}->${result})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mixing[c2] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let id in allColorData) {
|
||||||
|
let data = allColorData[id];
|
||||||
|
let mixingFrom = !data.mixingFrom
|
||||||
|
? []
|
||||||
|
: data.mixingFrom[0] instanceof Array
|
||||||
|
? data.mixingFrom
|
||||||
|
: [data.mixingFrom];
|
||||||
|
for (let [c1, c2] of mixingFrom) {
|
||||||
|
if (!c[c1] || !c[c2]) {
|
||||||
|
if (!allowColorMixingMissingSource) {
|
||||||
|
assertAlways(false, `Color mixing recipe source is not known (${c1}+${c2}=${id})`);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mix[c1][c2] && mix[c1][c2] != id) {
|
||||||
|
// TODO
|
||||||
|
throw "wut";
|
||||||
|
}
|
||||||
|
if (mix[c2][c1] && mix[c2][c1] != id) {
|
||||||
|
// TODO
|
||||||
|
throw "wut";
|
||||||
|
}
|
||||||
|
mix[c1][c2] = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let c1 in c) {
|
||||||
|
for (let c2 in c) {
|
||||||
|
if (mix[c1][c2] != mix[c2][c1]) {
|
||||||
|
if (mix[c1][c2] && mix[c2][c1] && !allowColorMixingMismatch) {
|
||||||
|
assertAlways(
|
||||||
|
false,
|
||||||
|
`Color mixing recipe result mismatch (${c1}+${c2}=${mix[c1][c2]}/${mix[c2][c1]}}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
mix[c1][c2] = mix[c2][c1] = mix[c1][c2] || mix[c2][c1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let c1 in c) {
|
||||||
|
if (!mix[c1][c1]) {
|
||||||
|
mix[c1][c1] = c1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let anyPairs = {};
|
||||||
|
for (let c1 in c) {
|
||||||
|
let mixing = allColorData[c1].mixing;
|
||||||
|
if (!mixing || !mixing.any) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (let c2 in c) {
|
||||||
|
if (mix[c1][c2] || mix[c2][c1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (anyPairs[`${c1}+${c2}`]) {
|
||||||
|
throw "wut";
|
||||||
|
}
|
||||||
|
anyPairs[`${c1}+${c2}`] = anyPairs[`${c2}+${c1}`] = true;
|
||||||
|
mix[c1][c2] = mix[c2][c1] = mixing.any == "any" ? c2 : mixing.any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let c1 in c) {
|
||||||
|
for (let c2 in c) {
|
||||||
|
if (!mix[c1][c2]) {
|
||||||
|
assertAlways(false, "Color mixing of", c1, "with", c2, "is not defined");
|
||||||
}
|
}
|
||||||
enumColorMixingResults[colorB][colorA] = resultColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const colorA in enumColorMixingResults) {
|
|
||||||
for (const colorB in enumColorMixingResults) {
|
|
||||||
if (!enumColorMixingResults[colorA][colorB]) {
|
|
||||||
assertAlways(false, "Color mixing of", colorA, "with", colorB, "is not defined");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/js/game/custom/colors.js
Normal file
29
src/js/game/custom/colors.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/** @enum {string} */
|
||||||
|
export const customColors = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} colorData
|
||||||
|
* @param {string} colorData.id
|
||||||
|
* @param {string} colorData.code
|
||||||
|
* @param {string} colorData.hex
|
||||||
|
* @param {string[][] | string[]} [colorData.mixingFrom]
|
||||||
|
* @param {Object.<string, string>} [colorData.mixing]
|
||||||
|
* @param {boolean} [colorData.spawnable]
|
||||||
|
* @param {number} [colorData.minDistance]
|
||||||
|
*/
|
||||||
|
export function registerCustomColor(colorData) {
|
||||||
|
customColors.push(colorData);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerCustomColor({
|
||||||
|
id: "black",
|
||||||
|
code: "k",
|
||||||
|
hex: "#333333",
|
||||||
|
mixing: {
|
||||||
|
white: "uncolored",
|
||||||
|
uncolored: "uncolored",
|
||||||
|
any: "black",
|
||||||
|
},
|
||||||
|
spawnable: true,
|
||||||
|
minDistance: 5,
|
||||||
|
});
|
||||||
@ -33,7 +33,7 @@ export class ColorItem extends BaseItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getBackgroundColorAsResource() {
|
getBackgroundColorAsResource() {
|
||||||
return THEME.map.resources[this.color];
|
return THEME.map.resources[this.color] || THEME.map.resources.shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { createLogger } from "../core/logging";
|
|||||||
import { clamp, fastArrayDeleteValueIfContained, make2DUndefinedArray } from "../core/utils";
|
import { clamp, fastArrayDeleteValueIfContained, make2DUndefinedArray } from "../core/utils";
|
||||||
import { Vector } from "../core/vector";
|
import { Vector } from "../core/vector";
|
||||||
import { BaseItem } from "./base_item";
|
import { BaseItem } from "./base_item";
|
||||||
import { enumColors } from "./colors";
|
import { enumColors, allColorData } from "./colors";
|
||||||
import { Entity } from "./entity";
|
import { Entity } from "./entity";
|
||||||
import { ColorItem } from "./items/color_item";
|
import { ColorItem } from "./items/color_item";
|
||||||
import { ShapeItem } from "./items/shape_item";
|
import { ShapeItem } from "./items/shape_item";
|
||||||
@ -136,9 +136,16 @@ export class MapChunk {
|
|||||||
*/
|
*/
|
||||||
internalGenerateColorPatch(rng, colorPatchSize, distanceToOriginInChunks) {
|
internalGenerateColorPatch(rng, colorPatchSize, distanceToOriginInChunks) {
|
||||||
// First, determine available colors
|
// First, determine available colors
|
||||||
let availableColors = [enumColors.red, enumColors.green];
|
let availableColors = [];
|
||||||
if (distanceToOriginInChunks > 2) {
|
for (let c in enumColors) {
|
||||||
availableColors.push(enumColors.blue);
|
c = enumColors[c];
|
||||||
|
if (
|
||||||
|
allColorData[c] &&
|
||||||
|
allColorData[c].spawnable &&
|
||||||
|
allColorData[c].minDistance <= distanceToOriginInChunks
|
||||||
|
) {
|
||||||
|
availableColors.push(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.internalGeneratePatch(rng, colorPatchSize, new ColorItem(rng.choice(availableColors)));
|
this.internalGeneratePatch(rng, colorPatchSize, new ColorItem(rng.choice(availableColors)));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user