Fantasy-Map-Generator/public/modules/coa-generator.js
Azgaar 9e0eb03618
[Migration] NPM (#1266)
* chore: add npm + vite for progressive enhancement

* fix: update Dockerfile to copy only the dist folder contents

* fix: update Dockerfile to use multi-stage build for optimized production image

* fix: correct nginx config file copy command in Dockerfile

* chore: add netlify configuration for build and redirects

* fix: add NODE_VERSION to environment in Netlify configuration

* remove wrong dist folder

* Update package.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: split public and src

* migrating all util files from js to ts

* feat: Implement HeightmapGenerator and Voronoi module

- Added HeightmapGenerator class for generating heightmaps with various tools (Hill, Pit, Range, Trough, Strait, etc.).
- Introduced Voronoi class for creating Voronoi diagrams using Delaunator.
- Updated index.html to include new modules.
- Created index.ts to manage module imports.
- Enhanced arrayUtils and graphUtils with type definitions and improved functionality.
- Added utility functions for generating grids and calculating Voronoi cells.

* chore: add GitHub Actions workflow for deploying to GitHub Pages

* fix: update branch name in GitHub Actions workflow from 'main' to 'master'

* chore: update package.json to specify Node.js engine version and remove unused launch.json

* Initial plan

* Update copilot guidelines to reflect NPM/Vite/TypeScript migration

Co-authored-by: Azgaar <26469650+Azgaar@users.noreply.github.com>

* Update src/modules/heightmap-generator.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/utils/graphUtils.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/modules/heightmap-generator.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* feat: Add TIME and ERROR variables to global scope in HeightmapGenerator

* fix: Update base path in vite.config.ts for Netlify deployment

* fix: Update Node.js version in Dockerfile to 24-alpine

---------

Co-authored-by: Marc Emmanuel <marc.emmanuel@tado.com>
Co-authored-by: Marc Emmanuel <marcwissler@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Azgaar <26469650+Azgaar@users.noreply.github.com>
2026-01-22 12:20:12 +01:00

2211 lines
48 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
window.COA = (function () {
const tinctures = {
field: {metals: 3, colours: 4, stains: +P(0.03), patterns: 1},
division: {metals: 5, colours: 8, stains: +P(0.03), patterns: 1},
charge: {metals: 2, colours: 3, stains: +P(0.05), patterns: 0},
metals: {argent: 3, or: 2},
colours: {gules: 5, azure: 4, sable: 3, purpure: 3, vert: 2},
stains: {murrey: 1, sanguine: 1, tenné: 1},
patterns: {
semy: 8,
ermine: 6,
vair: 4,
counterVair: 1,
vairInPale: 1,
vairEnPointe: 2,
vairAncien: 2,
potent: 2,
counterPotent: 1,
potentInPale: 1,
potentEnPointe: 1,
chequy: 8,
lozengy: 5,
fusily: 2,
pally: 8,
barry: 10,
gemelles: 1,
bendy: 8,
bendySinister: 4,
palyBendy: 2,
barryBendy: 1,
pappellony: 2,
pappellony2: 3,
scaly: 1,
plumetty: 1,
masoned: 6,
fretty: 3,
grillage: 1,
chainy: 1,
maily: 2,
honeycombed: 1
}
};
const chargeData = {
agnusDei: {
colors: 2,
sinister: true
},
angel: {
colors: 2,
positions: {e: 1}
},
anvil: {
sinister: true
},
apple: {
colors: 2
},
arbalest: {
colors: 3,
reversed: true
},
archer: {
colors: 3,
sinister: true
},
armEmbowedHoldingSabre: {
colors: 3,
sinister: true
},
armEmbowedVambraced: {
sinister: true
},
armEmbowedVambracedHoldingSword: {
colors: 3,
sinister: true
},
armillarySphere: {
positions: {e: 1}
},
arrow: {
colors: 3,
reversed: true
},
arrowsSheaf: {
colors: 3,
reversed: true
},
axe: {
colors: 2,
sinister: true
},
badgerStatant: {
colors: 2,
sinister: true
},
banner: {
colors: 2
},
basilisk: {
colors: 3,
sinister: true
},
bearPassant: {
colors: 3,
sinister: true
},
bearRampant: {
colors: 3,
sinister: true
},
bee: {
colors: 3,
reversed: true
},
bell: {
colors: 2
},
boarHeadErased: {
colors: 3,
sinister: true
},
boarRampant: {
colors: 3,
sinister: true,
positions: {e: 12, beh: 1, kn: 1, jln: 2}
},
boat: {
colors: 2
},
bookClosed: {
colors: 3,
sinister: true
},
bookClosed2: {
sinister: true
},
bookOpen: {
colors: 3
},
bow: {
sinister: true
},
bowWithArrow: {
colors: 3,
reversed: true
},
bowWithThreeArrows: {
colors: 3
},
bucket: {
colors: 2
},
bugleHorn: {
colors: 2
},
bugleHorn2: {
colors: 2
},
bullHeadCaboshed: {
colors: 2
},
bullPassant: {
colors: 3,
sinister: true
},
butterfly: {
colors: 3,
reversed: true
},
camel: {
colors: 2,
sinister: true
},
cancer: {
reversed: true
},
cannon: {
colors: 2,
sinister: true
},
caravel: {
colors: 3,
sinister: true
},
castle: {
colors: 2
},
castle2: {
colors: 3
},
catPassantGuardant: {
colors: 2,
sinister: true
},
cavalier: {
colors: 3,
sinister: true,
positions: {e: 1}
},
centaur: {
colors: 3,
sinister: true
},
chalice: {
colors: 2
},
cinquefoil: {
reversed: true
},
cock: {
colors: 3,
sinister: true
},
comet: {
reversed: true
},
cowStatant: {
colors: 3,
sinister: true
},
cossack: {
colors: 3,
sinister: true
},
crescent: {
reversed: true
},
crocodile: {
colors: 2,
sinister: true
},
crosier: {
sinister: true
},
crossbow: {
colors: 3,
sinister: true
},
crossGamma: {
sinister: true
},
crossLatin: {
reversed: true
},
crossTau: {
reversed: true
},
crossTriquetra: {
reversed: true
},
crown: {
colors: 2,
positions: {
e: 10,
abcdefgzi: 1,
beh: 3,
behdf: 2,
acegi: 1,
kn: 1,
pq: 2,
abc: 1,
jln: 4,
jleh: 1,
def: 2,
abcpqh: 3
}
},
crown2: {
colors: 3,
positions: {
e: 10,
abcdefgzi: 1,
beh: 3,
behdf: 2,
acegi: 1,
kn: 1,
pq: 2,
abc: 1,
jln: 4,
jleh: 1,
def: 2,
abcpqh: 3
}
},
deerHeadCaboshed: {
colors: 2
},
dolphin: {
colors: 2,
sinister: true
},
donkeyHeadCaboshed: {
colors: 2
},
dove: {
colors: 2,
natural: "argent",
sinister: true
},
doveDisplayed: {
colors: 2,
natural: "argent",
sinister: true
},
dragonfly: {
colors: 2,
reversed: true
},
dragonPassant: {
colors: 3,
sinister: true
},
dragonRampant: {
colors: 3,
sinister: true
},
drakkar: {
colors: 3,
sinister: true
},
drawingCompass: {
sinister: true
},
drum: {
colors: 3
},
duck: {
colors: 3,
sinister: true
},
eagle: {
colors: 3,
sinister: true,
positions: {e: 15, beh: 1, kn: 1, abc: 1, jlh: 2, def: 2, pq: 1}
},
eagleTwoHeads: {
colors: 3
},
elephant: {
colors: 2,
sinister: true
},
elephantHeadErased: {
colors: 2,
sinister: true
},
falchion: {
colors: 2,
reversed: true
},
falcon: {
colors: 3,
sinister: true
},
fan: {
colors: 2,
reversed: true
},
fasces: {
colors: 3,
sinister: true
},
feather: {
sinister: true
},
flamberge: {
colors: 2,
reversed: true
},
flangedMace: {
reversed: true
},
fly: {
colors: 3,
reversed: true
},
foot: {
sinister: true
},
fountain: {
natural: "azure"
},
frog: {
reversed: true
},
garb: {
colors: 2,
natural: "or",
positions: {e: 1, def: 3, abc: 2, beh: 1, kn: 1, jln: 3, jleh: 1, abcpqh: 1, joe: 1, lme: 1}
},
gauntlet: {
sinister: true,
reversed: true
},
goat: {
colors: 3,
sinister: true
},
goutte: {
reversed: true
},
grapeBunch: {
colors: 3,
sinister: true
},
grapeBunch2: {
colors: 3,
sinister: true
},
grenade: {
colors: 2
},
greyhoundCourant: {
colors: 3,
sinister: true,
positions: {e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1}
},
greyhoundRampant: {
colors: 2,
sinister: true,
positions: {e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1}
},
greyhoundSejant: {
colors: 3,
sinister: true
},
griffinPassant: {
colors: 3,
sinister: true,
positions: {e: 10, def: 2, abc: 2, bdefh: 1, kn: 1, jlh: 2, abcpqh: 1}
},
griffinRampant: {
colors: 3,
sinister: true,
positions: {e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1}
},
hand: {
sinister: true,
reversed: true,
positions: {e: 10, jln: 2, kn: 1, jeo: 1, abc: 2, pqe: 1}
},
harp: {
colors: 2,
sinister: true
},
hatchet: {
colors: 2,
sinister: true
},
head: {
colors: 2,
sinister: true,
positions: {e: 1}
},
headWreathed: {
colors: 3,
sinister: true,
positions: {e: 1}
},
hedgehog: {
colors: 3,
sinister: true
},
helmet: {
sinister: true
},
helmetCorinthian: {
colors: 3,
sinister: true
},
helmetGreat: {
sinister: true
},
helmetZischagge: {
sinister: true
},
heron: {
colors: 2,
sinister: true
},
hindStatant: {
colors: 2,
sinister: true
},
hook: {
sinister: true
},
horseHeadCouped: {
sinister: true
},
horsePassant: {
colors: 2,
sinister: true
},
horseRampant: {
colors: 3,
sinister: true
},
horseSalient: {
colors: 2,
sinister: true
},
horseshoe: {
reversed: true
},
hourglass: {
colors: 3
},
ladybird: {
colors: 3,
reversed: true
},
lamb: {
colors: 2,
sinister: true
},
lambPassantReguardant: {
colors: 2,
sinister: true
},
lanceWithBanner: {
colors: 3,
sinister: true
},
laurelWreath: {
colors: 2
},
lighthouse: {
colors: 3
},
lionHeadCaboshed: {
colors: 2
},
lionHeadErased: {
colors: 2,
sinister: true
},
lionPassant: {
colors: 3,
sinister: true,
positions: {e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1}
},
lionPassantGuardant: {
colors: 3,
sinister: true
},
lionRampant: {
colors: 3,
sinister: true,
positions: {e: 10, def: 2, abc: 2, bdefh: 1, kn: 1, jlh: 2, abcpqh: 1}
},
lionSejant: {
colors: 3,
sinister: true
},
lizard: {
reversed: true
},
lochaberAxe: {
colors: 2,
sinister: true
},
log: {
sinister: true
},
lute: {
colors: 2,
sinister: true
},
lymphad: {
colors: 3,
sinister: true,
positions: {e: 1}
},
mace: {
colors: 2
},
maces: {
colors: 2
},
mallet: {
colors: 2
},
mantle: {
colors: 3
},
martenCourant: {
colors: 3,
sinister: true
},
mascle: {
positions: {
e: 15,
abcdefgzi: 3,
beh: 3,
bdefh: 4,
acegi: 1,
kn: 3,
joe: 2,
abc: 3,
jlh: 8,
jleh: 1,
df: 3,
abcpqh: 4,
pqe: 3,
eknpq: 3
}
},
mastiffStatant: {
colors: 3,
sinister: true
},
mitre: {
colors: 3
},
monk: {
sinister: true
},
moonInCrescent: {
sinister: true
},
mullet: {
reversed: true
},
mullet7: {
reversed: true
},
oak: {
colors: 3
},
orb: {
colors: 3
},
ouroboros: {
sinister: true
},
owl: {
colors: 2,
sinister: true
},
owlDisplayed: {
colors: 2
},
palmTree: {
colors: 3
},
parrot: {
colors: 2,
sinister: true
},
peacock: {
colors: 3,
sinister: true
},
peacockInPride: {
colors: 3,
sinister: true
},
pear: {
colors: 2
},
pegasus: {
colors: 3,
sinister: true
},
pike: {
colors: 2,
sinister: true
},
pineTree: {
colors: 2
},
plaice: {
colors: 2,
sinister: true
},
plough: {
colors: 2,
sinister: true
},
ploughshare: {
sinister: true
},
porcupine: {
colors: 2,
sinister: true
},
portcullis: {
colors: 2
},
rabbitSejant: {
colors: 2,
sinister: true
},
rake: {
reversed: true
},
rapier: {
colors: 2,
sinister: true,
reversed: true
},
ramHeadErased: {
colors: 3,
sinister: true
},
ramPassant: {
colors: 3,
sinister: true
},
ratRampant: {
colors: 2,
sinister: true
},
raven: {
colors: 2,
natural: "sable",
sinister: true,
positions: {e: 15, beh: 1, kn: 1, jeo: 1, abc: 3, jln: 3, def: 1}
},
rhinoceros: {
colors: 2,
sinister: true
},
rose: {
colors: 3
},
sabre: {
colors: 2,
sinister: true
},
sabre2: {
colors: 2,
sinister: true,
reversed: true
},
sabresCrossed: {
colors: 2,
reversed: true
},
sagittarius: {
colors: 3,
sinister: true
},
salmon: {
colors: 2,
sinister: true
},
saw: {
colors: 2
},
scale: {
colors: 2
},
scaleImbalanced: {
colors: 2,
sinister: true
},
scissors: {
reversed: true
},
scorpion: {
reversed: true
},
scrollClosed: {
colors: 2,
sinister: true
},
scythe: {
colors: 2,
sinister: true,
reversed: true
},
scythe2: {
sinister: true
},
serpent: {
colors: 2,
sinister: true
},
shield: {
colors: 2,
sinister: true
},
sickle: {
colors: 2,
sinister: true,
reversed: true
},
snail: {
colors: 2,
sinister: true
},
snake: {
colors: 2,
sinister: true
},
spear: {
colors: 2,
reversed: true
},
spiral: {
sinister: true,
reversed: true
},
squirrel: {
sinister: true
},
stagLodgedRegardant: {
colors: 3,
sinister: true
},
stagPassant: {
colors: 2,
sinister: true
},
stirrup: {
colors: 2
},
swallow: {
colors: 2,
sinister: true
},
swan: {
colors: 3,
sinister: true
},
swanErased: {
colors: 3,
sinister: true
},
sword: {
colors: 2,
reversed: true
},
talbotPassant: {
colors: 3,
sinister: true
},
talbotSejant: {
colors: 3,
sinister: true
},
tower: {
colors: 2
},
tree: {
positions: {e: 1}
},
trefoil: {
reversed: true
},
trowel: {
colors: 2,
sinister: true,
reversed: true
},
unicornRampant: {
colors: 3,
sinister: true
},
wasp: {
colors: 3,
reversed: true
},
wheatStalk: {
colors: 2
},
windmill: {
colors: 3,
sinister: true
},
wing: {
sinister: true
},
wingSword: {
colors: 3,
sinister: true
},
wolfHeadErased: {
colors: 2,
sinister: true
},
wolfPassant: {
colors: 3,
sinister: true,
positions: {e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1}
},
wolfRampant: {
colors: 3,
sinister: true
},
wolfStatant: {
colors: 3,
sinister: true
},
wyvern: {
colors: 3,
sinister: true,
positions: {e: 10, jln: 1}
},
wyvernWithWingsDisplayed: {
colors: 3,
sinister: true
}
};
const charges = {
types: {
conventional: 33, // 40 charges
crosses: 13, // 30 charges
beasts: 7, // 41 charges
beastHeads: 3, // 10 charges
birds: 3, // 16 charges
reptiles: 2, // 5 charges
bugs: 2, // 8 charges
fishes: 1, // 3 charges
molluscs: 1, // 2 charges
plants: 3, // 18 charges
fantastic: 5, // 14 charges
agriculture: 2, // 8 charges
arms: 5, // 32 charges
bodyparts: 2, // 12 charges
people: 2, // 4 charges
architecture: 3, // 11 charges
seafaring: 3, // 9 charges
tools: 3, // 15 charges
miscellaneous: 5, // 30 charges
inescutcheon: 3, // 43 charges
ornaments: 0, // 9 charges
uploaded: 0
},
single: {
conventional: 10,
crosses: 8,
beasts: 7,
beastHeads: 3,
birds: 3,
reptiles: 2,
bugs: 2,
fishes: 1,
molluscs: 1,
plants: 3,
fantastic: 5,
agriculture: 2,
arms: 5,
bodyparts: 2,
people: 2,
architecture: 3,
seafaring: 3,
tools: 3,
miscellaneous: 5,
inescutcheon: 1
},
semy: {
conventional: 4,
crosses: 1
},
conventional: {
annulet: 4,
billet: 5,
carreau: 1,
comet: 1,
compassRose: 1,
crescent: 5,
delf: 0,
estoile: 1,
fleurDeLis: 6,
fountain: 1,
fusil: 4,
gear: 1,
goutte: 4,
heart: 4,
lozenge: 2,
lozengeFaceted: 3,
lozengePloye: 1,
mascle: 4,
moonInCrescent: 1,
mullet: 5,
mullet10: 1,
mullet4: 3,
mullet6: 4,
mullet6Faceted: 1,
mullet6Pierced: 1,
mullet7: 1,
mullet8: 1,
mulletFaceted: 1,
mulletPierced: 1,
pique: 2,
roundel: 4,
roundel2: 3,
rustre: 2,
spiral: 1,
sun: 3,
sunInSplendour: 1,
sunInSplendour2: 1,
trefle: 2,
triangle: 3,
trianglePierced: 1
},
crosses: {
crossHummetty: 15,
crossVoided: 1,
crossPattee: 2,
crossPatteeAlisee: 1,
crossFormee: 1,
crossFormee2: 2,
crossPotent: 2,
crossJerusalem: 1,
crosslet: 1,
crossClechy: 3,
crossBottony: 1,
crossFleury: 3,
crossPatonce: 1,
crossPommy: 1,
crossGamma: 1,
crossArrowed: 1,
crossFitchy: 1,
crossCercelee: 1,
crossMoline: 2,
crossFourchy: 1,
crossAvellane: 1,
crossErminee: 1,
crossBiparted: 1,
crossMaltese: 3,
crossTemplar: 2,
crossCeltic: 1,
crossCeltic2: 1,
crossTriquetra: 1,
crossCarolingian: 1,
crossOccitan: 1,
crossSaltire: 3,
crossBurgundy: 1,
crossLatin: 3,
crossPatriarchal: 1,
crossOrthodox: 1,
crossCalvary: 1,
crossDouble: 1,
crossTau: 1,
crossSantiago: 1,
crossAnkh: 1
},
beasts: {
agnusDei: 1,
badgerStatant: 1,
bearPassant: 1,
bearRampant: 3,
boarRampant: 1,
bullPassant: 1,
camel: 1,
catPassantGuardant: 1,
cowStatant: 1,
dolphin: 1,
elephant: 1,
goat: 1,
greyhoundCourant: 1,
greyhoundRampant: 1,
greyhoundSejant: 1,
hedgehog: 1,
hindStatant: 1,
horsePassant: 1,
horseRampant: 2,
horseSalient: 1,
lamb: 1,
lambPassantReguardant: 1,
lionPassant: 3,
lionPassantGuardant: 2,
lionRampant: 7,
lionSejant: 2,
martenCourant: 1,
mastiffStatant: 1,
porcupine: 1,
rabbitSejant: 1,
ramPassant: 1,
ratRampant: 1,
rhinoceros: 1,
squirrel: 1,
stagLodgedRegardant: 1,
stagPassant: 1,
talbotPassant: 1,
talbotSejant: 1,
wolfPassant: 1,
wolfRampant: 1,
wolfStatant: 1
},
beastHeads: {
boarHeadErased: 1,
bullHeadCaboshed: 1,
deerHeadCaboshed: 1,
donkeyHeadCaboshed: 1,
elephantHeadErased: 1,
horseHeadCouped: 1,
lionHeadCaboshed: 2,
lionHeadErased: 2,
ramHeadErased: 1,
wolfHeadErased: 2
},
birds: {
cock: 3,
dove: 2,
doveDisplayed: 1,
duck: 1,
eagle: 9,
falcon: 2,
heron: 1,
owl: 1,
owlDisplayed: 1,
parrot: 1,
peacock: 1,
peacockInPride: 1,
raven: 2,
swallow: 1,
swan: 2,
swanErased: 1
},
reptiles: {
crocodile: 1,
frog: 1,
lizard: 1,
ouroboros: 1,
snake: 1
},
bugs: {
bee: 1,
butterfly: 1,
cancer: 1,
dragonfly: 1,
fly: 1,
ladybird: 1,
scorpion: 1,
wasp: 1
},
fishes: {
pike: 1,
plaice: 1,
salmon: 1
},
molluscs: {
escallop: 4,
snail: 1
},
plants: {
apple: 1,
cinquefoil: 1,
earOfWheat: 1,
grapeBunch: 1,
grapeBunch2: 1,
mapleLeaf: 1,
oak: 1,
palmTree: 1,
pear: 1,
pineCone: 1,
pineTree: 1,
quatrefoil: 1,
rose: 1,
sextifoil: 1,
thistle: 1,
tree: 1,
trefoil: 1,
wheatStalk: 1
},
fantastic: {
angel: 3,
basilisk: 1,
centaur: 1,
dragonPassant: 3,
dragonRampant: 2,
eagleTwoHeads: 2,
griffinPassant: 1,
griffinRampant: 2,
pegasus: 1,
sagittarius: 1,
serpent: 1,
unicornRampant: 1,
wyvern: 1,
wyvernWithWingsDisplayed: 1
},
agriculture: {
garb: 2,
millstone: 1,
plough: 1,
ploughshare: 1,
rake: 1,
scythe: 1,
scythe2: 1,
sickle: 1
},
arms: {
arbalest: 1,
arbalest2: 1,
arrow: 1,
arrowsSheaf: 1,
axe: 3,
bow: 1,
bowWithArrow: 2,
bowWithThreeArrows: 1,
cannon: 1,
falchion: 1,
flamberge: 1,
flangedMace: 1,
gauntlet: 1,
grenade: 1,
hatchet: 3,
helmet: 2,
helmetCorinthian: 1,
helmetGreat: 2,
helmetZischagge: 1,
lanceHead: 1,
lanceWithBanner: 1,
lochaberAxe: 1,
mace: 1,
maces: 1,
mallet: 1,
rapier: 1,
sabre: 1,
sabre2: 1,
sabresCrossed: 1,
shield: 1,
spear: 1,
sword: 4
},
bodyparts: {
armEmbowedHoldingSabre: 1,
armEmbowedVambraced: 1,
armEmbowedVambracedHoldingSword: 1,
bone: 1,
crossedBones: 2,
foot: 1,
hand: 4,
head: 1,
headWreathed: 1,
skeleton: 2,
skull: 2,
skull2: 1
},
people: {
archer: 1,
cavalier: 3,
cossack: 1,
monk: 1
},
architecture: {
bridge: 1,
bridge2: 1,
castle: 2,
castle2: 1,
column: 1,
lighthouse: 1,
palace: 1,
pillar: 1,
portcullis: 1,
tower: 2,
windmill: 1
},
seafaring: {
anchor: 6,
armillarySphere: 1,
boat: 2,
boat2: 1,
caravel: 1,
drakkar: 1,
lymphad: 2,
raft: 1,
shipWheel: 1
},
tools: {
anvil: 2,
drawingCompass: 2,
fan: 1,
hook: 1,
ladder: 1,
ladder2: 1,
pincers: 1,
saw: 1,
scale: 1,
scaleImbalanced: 1,
scalesHanging: 1,
scissors: 1,
scissors2: 1,
shears: 1,
trowel: 1
},
miscellaneous: {
attire: 2,
banner: 2,
bell: 3,
bookClosed: 1,
bookClosed2: 1,
bookOpen: 1,
bucket: 1,
buckle: 1,
bugleHorn: 2,
bugleHorn2: 1,
chain: 2,
chalice: 2,
cowHorns: 3,
crosier: 1,
crown: 3,
crown2: 2,
drum: 1,
fasces: 1,
feather: 3,
harp: 2,
horseshoe: 3,
hourglass: 2,
key: 3,
laurelWreath: 2,
laurelWreath2: 1,
log: 1,
lute: 2,
lyre: 1,
mitre: 1,
orb: 1,
pot: 2,
ramsHorn: 1,
sceptre: 1,
scrollClosed: 1,
snowflake: 1,
stagsAttires: 1,
stirrup: 2,
wheel: 3,
wing: 2,
wingSword: 1
},
inescutcheon: {
inescutcheonHeater: 1,
inescutcheonSpanish: 1,
inescutcheonFrench: 1,
inescutcheonHorsehead: 1,
inescutcheonHorsehead2: 1,
inescutcheonPolish: 1,
inescutcheonHessen: 1,
inescutcheonSwiss: 1,
inescutcheonBoeotian: 1,
inescutcheonRoman: 1,
inescutcheonKite: 1,
inescutcheonOldFrench: 1,
inescutcheonRenaissance: 1,
inescutcheonBaroque: 1,
inescutcheonTarge: 1,
inescutcheonTarge2: 1,
inescutcheonPavise: 1,
inescutcheonWedged: 1,
inescutcheonFlag: 1,
inescutcheonPennon: 1,
inescutcheonGuidon: 1,
inescutcheonBanner: 1,
inescutcheonDovetail: 1,
inescutcheonGonfalon: 1,
inescutcheonPennant: 1,
inescutcheonRound: 1,
inescutcheonOval: 1,
inescutcheonVesicaPiscis: 1,
inescutcheonSquare: 1,
inescutcheonDiamond: 1,
inescutcheonNo: 1,
inescutcheonFantasy1: 1,
inescutcheonFantasy2: 1,
inescutcheonFantasy3: 1,
inescutcheonFantasy4: 1,
inescutcheonFantasy5: 1,
inescutcheonNoldor: 1,
inescutcheonGondor: 1,
inescutcheonEasterling: 1,
inescutcheonErebor: 1,
inescutcheonIronHills: 1,
inescutcheonUrukHai: 1,
inescutcheonMoriaOrc: 1
},
ornaments: {
mantle: 0,
ribbon1: 3,
ribbon2: 2,
ribbon3: 1,
ribbon4: 1,
ribbon5: 1,
ribbon6: 1,
ribbon7: 1,
ribbon8: 1
},
data: chargeData
};
// charges specific to culture or burg type (FMG-only config, not coming from Armoria)
const typeMapping = {
Naval: {
anchor: 3,
drakkar: 1,
lymphad: 2,
caravel: 1,
shipWheel: 1,
armillarySphere: 1,
escallop: 1,
dolphin: 1,
plaice: 1
},
Highland: {tower: 1, raven: 1, wolfHeadErased: 1, wolfPassant: 1, goat: 1, axe: 1},
River: {
garb: 1,
rake: 1,
raft: 1,
boat: 2,
drakkar: 2,
hook: 2,
pike: 2,
bullHeadCaboshed: 1,
apple: 1,
pear: 1,
plough: 1,
earOfWheat: 1,
salmon: 1,
cancer: 1,
bridge: 1,
bridge2: 2,
sickle: 1,
scythe: 1,
grapeBunch: 1,
wheatStalk: 1,
windmill: 1,
crocodile: 1
},
Lake: {
hook: 3,
cancer: 2,
escallop: 1,
pike: 2,
heron: 1,
boat: 1,
boat2: 2,
salmon: 1,
cancer: 1,
sickle: 1,
windmill: 1,
swanErased: 1,
swan: 1,
frog: 1,
wasp: 1
},
Nomadic: {
pot: 1,
buckle: 1,
wheel: 2,
sabre: 2,
sabresCrossed: 1,
bow: 2,
arrow: 1,
horseRampant: 1,
horseSalient: 1,
crescent: 1,
camel: 3,
scorpion: 1,
falcon: 1
},
Hunting: {
bugleHorn: 2,
bugleHorn2: 1,
stagsAttires: 2,
attire: 2,
hatchet: 1,
bowWithArrow: 2,
arrowsSheaf: 1,
lanceHead: 1,
saw: 1,
deerHeadCaboshed: 1,
wolfStatant: 1,
oak: 1,
pineCone: 1,
pineTree: 1,
oak: 1,
owl: 1,
falcon: 1,
peacock: 1,
boarHeadErased: 2,
horseHeadCouped: 1,
rabbitSejant: 1,
wolfRampant: 1,
wolfPassant: 1,
wolfStatant: 1,
greyhoundCourant: 1,
greyhoundRampant: 1,
greyhoundSejant: 1,
mastiffStatant: 1,
talbotPassant: 1,
talbotSejant: 1,
stagPassant: 21
},
// selection based on type
City: {
key: 4,
bell: 3,
lute: 1,
tower: 1,
pillar: 1,
castle: 1,
castle2: 1,
portcullis: 1,
mallet: 1,
cannon: 1,
anvil: 1,
buckle: 1,
horseshoe: 1,
stirrup: 1,
lanceWithBanner: 1,
bookClosed: 1,
scissors: 1,
scissors2: 1,
shears: 1,
pincers: 1,
bridge: 2,
archer: 1,
cannon: 1,
shield: 1,
arbalest: 1,
arbalest2: 1,
bowWithThreeArrows: 1,
spear: 1,
lochaberAxe: 1,
armEmbowedHoldingSabre: 1,
grenade: 1,
maces: 1,
grapeBunch: 1,
cock: 1,
ramHeadErased: 1,
ratRampant: 1,
hourglass: 1,
scale: 1,
scrollClosed: 1
},
Capital: {
crown: 2,
crown2: 2,
laurelWreath: 1,
orb: 1,
lute: 1,
lyre: 1,
banner: 1,
castle: 1,
castle2: 1,
palace: 1,
crown2: 2,
column: 1,
lionRampant: 1,
stagLodgedRegardant: 1,
drawingCompass: 1,
rapier: 1,
scaleImbalanced: 1,
scalesHanging: 1
},
Сathedra: {
crossHummetty: 3,
mitre: 3,
chalice: 1,
orb: 1,
crosier: 2,
lamb: 1,
monk: 2,
angel: 3,
crossLatin: 2,
crossPatriarchal: 1,
crossOrthodox: 1,
crossCalvary: 1,
agnusDei: 3,
bookOpen: 1,
sceptre: 1,
bone: 1,
skull: 1
}
};
const positions = {
conventional: {
e: 20,
abcdefgzi: 3,
beh: 3,
behdf: 2,
acegi: 1,
kn: 3,
bhdf: 1,
jeo: 1,
abc: 3,
jln: 6,
jlh: 3,
kmo: 2,
jleh: 1,
def: 3,
abcpqh: 4,
ABCDEFGHIJKL: 1
},
complex: {e: 40, beh: 1, kn: 1, jeo: 1, abc: 2, jln: 7, jlh: 2, def: 1, abcpqh: 1},
divisions: {
perPale: {e: 15, pq: 5, jo: 2, jl: 2, ABCDEFGHIJKL: 1},
perFess: {e: 12, kn: 4, jkl: 2, gizgiz: 1, jlh: 3, kmo: 1, ABCDEFGHIJKL: 1},
perBend: {e: 5, lm: 5, bcfdgh: 1},
perBendSinister: {e: 1, jo: 1},
perCross: {e: 4, jlmo: 1, j: 1, jo: 2, jl: 1},
perChevron: {e: 1, jlh: 1, dfk: 1, dfbh: 2, bdefh: 1},
perChevronReversed: {e: 1, mok: 2, dfh: 2, dfbh: 1, bdefh: 1},
perSaltire: {bhdf: 8, e: 3, abcdefgzi: 1, bh: 1, df: 1, ABCDEFGHIJKL: 1},
perPile: {ee: 3, be: 2, abceh: 1, abcabc: 1, jleh: 1}
},
inescutcheon: {e: 4, jln: 1}
};
const lines = {
straight: 50,
wavy: 8,
engrailed: 4,
invecked: 3,
rayonne: 3,
embattled: 1,
raguly: 1,
urdy: 1,
dancetty: 1,
indented: 2,
dentilly: 1,
bevilled: 1,
angled: 1,
flechy: 1,
barby: 1,
enclavy: 1,
escartely: 1,
arched: 2,
archedReversed: 1,
nowy: 1,
nowyReversed: 1,
embattledGhibellin: 1,
embattledNotched: 1,
embattledGrady: 1,
dovetailedIndented: 1,
dovetailed: 1,
potenty: 1,
potentyDexter: 1,
potentySinister: 1,
nebuly: 2,
seaWaves: 1,
dragonTeeth: 1,
firTrees: 1
};
const divisions = {
variants: {
perPale: 5,
perFess: 5,
perBend: 2,
perBendSinister: 1,
perChevron: 1,
perChevronReversed: 1,
perCross: 5,
perPile: 1,
perSaltire: 1,
gyronny: 1,
chevronny: 1
},
perPale: lines,
perFess: lines,
perBend: lines,
perBendSinister: lines,
perChevron: lines,
perChevronReversed: lines,
perCross: {
straight: 20,
wavy: 5,
engrailed: 4,
invecked: 3,
rayonne: 1,
embattled: 1,
raguly: 1,
urdy: 1,
indented: 2,
dentilly: 1,
bevilled: 1,
angled: 1,
embattledGhibellin: 1,
embattledGrady: 1,
dovetailedIndented: 1,
dovetailed: 1,
potenty: 1,
potentyDexter: 1,
potentySinister: 1,
nebuly: 1
},
perPile: lines
};
const ordinaries = {
lined: {
pale: 7,
fess: 5,
bend: 3,
bendSinister: 2,
chief: 5,
bar: 2,
gemelle: 1,
fessCotissed: 1,
fessDoubleCotissed: 1,
bendlet: 2,
bendletSinister: 1,
terrace: 3,
cross: 6,
crossParted: 1,
saltire: 2,
saltireParted: 1
},
straight: {
bordure: 8,
orle: 4,
mount: 1,
point: 2,
flaunches: 1,
gore: 1,
gyron: 1,
quarter: 1,
canton: 2,
pall: 3,
pallReversed: 2,
chevron: 4,
chevronReversed: 3,
pile: 2,
pileInBend: 2,
pileInBendSinister: 1,
piles: 1,
pilesInPoint: 2,
label: 1
},
data: {
bar: {
positionsOn: {defdefdef: 1},
positionsOff: {abc: 2, abcgzi: 1, jlh: 5, bgi: 2, ach: 1}
},
bend: {
positionsOn: {ee: 2, jo: 1, joe: 1},
positionsOff: {ccg: 2, ccc: 1}
},
bendSinister: {
positionsOn: {ee: 1, lm: 1, lem: 4},
positionsOff: {aai: 2, aaa: 1}
},
bendlet: {
positionsOn: {joejoejoe: 1},
positionsOff: {ccg: 2, ccc: 1}
},
bendletSinister: {
positionsOn: {lemlemlem: 1},
positionsOff: {aai: 2, aaa: 1}
},
bordure: {
positionsOn: {ABCDEFGHIJKL: 1},
positionsOff: {e: 4, jleh: 2, kenken: 1, peqpeq: 1}
},
canton: {
positionsOn: {yyyy: 1},
positionsOff: {e: 5, beh: 1, def: 1, bdefh: 1, kn: 1}
},
chevron: {
positionsOn: {ach: 3, hhh: 1}
},
chevronReversed: {
positionsOff: {bbb: 1}
},
chief: {
positionsOn: {abc: 5, bbb: 1},
positionsOff: {emo: 2, emoz: 1, ez: 2}
},
cross: {
positionsOn: {eeee: 1, behdfbehdf: 3, behbehbeh: 2},
positionsOff: {acgi: 1}
},
crossParted: {
positionsOn: {e: 5, ee: 1}
},
fess: {
positionsOn: {ee: 1, def: 3},
positionsOff: {abc: 3, abcz: 1}
},
fessCotissed: {
positionsOn: {ee: 1, def: 3}
},
fessDoubleCotissed: {
positionsOn: {ee: 1, defdef: 3}
},
flaunches: {
positionsOff: {e: 3, kn: 1, beh: 3}
},
gemelle: {
positionsOff: {abc: 1}
},
gyron: {
positionsOff: {bh: 1}
},
label: {
positionsOff: {defgzi: 2, eh: 3, defdefhmo: 1, egiegi: 1, pqn: 5}
},
mount: {
positionsOff: {e: 5, def: 1, bdf: 3}
},
orle: {
positionsOff: {e: 4, jleh: 1, kenken: 1, peqpeq: 1}
},
pale: {
positionsOn: {ee: 12, beh: 10, kn: 3, bb: 1},
positionsOff: {yyy: 1}
},
pall: {
positionsOn: {ee: 1, jleh: 5, jlhh: 3},
positionsOff: {BCKFEILGJbdmfo: 1}
},
pallReversed: {
positionsOn: {ee: 1, bemo: 5},
positionsOff: {aczac: 1}
},
pile: {
positionsOn: {bbb: 1},
positionsOff: {acdfgi: 1, acac: 1}
},
pileInBend: {
positionsOn: {eeee: 1, eeoo: 1},
positionsOff: {cg: 1}
},
pileInBendSinister: {
positionsOn: {eeee: 1, eemm: 1},
positionsOff: {ai: 1}
},
point: {
positionsOff: {e: 2, def: 1, bdf: 3, acbdef: 1}
},
quarter: {
positionsOn: {jjj: 1},
positionsOff: {e: 1}
},
saltire: {
positionsOn: {ee: 5, jlemo: 1}
},
saltireParted: {
positionsOn: {e: 5, ee: 1}
},
terrace: {
positionsOff: {e: 5, def: 1, bdf: 3}
}
}
};
const shields = {
types: {basic: 10, regional: 2, historical: 1, specific: 1, banner: 1, simple: 2, fantasy: 1, middleEarth: 0},
basic: {heater: 12, spanish: 6, french: 1},
regional: {horsehead: 1, horsehead2: 1, polish: 1, hessen: 1, swiss: 1},
historical: {boeotian: 1, roman: 2, kite: 1, oldFrench: 5, renaissance: 2, baroque: 2},
specific: {targe: 1, targe2: 0, pavise: 5, wedged: 10},
banner: {flag: 1, pennon: 0, guidon: 0, banner: 0, dovetail: 1, gonfalon: 5, pennant: 0},
simple: {round: 12, oval: 6, vesicaPiscis: 1, square: 1, diamond: 2, no: 0},
fantasy: {fantasy1: 2, fantasy2: 2, fantasy3: 1, fantasy4: 1, fantasy5: 3},
middleEarth: {noldor: 1, gondor: 1, easterling: 1, erebor: 1, ironHills: 1, urukHai: 1, moriaOrc: 1}
};
const generate = function (parent, kinship, dominion, type) {
if (!parent || parent.custom) {
parent = null;
kinship = 0;
dominion = 0;
}
let usedPattern = null;
let usedTinctures = [];
const t1 = P(kinship) ? parent.t1 : getTincture("field");
if (t1.includes("-")) usedPattern = t1;
const coa = {t1};
const addCharge = P(usedPattern ? 0.5 : 0.93); // 80% for charge
const linedOrdinary =
(addCharge && P(0.3)) || P(0.5)
? parent?.ordinaries && P(kinship)
? parent.ordinaries[0].ordinary
: rw(ordinaries.lined)
: null;
const ordinary =
(!addCharge && P(0.65)) || P(0.3) ? (linedOrdinary ? linedOrdinary : rw(ordinaries.straight)) : null; // 36% for ordinary
const rareDivided = ["chief", "terrace", "chevron", "quarter", "flaunches"].includes(ordinary);
const divisioned = (() => {
if (rareDivided) return P(0.03);
if (addCharge && ordinary) return P(0.03);
if (addCharge) return P(0.3);
if (ordinary) return P(0.7);
return P(0.995);
})();
const division = (() => {
if (divisioned) {
if (parent?.division && P(kinship - 0.1)) return parent.division.division;
return rw(divisions.variants);
}
return null;
})();
if (division) {
const t = getTincture("division", usedTinctures, P(0.98) ? coa.t1 : null);
coa.division = {division, t};
if (divisions[division])
coa.division.line = usedPattern || (ordinary && P(0.7)) ? "straight" : rw(divisions[division]);
}
if (ordinary) {
coa.ordinaries = [{ordinary, t: getTincture("charge", usedTinctures, coa.t1)}];
if (linedOrdinary) coa.ordinaries[0].line = usedPattern || (division && P(0.7)) ? "straight" : rw(lines);
if (division && !addCharge && !usedPattern && P(0.5) && ordinary !== "bordure" && ordinary !== "orle") {
if (P(0.8)) coa.ordinaries[0].divided = "counter";
// 40%
else if (P(0.6)) coa.ordinaries[0].divided = "field";
// 6%
else coa.ordinaries[0].divided = "division"; // 4%
}
}
if (addCharge) {
const charge = (() => {
if (parent?.charges && P(kinship - 0.1)) return parent.charges[0].charge;
if (type && type !== "Generic" && P(0.3)) return rw(typeMapping[type]);
return selectCharge(ordinary || divisioned ? charges.types : charges.single);
})();
const chargeData = charges.data[charge] || {};
let p = "e";
let t = "gules";
const ordinaryData = ordinaries.data[ordinary];
const tOrdinary = coa.ordinaries ? coa.ordinaries[0].t : null;
if (ordinaryData?.positionsOn && P(0.8)) {
// place charge over ordinary (use tincture of field type)
p = rw(ordinaryData.positionsOn);
t = !usedPattern && P(0.3) ? coa.t1 : getTincture("charge", [], tOrdinary);
} else if (ordinaryData?.positionsOff && P(0.95)) {
// place charge out of ordinary (use tincture of ordinary type)
p = rw(ordinaryData.positionsOff);
t = !usedPattern && P(0.3) ? tOrdinary : getTincture("charge", usedTinctures, coa.t1);
} else if (positions.divisions[division]) {
// place charge in fields made by division
p = rw(positions.divisions[division]);
t = getTincture("charge", tOrdinary ? usedTinctures.concat(tOrdinary) : usedTinctures, coa.t1);
} else if (chargeData.positions) {
// place charge-suitable position
p = rw(chargeData.positions);
t = getTincture("charge", usedTinctures, coa.t1);
} else {
// place in standard position (use new tincture)
p = usedPattern ? "e" : charges.conventional[charge] ? rw(positions.conventional) : rw(positions.complex);
t = getTincture("charge", usedTinctures.concat(tOrdinary), coa.t1);
}
if (chargeData.natural && chargeData.natural !== t && chargeData.natural !== tOrdinary) t = chargeData.natural;
const item = {charge: charge, t, p};
const colors = chargeData.colors || 1;
if (colors > 1) item.t2 = P(0.25) ? getTincture("charge", usedTinctures, coa.t1) : t;
if (colors > 2 && item.t2) item.t3 = P(0.5) ? getTincture("charge", usedTinctures, coa.t1) : t;
coa.charges = [item];
if (p === "ABCDEFGHIKL" && P(0.95)) {
// add central charge if charge is in bordure
coa.charges[0].charge = rw(charges.conventional);
const charge = selectCharge(charges.single);
const t = getTincture("charge", usedTinctures, coa.t1);
coa.charges.push({charge, t, p: "e"});
} else if (P(0.8) && charge === "inescutcheon") {
// add charge to inescutcheon
const charge = selectCharge(charges.types);
const t2 = getTincture("charge", [], t);
coa.charges.push({charge, t: t2, p, size: 0.5});
} else if (division && !ordinary) {
const allowCounter = !usedPattern && (!coa.line || coa.line === "straight");
// dimidiation: second charge at division basic positons
if (P(0.3) && ["perPale", "perFess"].includes(division) && coa.line === "straight") {
coa.charges[0].divided = "field";
if (P(0.95)) {
const p2 = p === "e" || P(0.5) ? "e" : rw(positions.divisions[division]);
const charge = selectCharge(charges.single);
const t = getTincture("charge", usedTinctures, coa.division.t);
coa.charges.push({charge, t, p: p2, divided: "division"});
}
} else if (allowCounter && P(0.4)) coa.charges[0].divided = "counter";
// counterchanged, 40%
else if (["perPale", "perFess", "perBend", "perBendSinister"].includes(division) && P(0.8)) {
// place 2 charges in division standard positions
const [p1, p2] =
division === "perPale"
? ["p", "q"]
: division === "perFess"
? ["k", "n"]
: division === "perBend"
? ["l", "m"]
: ["j", "o"]; // perBendSinister
coa.charges[0].p = p1;
const charge = selectCharge(charges.single);
const t = getTincture("charge", usedTinctures, coa.division.t);
coa.charges.push({charge, t, p: p2});
} else if (["perCross", "perSaltire"].includes(division) && P(0.5)) {
// place 4 charges in division standard positions
const [p1, p2, p3, p4] = division === "perCross" ? ["j", "l", "m", "o"] : ["b", "d", "f", "h"];
coa.charges[0].p = p1;
const c2 = selectCharge(charges.single);
const t2 = getTincture("charge", [], coa.division.t);
const c3 = selectCharge(charges.single);
const t3 = getTincture("charge", [], coa.division.t);
const c4 = selectCharge(charges.single);
const t4 = getTincture("charge", [], coa.t1);
coa.charges.push({charge: c2, t: t2, p: p2}, {charge: c3, t: t3, p: p3}, {charge: c4, t: t4, p: p4});
} else if (allowCounter && p.length > 1) coa.charges[0].divided = "counter"; // counterchanged, 40%
}
coa.charges.forEach(c => defineChargeAttributes(ordinary, division, c));
}
// dominions have canton with parent coa
if (P(dominion) && parent.charges) {
const invert = isSameType(parent.t1, coa.t1);
const t = invert ? getTincture("division", usedTinctures, coa.t1) : parent.t1;
const canton = {ordinary: "canton", t};
coa.charges?.forEach((charge, i) => {
if (charge.size === 1.5) charge.size = 1.4;
charge.p = charge.p.replaceAll(/[ajy]/g, "");
if (!charge.p) coa.charges.splice(i, 1);
});
let charge = parent.charges[0].charge;
if (charge === "inescutcheon" && parent.charges[1]) charge = parent.charges[1].charge;
let t2 = invert ? parent.t1 : parent.charges[0].t;
if (isSameType(t, t2)) t2 = getTincture("charge", usedTinctures, t);
if (!coa.charges) coa.charges = [];
coa.charges.push({charge, t: t2, p: "y", size: 0.5});
coa.ordinaries ? coa.ordinaries.push(canton) : (coa.ordinaries = [canton]);
}
function selectCharge(set) {
const type = set ? rw(set) : ordinary || divisioned ? rw(charges.types) : rw(charges.single);
return type === "inescutcheon" ? "inescutcheon" : rw(charges[type]);
}
// select tincture: element type (field, division, charge), used field tinctures, field type to follow RoT
function getTincture(element, fields = [], RoT) {
const base = RoT ? (RoT.includes("-") ? RoT.split("-")[1] : RoT) : null;
let type = rw(tinctures[element]); // metals, colours, stains, patterns
if (RoT && type !== "patterns") type = getType(base) === "metals" ? "colours" : "metals"; // follow RoT
if (type === "metals" && fields.includes("or") && fields.includes("argent")) type = "colours"; // exclude metals overuse
let tincture = rw(tinctures[type]);
while (tincture === base || fields.includes(tincture)) {
tincture = rw(tinctures[type]);
} // follow RoT
if (type !== "patterns" && element !== "charge") usedTinctures.push(tincture); // add field tincture
if (type === "patterns") {
usedPattern = tincture;
tincture = definePattern(tincture, element);
}
return tincture;
}
function defineChargeAttributes(ordinary, division, c) {
// define size
c.size = (c.size || 1) * getSize(c.p, ordinary, division);
// clean-up position
c.p = [...new Set(c.p)].join("");
// define orientation
if (P(0.02) && charges.data[c.charge]?.sinister) c.sinister = 1;
if (P(0.02) && charges.data[c.charge]?.reversed) c.reversed = 1;
}
function getType(t) {
const tincture = t.includes("-") ? t.split("-")[1] : t;
if (Object.keys(tinctures.metals).includes(tincture)) return "metals";
if (Object.keys(tinctures.colours).includes(tincture)) return "colours";
if (Object.keys(tinctures.stains).includes(tincture)) return "stains";
}
function isSameType(t1, t2) {
return type(t1) === type(t2);
function type(tincture) {
if (Object.keys(tinctures.metals).includes(tincture)) return "metals";
if (Object.keys(tinctures.colours).includes(tincture)) return "colours";
if (Object.keys(tinctures.stains).includes(tincture)) return "stains";
else return "pattern";
}
}
function definePattern(pattern, element, size = "") {
let t1 = null,
t2 = null;
if (P(0.1)) size = "-small";
else if (P(0.1)) size = "-smaller";
else if (P(0.01)) size = "-big";
else if (P(0.005)) size = "-smallest";
// apply standard tinctures
if (P(0.5) && ["vair", "vairInPale", "vairEnPointe"].includes(pattern)) {
t1 = "azure";
t2 = "argent";
} else if (P(0.8) && pattern === "ermine") {
t1 = "argent";
t2 = "sable";
} else if (pattern === "pappellony") {
if (P(0.2)) {
t1 = "gules";
t2 = "or";
} else if (P(0.2)) {
t1 = "argent";
t2 = "sable";
} else if (P(0.2)) {
t1 = "azure";
t2 = "argent";
}
} else if (pattern === "masoned") {
if (P(0.3)) {
t1 = "gules";
t2 = "argent";
} else if (P(0.3)) {
t1 = "argent";
t2 = "sable";
} else if (P(0.1)) {
t1 = "or";
t2 = "sable";
}
} else if (pattern === "fretty") {
if (t2 === "sable" || P(0.35)) {
t1 = "argent";
t2 = "gules";
} else if (P(0.25)) {
t1 = "sable";
t2 = "or";
} else if (P(0.15)) {
t1 = "gules";
t2 = "argent";
}
} else if (pattern === "semy") pattern += "_of_" + selectCharge(charges.semy);
if (!t1 || !t2) {
const startWithMetal = P(0.7);
t1 = startWithMetal ? rw(tinctures.metals) : rw(tinctures.colours);
t2 = startWithMetal ? rw(tinctures.colours) : rw(tinctures.metals);
}
// division should not be the same tincture as base field
if (element === "division") {
if (usedTinctures.includes(t1)) t1 = replaceTincture(t1);
if (usedTinctures.includes(t2)) t2 = replaceTincture(t2);
}
usedTinctures.push(t1, t2);
return `${pattern}-${t1}-${t2}${size}`;
}
function replaceTincture(t, n) {
const type = getType(t);
while (!n || n === t) {
n = rw(tinctures[type]);
}
return n;
}
function getSize(p, o = null, d = null) {
if (p === "e" && (o === "bordure" || o === "orle")) return 1.1;
if (p === "e") return 1.5;
if (p === "jln" || p === "jlh") return 0.7;
if (p === "abcpqh" || p === "ez" || p === "be") return 0.5;
if (["a", "b", "c", "d", "f", "g", "h", "i", "bh", "df"].includes(p)) return 0.5;
if (["j", "l", "m", "o", "jlmo"].includes(p) && d === "perCross") return 0.6;
if (p.length > 10) return 0.18; // >10 (bordure)
if (p.length > 7) return 0.3; // 8, 9, 10
if (p.length > 4) return 0.4; // 5, 6, 7
if (p.length > 2) return 0.5; // 3, 4
return 0.7; // 1, 2
}
return coa;
};
const getShield = function (culture, state) {
const emblemShape = document.getElementById("emblemShape");
const shapeGroup = emblemShape.selectedOptions[0]?.parentNode.label || "Diversiform";
if (shapeGroup !== "Diversiform") return emblemShape.value;
if (emblemShape.value === "state" && state && pack.states[state].coa) return pack.states[state].coa.shield;
if (pack.cultures[culture].shield) return pack.cultures[culture].shield;
ERROR && console.error("Shield shape is not defined on culture level", pack.cultures[culture]);
return "heater";
};
const toString = coa => JSON.stringify(coa).replaceAll("#", "%23");
const copy = coa => JSON.parse(JSON.stringify(coa));
return {generate, toString, copy, getShield, shields};
})();