mirror of
https://github.com/thepaperpilot/Planar-Pioneers.git
synced 2024-11-22 00:21:31 +00:00
Implement creating planes
This commit is contained in:
parent
5dcba9fe3a
commit
1e3f065427
4 changed files with 493 additions and 9 deletions
41
src/data/planes.tsx
Normal file
41
src/data/planes.tsx
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { jsx } from "features/feature";
|
||||||
|
import MainDisplayVue from "features/resources/MainDisplay.vue";
|
||||||
|
import { createResource } from "features/resources/resource";
|
||||||
|
import { BaseLayer, createLayer } from "game/layers";
|
||||||
|
import { persistent } from "game/persistence";
|
||||||
|
import { DecimalSource } from "util/bignum";
|
||||||
|
import { Resources } from "./projEntry";
|
||||||
|
import { getColor, getName, sfc32 } from "./utils";
|
||||||
|
|
||||||
|
export function createPlane(id: string, tier: Resources, seed: number) {
|
||||||
|
return createLayer(id, function (this: BaseLayer) {
|
||||||
|
const random = sfc32(0, seed >> 0, seed >> 32, 1);
|
||||||
|
for (let i = 0; i < 12; i++) random();
|
||||||
|
|
||||||
|
const name = getName(random);
|
||||||
|
const color = getColor([0.64, 0.75, 0.55], random);
|
||||||
|
const background = getColor([0.18, 0.2, 0.25], random);
|
||||||
|
const resource = createResource<DecimalSource>(0, getName(random));
|
||||||
|
|
||||||
|
return {
|
||||||
|
tier: persistent(tier),
|
||||||
|
seed: persistent(seed),
|
||||||
|
name,
|
||||||
|
color,
|
||||||
|
resource,
|
||||||
|
background,
|
||||||
|
style: {
|
||||||
|
background,
|
||||||
|
"--background": background
|
||||||
|
},
|
||||||
|
display: jsx(() => (
|
||||||
|
<>
|
||||||
|
<h1>{name}</h1>
|
||||||
|
<MainDisplayVue resource={resource} color={color} />
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GenericPlane = ReturnType<typeof createPlane>;
|
|
@ -14,16 +14,16 @@ import { jsx } from "features/feature";
|
||||||
import { createResource } from "features/resources/resource";
|
import { createResource } from "features/resources/resource";
|
||||||
import { createTabFamily } from "features/tabs/tabFamily";
|
import { createTabFamily } from "features/tabs/tabFamily";
|
||||||
import Formula, { calculateCost } from "game/formulas/formulas";
|
import Formula, { calculateCost } from "game/formulas/formulas";
|
||||||
import type { BaseLayer, GenericLayer } from "game/layers";
|
import { GenericFormula, InvertibleIntegralFormula } from "game/formulas/types";
|
||||||
import { createLayer } from "game/layers";
|
import { BaseLayer, GenericLayer, addLayer, createLayer, layers } from "game/layers";
|
||||||
import {
|
import {
|
||||||
Modifier,
|
Modifier,
|
||||||
createAdditiveModifier,
|
createAdditiveModifier,
|
||||||
createMultiplicativeModifier,
|
createMultiplicativeModifier,
|
||||||
createSequentialModifier
|
createSequentialModifier
|
||||||
} from "game/modifiers";
|
} from "game/modifiers";
|
||||||
import { State, persistent } from "game/persistence";
|
import { State } from "game/persistence";
|
||||||
import type { Player } from "game/player";
|
import type { LayerData, Player } from "game/player";
|
||||||
import player from "game/player";
|
import player from "game/player";
|
||||||
import settings from "game/settings";
|
import settings from "game/settings";
|
||||||
import Decimal, { DecimalSource } from "lib/break_eternity";
|
import Decimal, { DecimalSource } from "lib/break_eternity";
|
||||||
|
@ -34,7 +34,7 @@ import { ComputedRef, computed, nextTick, reactive, ref, watch } from "vue";
|
||||||
import { useToast } from "vue-toastification";
|
import { useToast } from "vue-toastification";
|
||||||
import { Section, createCollapsibleModifierSections, createFormulaPreview } from "./common";
|
import { Section, createCollapsibleModifierSections, createFormulaPreview } from "./common";
|
||||||
import "./main.css";
|
import "./main.css";
|
||||||
import { GenericFormula, InvertibleIntegralFormula } from "game/formulas/types";
|
import { GenericPlane, createPlane } from "./planes";
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
@ -64,6 +64,16 @@ export interface EmpowererState {
|
||||||
powered: boolean;
|
powered: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PortalGeneratorState {
|
||||||
|
tier: Resources | undefined;
|
||||||
|
influences: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PortalState {
|
||||||
|
id: string;
|
||||||
|
powered: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const mineLootTable = {
|
const mineLootTable = {
|
||||||
dirt: 120,
|
dirt: 120,
|
||||||
sand: 60,
|
sand: 60,
|
||||||
|
@ -132,7 +142,8 @@ const tools = {
|
||||||
iron: {
|
iron: {
|
||||||
cost: 1e10,
|
cost: 1e10,
|
||||||
name: "Portal Generator",
|
name: "Portal Generator",
|
||||||
type: "portalGenerator"
|
type: "portalGenerator",
|
||||||
|
state: { tier: null, influences: [] }
|
||||||
},
|
},
|
||||||
silver: {
|
silver: {
|
||||||
cost: 1e12,
|
cost: 1e12,
|
||||||
|
@ -227,7 +238,8 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
}, {} as Record<Resources, BoardNode>),
|
}, {} as Record<Resources, BoardNode>),
|
||||||
sand: board.types.dowsing.nodes.value[0],
|
sand: board.types.dowsing.nodes.value[0],
|
||||||
wood: board.types.quarry.nodes.value[0],
|
wood: board.types.quarry.nodes.value[0],
|
||||||
coal: board.types.empowerer.nodes.value[0]
|
coal: board.types.empowerer.nodes.value[0],
|
||||||
|
iron: board.types.portalGenerator.nodes.value[0]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const resourceLevels = computed(() =>
|
const resourceLevels = computed(() =>
|
||||||
|
@ -854,6 +866,156 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
running: isPowered(node)
|
running: isPowered(node)
|
||||||
}),
|
}),
|
||||||
draggable: true
|
draggable: true
|
||||||
|
},
|
||||||
|
portalGenerator: {
|
||||||
|
shape: Shape.Diamond,
|
||||||
|
size: 50,
|
||||||
|
title: "⛩️",
|
||||||
|
label: node => {
|
||||||
|
if (node === board.selectedNode.value) {
|
||||||
|
return {
|
||||||
|
text:
|
||||||
|
(node.state as unknown as PortalGeneratorState).tier == null
|
||||||
|
? "Portal Spawner - Drag a resource to me!"
|
||||||
|
: `Spawning ${
|
||||||
|
(node.state as unknown as PortalGeneratorState).tier
|
||||||
|
}-tier portal`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if ((board as GenericBoard).draggingNode.value?.type === "resource") {
|
||||||
|
const resource = (
|
||||||
|
(board as GenericBoard).draggingNode.value
|
||||||
|
?.state as unknown as ResourceState
|
||||||
|
).type;
|
||||||
|
const text =
|
||||||
|
(node.state as unknown as PortalGeneratorState).tier === resource
|
||||||
|
? "Disconnect"
|
||||||
|
: `${camelToTitle(resource)}-tier Portal`;
|
||||||
|
return {
|
||||||
|
text,
|
||||||
|
color: "var(--accent2)"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// TODO handle influences
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
actionDistance: Math.PI / 4,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
id: "deselect",
|
||||||
|
icon: "close",
|
||||||
|
tooltip: { text: "Disconnect all" },
|
||||||
|
onClick(node: BoardNode) {
|
||||||
|
node.state = {
|
||||||
|
...(node.state as object),
|
||||||
|
tier: undefined,
|
||||||
|
influences: []
|
||||||
|
};
|
||||||
|
board.selectedAction.value = null;
|
||||||
|
board.selectedNode.value = null;
|
||||||
|
},
|
||||||
|
visibility: (node: BoardNode) => {
|
||||||
|
const { tier, influences } =
|
||||||
|
node.state as unknown as PortalGeneratorState;
|
||||||
|
return tier != null || influences.length > 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "makePortal",
|
||||||
|
icon: "done",
|
||||||
|
tooltip: node => ({
|
||||||
|
text: `Spawn ${
|
||||||
|
(node.state as unknown as PortalGeneratorState).tier
|
||||||
|
}-tier portal`
|
||||||
|
}),
|
||||||
|
onClick(node) {
|
||||||
|
let id = 0;
|
||||||
|
while (`portal-${id}` in layers) {
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
addLayer(
|
||||||
|
createPlane(
|
||||||
|
`portal-${id}`,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
(node.state as unknown as PortalGeneratorState).tier!,
|
||||||
|
Math.floor(Math.random() * 4294967296)
|
||||||
|
),
|
||||||
|
player
|
||||||
|
);
|
||||||
|
const newNode = {
|
||||||
|
id: getUniqueNodeID(board as GenericBoard),
|
||||||
|
position: { ...node.position },
|
||||||
|
type: "portal",
|
||||||
|
state: { id: `portal-${id}`, powered: false }
|
||||||
|
};
|
||||||
|
board.placeInAvailableSpace(newNode);
|
||||||
|
board.nodes.value.push(newNode);
|
||||||
|
board.selectedAction.value = null;
|
||||||
|
board.selectedNode.value = null;
|
||||||
|
node.state = { tier: undefined, influences: [] };
|
||||||
|
},
|
||||||
|
visibility: node =>
|
||||||
|
(node.state as unknown as PortalGeneratorState).tier != null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
canAccept(node, otherNode) {
|
||||||
|
return otherNode.type === "resource" || otherNode.type === "influence";
|
||||||
|
},
|
||||||
|
onDrop(node, otherNode) {
|
||||||
|
if (otherNode.type === "resource") {
|
||||||
|
const droppedType = (otherNode.state as unknown as ResourceState).type;
|
||||||
|
const currentType = (node.state as unknown as PortalGeneratorState).tier;
|
||||||
|
node.state = {
|
||||||
|
...(node.state as object),
|
||||||
|
tier: droppedType === currentType ? undefined : droppedType
|
||||||
|
};
|
||||||
|
} else if (otherNode.type === "influence") {
|
||||||
|
const droppedInfluence = otherNode.state as string;
|
||||||
|
const currentInfluences = (node.state as unknown as PortalGeneratorState)
|
||||||
|
.influences;
|
||||||
|
if (currentInfluences.includes(droppedInfluence)) {
|
||||||
|
node.state = {
|
||||||
|
...(node.state as object),
|
||||||
|
influences: currentInfluences.filter(i => i !== droppedInfluence)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
node.state = {
|
||||||
|
...(node.state as object),
|
||||||
|
influences: [...currentInfluences, droppedInfluence]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
board.selectedNode.value = node;
|
||||||
|
},
|
||||||
|
draggable: true
|
||||||
|
},
|
||||||
|
portal: {
|
||||||
|
shape: Shape.Diamond,
|
||||||
|
size: 50,
|
||||||
|
title: "🌀",
|
||||||
|
label: node =>
|
||||||
|
node === board.selectedNode.value
|
||||||
|
? {
|
||||||
|
text: `Portal to ${
|
||||||
|
(
|
||||||
|
layers[
|
||||||
|
(node.state as unknown as PortalState).id
|
||||||
|
] as GenericPlane
|
||||||
|
).name
|
||||||
|
}`,
|
||||||
|
color: (
|
||||||
|
layers[(node.state as unknown as PortalState).id] as GenericPlane
|
||||||
|
).color
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
actionDistance: Math.PI / 4,
|
||||||
|
actions: [togglePoweredAction],
|
||||||
|
classes: node => ({
|
||||||
|
running: isPowered(node)
|
||||||
|
}),
|
||||||
|
outlineColor: node =>
|
||||||
|
(layers[(node.state as unknown as PortalState).id] as GenericPlane).background,
|
||||||
|
draggable: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
|
@ -929,6 +1091,23 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (portalGenerator.value != null) {
|
||||||
|
if ((portalGenerator.value.state as unknown as PortalGeneratorState).tier != null) {
|
||||||
|
links.push({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
startNode: portalGenerator.value!,
|
||||||
|
endNode:
|
||||||
|
resourceNodes.value[
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
(portalGenerator.value.state as unknown as PortalGeneratorState)
|
||||||
|
.tier!
|
||||||
|
],
|
||||||
|
stroke: "var(--foreground)",
|
||||||
|
strokeWidth: 4
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// TODO link to influences
|
||||||
|
}
|
||||||
return links;
|
return links;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -944,6 +1123,9 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
const dowsing: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.sand);
|
const dowsing: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.sand);
|
||||||
const quarry: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.wood);
|
const quarry: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.wood);
|
||||||
const empowerer: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.coal);
|
const empowerer: ComputedRef<BoardNode | undefined> = computed(() => toolNodes.value.coal);
|
||||||
|
const portalGenerator: ComputedRef<BoardNode | undefined> = computed(
|
||||||
|
() => toolNodes.value.iron
|
||||||
|
);
|
||||||
|
|
||||||
function grantResource(type: Resources, amount: DecimalSource) {
|
function grantResource(type: Resources, amount: DecimalSource) {
|
||||||
let node = resourceNodes.value[type];
|
let node = resourceNodes.value[type];
|
||||||
|
@ -1304,6 +1486,17 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
energyProductionChange
|
energyProductionChange
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const activePortals = computed(() => board.types.portal.nodes.value.filter(n => isPowered(n)));
|
||||||
|
|
||||||
|
watch(activePortals, activePortals => {
|
||||||
|
nextTick(() => {
|
||||||
|
player.tabs = [
|
||||||
|
"main",
|
||||||
|
...activePortals.map(node => (node.state as unknown as PortalState).id)
|
||||||
|
];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "World",
|
name: "World",
|
||||||
board,
|
board,
|
||||||
|
@ -1368,7 +1561,22 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
||||||
export const getInitialLayers = (
|
export const getInitialLayers = (
|
||||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||||
player: Partial<Player>
|
player: Partial<Player>
|
||||||
): Array<GenericLayer> => [main];
|
): Array<GenericLayer> => {
|
||||||
|
const layers: GenericLayer[] = [main];
|
||||||
|
let id = 0;
|
||||||
|
while (`portal-${id}` in (player.layers ?? {})) {
|
||||||
|
const layer = player.layers?.[`portal-${id}`] as LayerData<GenericPlane>;
|
||||||
|
layers.push(
|
||||||
|
createPlane(
|
||||||
|
`portal-${id}`,
|
||||||
|
layer.tier ?? "dirt",
|
||||||
|
layer.seed ?? Math.floor(Math.random() * 4294967296)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
return layers;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A computed ref whose value is true whenever the game is over.
|
* A computed ref whose value is true whenever the game is over.
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"versionNumber": "0.0",
|
"versionNumber": "0.0",
|
||||||
"versionTitle": "Initial Commit",
|
"versionTitle": "Initial Commit",
|
||||||
|
|
||||||
"allowGoBack": true,
|
"allowGoBack": false,
|
||||||
"defaultShowSmall": false,
|
"defaultShowSmall": false,
|
||||||
"defaultDecimalsShown": 2,
|
"defaultDecimalsShown": 2,
|
||||||
"useHeader": true,
|
"useHeader": true,
|
||||||
|
|
235
src/data/utils.tsx
Normal file
235
src/data/utils.tsx
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
import { camelToTitle } from "util/common";
|
||||||
|
|
||||||
|
// Simple Fast Counter is a part of PractRand suite by Chris Doty-Humphrey.
|
||||||
|
export function sfc32(a: number, b: number, c: number, d: number) {
|
||||||
|
return function () {
|
||||||
|
a >>>= 0;
|
||||||
|
b >>>= 0;
|
||||||
|
c >>>= 0;
|
||||||
|
d >>>= 0;
|
||||||
|
let t = (a + b) | 0;
|
||||||
|
a = b ^ (b >>> 9);
|
||||||
|
b = (c + (c << 3)) | 0;
|
||||||
|
c = (c << 21) | (c >>> 11);
|
||||||
|
d = (d + 1) | 0;
|
||||||
|
t = (t + d) | 0;
|
||||||
|
c = (c + t) | 0;
|
||||||
|
return (t >>> 0) / 4294967296;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modified version of this lib to use seed: https://github.com/hbi99/namegen
|
||||||
|
const morphemes = {
|
||||||
|
1: [
|
||||||
|
"b",
|
||||||
|
"c",
|
||||||
|
"d",
|
||||||
|
"f",
|
||||||
|
"g",
|
||||||
|
"h",
|
||||||
|
"i",
|
||||||
|
"j",
|
||||||
|
"k",
|
||||||
|
"l",
|
||||||
|
"m",
|
||||||
|
"n",
|
||||||
|
"p",
|
||||||
|
"q",
|
||||||
|
"r",
|
||||||
|
"s",
|
||||||
|
"t",
|
||||||
|
"v",
|
||||||
|
"w",
|
||||||
|
"x",
|
||||||
|
"y",
|
||||||
|
"z"
|
||||||
|
],
|
||||||
|
2: ["a", "e", "o", "u"],
|
||||||
|
3: [
|
||||||
|
"br",
|
||||||
|
"cr",
|
||||||
|
"dr",
|
||||||
|
"fr",
|
||||||
|
"gr",
|
||||||
|
"pr",
|
||||||
|
"str",
|
||||||
|
"tr",
|
||||||
|
"bl",
|
||||||
|
"cl",
|
||||||
|
"fl",
|
||||||
|
"gl",
|
||||||
|
"pl",
|
||||||
|
"sl",
|
||||||
|
"sc",
|
||||||
|
"sk",
|
||||||
|
"sm",
|
||||||
|
"sn",
|
||||||
|
"sp",
|
||||||
|
"st",
|
||||||
|
"sw",
|
||||||
|
"ch",
|
||||||
|
"sh",
|
||||||
|
"th",
|
||||||
|
"wh"
|
||||||
|
],
|
||||||
|
4: [
|
||||||
|
"ae",
|
||||||
|
"ai",
|
||||||
|
"ao",
|
||||||
|
"au",
|
||||||
|
"a",
|
||||||
|
"ay",
|
||||||
|
"ea",
|
||||||
|
"ei",
|
||||||
|
"eo",
|
||||||
|
"eu",
|
||||||
|
"e",
|
||||||
|
"ey",
|
||||||
|
"ua",
|
||||||
|
"ue",
|
||||||
|
"ui",
|
||||||
|
"uo",
|
||||||
|
"u",
|
||||||
|
"uy",
|
||||||
|
"ia",
|
||||||
|
"ie",
|
||||||
|
"iu",
|
||||||
|
"io",
|
||||||
|
"iy",
|
||||||
|
"oa",
|
||||||
|
"oe",
|
||||||
|
"ou",
|
||||||
|
"oi",
|
||||||
|
"o",
|
||||||
|
"oy"
|
||||||
|
],
|
||||||
|
5: [
|
||||||
|
"turn",
|
||||||
|
"ter",
|
||||||
|
"nus",
|
||||||
|
"rus",
|
||||||
|
"tania",
|
||||||
|
"hiri",
|
||||||
|
"hines",
|
||||||
|
"gawa",
|
||||||
|
"nides",
|
||||||
|
"carro",
|
||||||
|
"rilia",
|
||||||
|
"stea",
|
||||||
|
"lia",
|
||||||
|
"lea",
|
||||||
|
"ria",
|
||||||
|
"nov",
|
||||||
|
"phus",
|
||||||
|
"mia",
|
||||||
|
"nerth",
|
||||||
|
"wei",
|
||||||
|
"ruta",
|
||||||
|
"tov",
|
||||||
|
"zuno",
|
||||||
|
"vis",
|
||||||
|
"lara",
|
||||||
|
"nia",
|
||||||
|
"liv",
|
||||||
|
"tera",
|
||||||
|
"gantu",
|
||||||
|
"yama",
|
||||||
|
"tune",
|
||||||
|
"ter",
|
||||||
|
"nus",
|
||||||
|
"cury",
|
||||||
|
"bos",
|
||||||
|
"pra",
|
||||||
|
"thea",
|
||||||
|
"nope",
|
||||||
|
"tis",
|
||||||
|
"clite"
|
||||||
|
],
|
||||||
|
6: [
|
||||||
|
"una",
|
||||||
|
"ion",
|
||||||
|
"iea",
|
||||||
|
"iri",
|
||||||
|
"illes",
|
||||||
|
"ides",
|
||||||
|
"agua",
|
||||||
|
"olla",
|
||||||
|
"inda",
|
||||||
|
"eshan",
|
||||||
|
"oria",
|
||||||
|
"ilia",
|
||||||
|
"erth",
|
||||||
|
"arth",
|
||||||
|
"orth",
|
||||||
|
"oth",
|
||||||
|
"illon",
|
||||||
|
"ichi",
|
||||||
|
"ov",
|
||||||
|
"arvis",
|
||||||
|
"ara",
|
||||||
|
"ars",
|
||||||
|
"yke",
|
||||||
|
"yria",
|
||||||
|
"onoe",
|
||||||
|
"ippe",
|
||||||
|
"osie",
|
||||||
|
"one",
|
||||||
|
"ore",
|
||||||
|
"ade",
|
||||||
|
"adus",
|
||||||
|
"urn",
|
||||||
|
"ypso",
|
||||||
|
"ora",
|
||||||
|
"iuq",
|
||||||
|
"orix",
|
||||||
|
"apus",
|
||||||
|
"ion",
|
||||||
|
"eon",
|
||||||
|
"eron",
|
||||||
|
"ao",
|
||||||
|
"omia"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const templates = [
|
||||||
|
[1, 2, 5],
|
||||||
|
[2, 3, 6],
|
||||||
|
[3, 4, 5],
|
||||||
|
[4, 3, 6],
|
||||||
|
[3, 4, 2, 5],
|
||||||
|
[2, 1, 3, 6],
|
||||||
|
[3, 4, 2, 5],
|
||||||
|
[4, 3, 1, 6],
|
||||||
|
[3, 4, 1, 4, 5],
|
||||||
|
[4, 1, 4, 3, 6]
|
||||||
|
] as const;
|
||||||
|
export function getName(random: () => number) {
|
||||||
|
const template = templates[Math.floor(random() * templates.length)];
|
||||||
|
let name = "";
|
||||||
|
for (let i = 0; i < template.length; i++) {
|
||||||
|
const morphemeSet = morphemes[template[i]];
|
||||||
|
name += morphemeSet[Math.floor(random() * morphemeSet.length)];
|
||||||
|
}
|
||||||
|
return camelToTitle(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getColor(base: [number, number, number], random: () => number) {
|
||||||
|
const [h, s, v] = rgb2hsv(...base);
|
||||||
|
const [r, g, b] = hsv2rgb(Math.floor(random() * 360), s, v);
|
||||||
|
return `rgb(${r * 255}, ${g * 255}, ${b * 255})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/54070620/4376101
|
||||||
|
// input: r,g,b in [0,1], out: h in [0,360) and s,v in [0,1]
|
||||||
|
function rgb2hsv(r: number, g: number, b: number) {
|
||||||
|
const v = Math.max(r, g, b),
|
||||||
|
c = v - Math.min(r, g, b);
|
||||||
|
const h = c && (v == r ? (g - b) / c : v == g ? 2 + (b - r) / c : 4 + (r - g) / c);
|
||||||
|
return [60 * (h < 0 ? h + 6 : h), v && c / v, v];
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/54024653/4376101
|
||||||
|
// input: h in [0,360] and s,v in [0,1] - output: r,g,b in [0,1]
|
||||||
|
function hsv2rgb(h: number, s: number, v: number) {
|
||||||
|
const f = (n: number, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);
|
||||||
|
return [f(5), f(3), f(1)];
|
||||||
|
}
|
Loading…
Reference in a new issue