This commit is contained in:
Azgaar 2020-04-26 20:30:07 +03:00
parent 9573f99376
commit a2b93f1396
16 changed files with 130 additions and 130 deletions

View file

@ -326,13 +326,13 @@ div.tab > button#optionsHide {
.tab { .tab {
overflow: hidden; overflow: hidden;
border-bottom: 1px solid #5d4651; border-bottom: 1px solid #5d4651;
height: 2.3em; height: 2.2em;
} }
#options p { #options p {
font-style: italic; font-style: italic;
font-weight: bold; font-weight: bold;
margin-bottom: 0; margin: .8em 0 0 0;
} }
#aboutContent { #aboutContent {
@ -346,6 +346,7 @@ div.tab > button#optionsHide {
#aboutContent a { #aboutContent a {
color: #1d1b1c; color: #1d1b1c;
font-weight: bold; font-weight: bold;
text-decoration: underline;
} }
#optionsContent span { #optionsContent span {
@ -572,10 +573,9 @@ input[type="color"]::-webkit-color-swatch-wrapper {
} }
.tab > button.options { .tab > button.options {
/* width: 23.25%; */
width: 18.6%; width: 18.6%;
height: 100%; height: 100%;
padding: 7px 0px; padding: 6px 0px;
} }
button.options { button.options {
@ -943,18 +943,18 @@ body button.noicon {
} }
.drag-trigger { .drag-trigger {
border-left: 12px solid transparent; border-left: 1em solid transparent;
border-right: 12px solid #916e7f; border-right: 1em solid #000;
border-top: 12px solid transparent; border-top: 1em solid transparent;
position: absolute; position: absolute;
right: 0; right: -1px;
top: 100%; bottom: -1px;
margin-top: -12px; opacity: .3;
} }
.drag-trigger:hover { .drag-trigger:hover {
cursor: move; cursor: move;
border-right-color: #5e4fa2; opacity: .6;
} }
.tint { .tint {
@ -1684,7 +1684,7 @@ ul.share-buttons li {
} }
ul.share-buttons img { ul.share-buttons img {
width: 18px; width: 2em;
} }
input[type="checkbox"] { input[type="checkbox"] {

View file

@ -1912,22 +1912,21 @@
<div id="aboutContent" class="tabcontent"> <div id="aboutContent" class="tabcontent">
<p><a href="https://github.com/Azgaar/Fantasy-Map-Generator" target="_blank">Fantasy Map Generator</a> is a free <a href="https://github.com/Azgaar/Fantasy-Map-Generator/blob/master/LICENSE" target="_blank">open source</a> tool which procedurally generates fantasy maps. You may use auto-generated maps as they are, edit them or even create a new map from scratch. Check out the <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Quick-Start-Tutorial" target="_blank">quick start tutorial</a>, <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Q&A" target="_blank">Q&A</a> and <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys" target="_blank">hotkeys</a> for guidance.</p> <p><a href="https://github.com/Azgaar/Fantasy-Map-Generator" target="_blank">Fantasy Map Generator</a> is a free <a href="https://github.com/Azgaar/Fantasy-Map-Generator/blob/master/LICENSE" target="_blank">open source</a> tool which procedurally generates fantasy maps. You may use auto-generated maps as they are, edit them or even create a new map from scratch. Check out the <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Quick-Start-Tutorial" target="_blank">quick start tutorial</a>, <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Q&A" target="_blank">Q&A</a> and <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys" target="_blank">hotkeys</a> for guidance.</p>
<p>Join our <a href='https://discordapp.com/invite/X7E84HU' target='_blank'>Discord server</a> and <a href="https://www.reddit.com/r/FantasyMapGenerator/" target="_blank">Reddit community</a> to ask questions, get help and share created maps. You may support the project on <a href='https://www.patreon.com/azgaar' target='_blank'>Patreon</a>.</p> <p>Join our <a href='https://discordapp.com/invite/X7E84HU' target='_blank'>Discord server</a> and <a href="https://www.reddit.com/r/FantasyMapGenerator/" target="_blank">Reddit community</a> to ask questions, get help and share maps.</p>
<p>The project is under active development. Creator and main maintainer: Azgaar. For older versions see the <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog" target="_blank">changelog</a>. To track the development progress see the <a href="https://trello.com/b/7x832DG4/fantasy-map-generator" target="_blank">devboard</a>. Please report bugs <a href="https://github.com/Azgaar/Fantasy-Map-Generator/issues" target="_blank">here</a>. You can also contact me directly via <a href="mailto:azgaar.fmg@yandex.by" target="_blank">email</a>.</p> <p>The project is under active development. Creator and main maintainer: Azgaar. To track the development progress see the <a href="https://trello.com/b/7x832DG4/fantasy-map-generator" target="_blank">devboard</a>. For older versions see the <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog" target="_blank">changelog</a>. Please report bugs <a href="https://github.com/Azgaar/Fantasy-Map-Generator/issues" target="_blank">here</a>. You can also contact me directly via <a href="mailto:azgaar.fmg@yandex.by" target="_blank">email</a>.</p>
<p>Special thanks to all supporters on Patreon! <i data-tip="Click to see supporters names" class="collapsible icon-down-open pointer"></i></p> <div style="background-color: #e85b46; padding: .4em; width: max-content; margin: .6em auto 0 auto; border: 1px solid #943838">
<p style="display:none">Patreon Supporters: Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, <a href="https://www.patreon.com/azgaar" target="_blank" style="color: white; text-decoration: none; font-family: sans-serif">
Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, <div>
Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, <div style="width: .8em; display: inline-block; padding: 0 .2em; fill: white">
Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, <svg viewBox="0 0 569 546">
Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), <circle cx="362.589996" cy="204.589996" data-fill="1" id="Oval" r="204.589996"></circle>
Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, <rect data-fill="2" height="545.799988" id="Rectangle" width="100" x="0" y="0"></rect>
Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, </svg>
Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, </div>SUPPORT ON PATREON
Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, </div>
Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, </a>
FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, </div>
PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, <p>Special thanks to <a data-tip="Click to see list of supporters" onclick="showSupporters()">all supporters</a> on Patreon!</p>
Ben Craigie, Alex Smolin and many others!</p>
<ul class="share-buttons"> <ul class="share-buttons">
<li><a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fazgaar.github.io%2FFantasy-Map-Generator%2F&quote=" data-tip="Share on Facebook" target="_blank"><img alt="Share on Facebook" src="images/Facebook.png" /></a></li> <li><a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fazgaar.github.io%2FFantasy-Map-Generator%2F&quote=" data-tip="Share on Facebook" target="_blank"><img alt="Share on Facebook" src="images/Facebook.png" /></a></li>
@ -3004,9 +3003,7 @@
<input id="namesbaseMin" data-tip="Recommended minimum name length" type="number" min=2 max=100> <input id="namesbaseMin" data-tip="Recommended minimum name length" type="number" min=2 max=100>
<input id="namesbaseMax" data-tip="Recommended maximum name length" type="number" min=2 value=10> <input id="namesbaseMax" data-tip="Recommended maximum name length" type="number" min=2 value=10>
<span>Double: </span> <span>Double: </span>
<input id="namesbaseDouble" data-tip="Populate with letters that can used twice in a row" autocorrect="off" spellcheck="false" style="width:5em"> <input id="namesbaseDouble" data-tip="Populate with letters that can used twice in a row (geminates)" autocorrect="off" spellcheck="false" style="width:10em">
<span>Multi: </span>
<input id="namesbaseMulti" data-tip="Multi-word names rate. 1 - allow all multi-word names, 0 - all names should spelled as a single word" type="number" min=0 max=1 step=.1 value=0 style="width:3.6em">
</div> </div>
<fieldset> <fieldset>
<legend>Generated examples: </legend> <legend>Generated examples: </legend>

View file

@ -48,7 +48,7 @@ function lineclip(points, bbox, result) {
} }
// Sutherland-Hodgeman polygon clipping algorithm // Sutherland-Hodgeman polygon clipping algorithm
function polygonclip(points, bbox, secure = false) { function polygonclip(points, bbox, secure = 0) {
var result, edge, prev, prevInside, inter, i, p, inside; var result, edge, prev, prevInside, inter, i, p, inside;
// clip against each side of the clip rectangle // clip against each side of the clip rectangle
@ -62,10 +62,10 @@ function polygonclip(points, bbox, secure = false) {
inside = !(bitCode(p, bbox) & edge); inside = !(bitCode(p, bbox) & edge);
inter = inside !== prevInside; // segment goes through the clip window inter = inside !== prevInside; // segment goes through the clip window
if (secure && inter && inside && i) result.push(points[i-1]); // add previous point in secure mode (to get a correct d3 curve) const pi = intersect(prev, p, edge, bbox);
if (inter) result.push(intersect(prev, p, edge, bbox)); // add an intersection point if (inter) result.push(pi); // add an intersection point
if (secure && inter) result.push(pi, pi); // add additional intersection points to secure correct d3 curve
if (inside) result.push(p); // add a point if it's inside if (inside) result.push(p); // add a point if it's inside
else if (secure && prevInside) result.push(p); // // add an outside point if in secure mode (to get a correct d3 curve)
prev = p; prev = p;
prevInside = inside; prevInside = inside;
@ -73,6 +73,7 @@ function polygonclip(points, bbox, secure = false) {
points = result; points = result;
if (!points.length) break; if (!points.length) break;
} }
//result.forEach(p => debug.append("circle").attr("cx", p[0]).attr("cy", p[1]).attr("r", .6).attr("fill", "red"));
return result; return result;
} }

2
libs/three.min.js vendored
View file

@ -88,7 +88,7 @@ var t=a.getRenderTarget();return{isWebGL2:c.isWebGL2,shaderID:h,precision:m,inst
emissiveMap:!!b.emissiveMap,emissiveMapEncoding:d(b.emissiveMap,a.gammaInput),bumpMap:!!b.bumpMap,normalMap:!!b.normalMap,objectSpaceNormalMap:1===b.normalMapType,tangentSpaceNormalMap:0===b.normalMapType,clearcoatNormalMap:!!b.clearcoatNormalMap,displacementMap:!!b.displacementMap,roughnessMap:!!b.roughnessMap,metalnessMap:!!b.metalnessMap,specularMap:!!b.specularMap,alphaMap:!!b.alphaMap,gradientMap:!!b.gradientMap,sheen:!!b.sheen,combine:b.combine,vertexTangents:b.normalMap&&b.vertexTangents,vertexColors:b.vertexColors, emissiveMap:!!b.emissiveMap,emissiveMapEncoding:d(b.emissiveMap,a.gammaInput),bumpMap:!!b.bumpMap,normalMap:!!b.normalMap,objectSpaceNormalMap:1===b.normalMapType,tangentSpaceNormalMap:0===b.normalMapType,clearcoatNormalMap:!!b.clearcoatNormalMap,displacementMap:!!b.displacementMap,roughnessMap:!!b.roughnessMap,metalnessMap:!!b.metalnessMap,specularMap:!!b.specularMap,alphaMap:!!b.alphaMap,gradientMap:!!b.gradientMap,sheen:!!b.sheen,combine:b.combine,vertexTangents:b.normalMap&&b.vertexTangents,vertexColors:b.vertexColors,
vertexUvs:!!b.map||!!b.bumpMap||!!b.normalMap||!!b.specularMap||!!b.alphaMap||!!b.emissiveMap||!!b.roughnessMap||!!b.metalnessMap||!!b.clearcoatNormalMap,fog:!!q,useFog:b.fog,fogExp2:q&&q.isFogExp2,flatShading:b.flatShading,sizeAttenuation:b.sizeAttenuation,logarithmicDepthBuffer:c.logarithmicDepthBuffer,skinning:b.skinning&&0<l,maxBones:l,useVertexTexture:c.floatVertexTextures,morphTargets:b.morphTargets,morphNormals:b.morphNormals,maxMorphTargets:a.maxMorphTargets,maxMorphNormals:a.maxMorphNormals, vertexUvs:!!b.map||!!b.bumpMap||!!b.normalMap||!!b.specularMap||!!b.alphaMap||!!b.emissiveMap||!!b.roughnessMap||!!b.metalnessMap||!!b.clearcoatNormalMap,fog:!!q,useFog:b.fog,fogExp2:q&&q.isFogExp2,flatShading:b.flatShading,sizeAttenuation:b.sizeAttenuation,logarithmicDepthBuffer:c.logarithmicDepthBuffer,skinning:b.skinning&&0<l,maxBones:l,useVertexTexture:c.floatVertexTextures,morphTargets:b.morphTargets,morphNormals:b.morphNormals,maxMorphTargets:a.maxMorphTargets,maxMorphNormals:a.maxMorphNormals,
numDirLights:e.directional.length,numPointLights:e.point.length,numSpotLights:e.spot.length,numRectAreaLights:e.rectArea.length,numHemiLights:e.hemi.length,numDirLightShadows:e.directionalShadowMap.length,numPointLightShadows:e.pointShadowMap.length,numSpotLightShadows:e.spotShadowMap.length,numClippingPlanes:u,numClipIntersection:k,dithering:b.dithering,shadowMapEnabled:a.shadowMap.enabled&&0<g.length,shadowMapType:a.shadowMap.type,toneMapping:b.toneMapped?a.toneMapping:0,physicallyCorrectLights:a.physicallyCorrectLights, numDirLights:e.directional.length,numPointLights:e.point.length,numSpotLights:e.spot.length,numRectAreaLights:e.rectArea.length,numHemiLights:e.hemi.length,numDirLightShadows:e.directionalShadowMap.length,numPointLightShadows:e.pointShadowMap.length,numSpotLightShadows:e.spotShadowMap.length,numClippingPlanes:u,numClipIntersection:k,dithering:b.dithering,shadowMapEnabled:a.shadowMap.enabled&&0<g.length,shadowMapType:a.shadowMap.type,toneMapping:b.toneMapped?a.toneMapping:0,physicallyCorrectLights:a.physicallyCorrectLights,
premultipliedAlpha:b.premultipliedAlpha,alphaTest:b.alphaTest,doubleSided:2===b.side,flipSided:1===b.side,depthPacking:void 0!==b.depthPacking?b.depthPacking:!1}};this.getProgramCode=function(b,c){var d=[];c.shaderID?d.push(c.shaderID):(d.push(b.fragmentShader),d.push(b.vertexShader));if(void 0!==b.defines)for(var e in b.defines)d.push(e),d.push(b.defines[e]);for(e=0;e<g.length;e++)d.push(c[g[e]]);d.push(b.onBeforeCompile.toString());d.push(a.gammaOutput);d.push(a.gammaFactor);return d.join()};this.acquireProgram= premultipliedAlpha:b.premultipliedAlpha,alphaTest:b.alphaTest,doubleSided:2===b.side,flipSided:1===b.side,depthPacking:void 0!==b.depthPacking?b.depthPacking:!1}};this.getProgramCode=function(b,c){var d=[];c.shaderID?d.push(c.shaderID):(d.push(b.fragmentShader),d.push(b.vertexShader));if(void 0!==b.defines)for(var e in b.defines)d.push(e),d.push(b.defines[e]);for(e=0;e<g.length;e++)d.push(c[g[e]]);d.push(b.onBeforeCompile.toString());d.push(a.gammaOutput);d.push(a.gammaFactor);return d.join("")};this.acquireProgram=
function(c,d,f,g){for(var h,l=0,m=e.length;l<m;l++){var q=e[l];if(q.code===g){h=q;++h.usedTimes;break}}void 0===h&&(h=new Wj(a,b,g,c,d,f),e.push(h));return h};this.releaseProgram=function(a){if(0===--a.usedTimes){var b=e.indexOf(a);e[b]=e[e.length-1];e.pop();a.destroy()}};this.programs=e}function Zj(){var a=new WeakMap;return{get:function(b){var c=a.get(b);void 0===c&&(c={},a.set(b,c));return c},remove:function(b){a.delete(b)},update:function(b,c,d){a.get(b)[c]=d},dispose:function(){a=new WeakMap}}} function(c,d,f,g){for(var h,l=0,m=e.length;l<m;l++){var q=e[l];if(q.code===g){h=q;++h.usedTimes;break}}void 0===h&&(h=new Wj(a,b,g,c,d,f),e.push(h));return h};this.releaseProgram=function(a){if(0===--a.usedTimes){var b=e.indexOf(a);e[b]=e[e.length-1];e.pop();a.destroy()}};this.programs=e}function Zj(){var a=new WeakMap;return{get:function(b){var c=a.get(b);void 0===c&&(c={},a.set(b,c));return c},remove:function(b){a.delete(b)},update:function(b,c,d){a.get(b)[c]=d},dispose:function(){a=new WeakMap}}}
function ak(a,b){return a.groupOrder!==b.groupOrder?a.groupOrder-b.groupOrder:a.renderOrder!==b.renderOrder?a.renderOrder-b.renderOrder:a.program!==b.program?a.program.id-b.program.id:a.material.id!==b.material.id?a.material.id-b.material.id:a.z!==b.z?a.z-b.z:a.id-b.id}function bk(a,b){return a.groupOrder!==b.groupOrder?a.groupOrder-b.groupOrder:a.renderOrder!==b.renderOrder?a.renderOrder-b.renderOrder:a.z!==b.z?b.z-a.z:a.id-b.id}function Hh(){function a(a,d,e,m,q,u){var g=b[c];void 0===g?(g={id:a.id, function ak(a,b){return a.groupOrder!==b.groupOrder?a.groupOrder-b.groupOrder:a.renderOrder!==b.renderOrder?a.renderOrder-b.renderOrder:a.program!==b.program?a.program.id-b.program.id:a.material.id!==b.material.id?a.material.id-b.material.id:a.z!==b.z?a.z-b.z:a.id-b.id}function bk(a,b){return a.groupOrder!==b.groupOrder?a.groupOrder-b.groupOrder:a.renderOrder!==b.renderOrder?a.renderOrder-b.renderOrder:a.z!==b.z?b.z-a.z:a.id-b.id}function Hh(){function a(a,d,e,m,q,u){var g=b[c];void 0===g?(g={id:a.id,
object:a,geometry:d,material:e,program:e.program||f,groupOrder:m,renderOrder:a.renderOrder,z:q,group:u},b[c]=g):(g.id=a.id,g.object=a,g.geometry=d,g.material=e,g.program=e.program||f,g.groupOrder=m,g.renderOrder=a.renderOrder,g.z=q,g.group=u);c++;return g}var b=[],c=0,d=[],e=[],f={id:-1};return{opaque:d,transparent:e,init:function(){c=0;d.length=0;e.length=0},push:function(b,c,f,m,q,u){b=a(b,c,f,m,q,u);(!0===f.transparent?e:d).push(b)},unshift:function(b,c,f,m,q,u){b=a(b,c,f,m,q,u);(!0===f.transparent? object:a,geometry:d,material:e,program:e.program||f,groupOrder:m,renderOrder:a.renderOrder,z:q,group:u},b[c]=g):(g.id=a.id,g.object=a,g.geometry=d,g.material=e,g.program=e.program||f,g.groupOrder=m,g.renderOrder=a.renderOrder,g.z=q,g.group=u);c++;return g}var b=[],c=0,d=[],e=[],f={id:-1};return{opaque:d,transparent:e,init:function(){c=0;d.length=0;e.length=0},push:function(b,c,f,m,q,u){b=a(b,c,f,m,q,u);(!0===f.transparent?e:d).push(b)},unshift:function(b,c,f,m,q,u){b=a(b,c,f,m,q,u);(!0===f.transparent?

View file

@ -952,6 +952,8 @@ function drawCoastline() {
const waterMask = defs.select("#water"); const waterMask = defs.select("#water");
lineGen.curve(d3.curveBasisClosed); lineGen.curve(d3.curveBasisClosed);
zoom.translateExtent([[-200, -200],[graphWidth+200, graphHeight+200]]);
for (const i of cells.i) { for (const i of cells.i) {
const startFromEdge = !i && cells.h[i] >= 20; const startFromEdge = !i && cells.h[i] >= 20;
if (!startFromEdge && cells.t[i] !== -1 && cells.t[i] !== 1) continue; // non-edge cell if (!startFromEdge && cells.t[i] !== -1 && cells.t[i] !== 1) continue; // non-edge cell

View file

@ -691,7 +691,7 @@
const naval = states[f].type === "Naval" && states[t].type === "Naval" && cells.f[states[f].center] !== cells.f[states[t].center]; const naval = states[f].type === "Naval" && states[t].type === "Naval" && cells.f[states[f].center] !== cells.f[states[t].center];
const neib = naval ? false : states[f].neighbors.includes(t); const neib = naval ? false : states[f].neighbors.includes(t);
const neibOfNeib = naval || neib ? false : states[f].neighbors.map(n => states[n].neighbors).join().includes(t); const neibOfNeib = naval || neib ? false : states[f].neighbors.map(n => states[n].neighbors).join("").includes(t);
let status = naval ? rw(navals) : neib ? rw(neibs) : neibOfNeib ? rw(neibsOfNeibs) : rw(far); let status = naval ? rw(navals) : neib ? rw(neibs) : neibOfNeib ? rw(neibsOfNeibs) : rw(far);

View file

@ -8,25 +8,41 @@
// calculate Markov chain for a namesbase // calculate Markov chain for a namesbase
const calculateChain = function(string) { const calculateChain = function(string) {
const chain = []; const chain = [], array = string.split(",");
const d = string.toLowerCase().replace(/,/g, " ");
for (let i = -1, str = ""; i < d.length - 2; i += str.length, str = "") { for (const n of array) {
let v = 0, f = " "; let name = n.trim().toLowerCase();
const basic = !(/[^\u0000-\u007f]/.test(name)); // basic chars and English rules can be applied
for (let c=i+1; str.length < 5; c++) { // split word into pseudo-syllables
if (d[c] === undefined) break; for (let i=-1, syllable = ""; i < name.length; i += (syllable.length||1), syllable = "") {
str += d[c]; let prev = name[i] || ""; // pre-onset letter
if (str === " ") break; let v = 0; // 0 if no vowels in syllable
if (d[c] !== "o" && d[c] !== "e" && vowel(d[c]) && d[c+1] === d[c]) break;
if (d[c+2] === " ") {str += d[c+1]; break;} for (let c=i+1; name[c] && syllable.length < 5; c++) {
if (vowel(d[c])) v++; const that = name[c], next = name[c+1]; // next char
if (v && vowel(d[c+2])) break; syllable += that;
if (syllable === " " || syllable === "-") break; // syllable starts with space or hyphen
if (!next || next === " " || next === "-") break; // no need to check
if (vowel(that)) v = 1; // check if letter is vowel
// do not split some diphthongs
if (that === "y" && next === "e") continue; // 'ye'
if (basic) { // English-like
if (that === "o" && next === "o") continue; // 'oo'
if (that === "e" && next === "e") continue; // 'ee'
if (that === "a" && next === "e") continue; // 'ae'
if (that === "c" && next === "h") continue; // 'ch'
} }
if (i >= 0) f = d[i]; if (vowel(that) === next) break; // two same vowels in a row
if (chain[f] === undefined) chain[f] = []; if (v && vowel(name[c+2])) break; // syllable has vowel and additional vowel is expected soon
chain[f].push(str); }
if (chain[prev] === undefined) chain[prev] = [];
chain[prev].push(syllable);
}
} }
return chain; return chain;
@ -39,7 +55,7 @@
const clearChains = () => chains = []; const clearChains = () => chains = [];
// generate name using Markov's chain // generate name using Markov's chain
const getBase = function(base, min, max, dupl, multi) { const getBase = function(base, min, max, dupl) {
if (base === undefined) {console.error("Please define a base"); return;} if (base === undefined) {console.error("Please define a base"); return;}
if (!chains[base]) updateChain(base); if (!chains[base]) updateChain(base);
@ -53,31 +69,26 @@
if (!min) min = nameBases[base].min; if (!min) min = nameBases[base].min;
if (!max) max = nameBases[base].max; if (!max) max = nameBases[base].max;
if (dupl !== "") dupl = nameBases[base].d; if (dupl !== "") dupl = nameBases[base].d;
if (!multi) multi = nameBases[base].m;
let v = data[" "], cur = v[rand(v.length-1)], w = ""; let v = data[""], cur = ra(v), w = "";
for (let i=0; i < 21; i++) { for (let i=0; i < 20; i++) {
if (cur === " " && Math.random() > multi) { if (cur === "") { // end of word
if (w.length < min) {cur = ""; w = ""; v = data[""];} else break; if (w.length < min) {cur = ""; w = ""; v = data[""];} else break;
} else { } else {
if ((w+cur).length > max) { if (w.length + cur.length > max) { // word too long
if (w.length < min) w += cur; if (w.length < min) w += cur;
break; break;
} else if (cur === " " && w.length+1 < min) { } else v = data[last(cur)] || data[""];
cur = "";
v = data[" "];
} else {
v = data[cur.slice(-1)] || data[" "];
}
} }
w += cur; w += cur;
cur = v[rand(v.length - 1)]; cur = ra(v);
} }
// parse word to get a final name // parse word to get a final name
const l = last(w); // last letter const l = last(w); // last letter
if (l === "'" || l === " ") w = w.slice(0,-1); // not allow apostrophe and space at the end if (l === "'" || l === " " || l === "-") w = w.slice(0,-1); // not allow some characters at the end
const basic = !(/[^\u0000-\u007f]/.test(w)); // true if word has only basic characters
let name = [...w].reduce(function(r, c, i, d) { let name = [...w].reduce(function(r, c, i, d) {
if (c === d[i+1] && !dupl.includes(c)) return r; // duplication is not allowed if (c === d[i+1] && !dupl.includes(c)) return r; // duplication is not allowed
@ -86,8 +97,8 @@
if (r.slice(-1) === " ") return r + c.toUpperCase(); // capitalize letter after space if (r.slice(-1) === " ") return r + c.toUpperCase(); // capitalize letter after space
if (r.slice(-1) === "-") return r + c.toUpperCase(); // capitalize letter after hyphen if (r.slice(-1) === "-") return r + c.toUpperCase(); // capitalize letter after hyphen
if (c === "a" && d[i+1] === "e") return r; // "ae" => "e" if (c === "a" && d[i+1] === "e") return r; // "ae" => "e"
if (i+1 < d.length && !vowel(c) && !vowel(d[i-1]) && !vowel(d[i+1])) return r; // remove consonant between 2 consonants if (basic && i+1 < d.length && !vowel(c) && !vowel(d[i-1]) && !vowel(d[i+1])) return r; // remove consonant between 2 consonants
if (i+2 < d.length && c === d[i+1] && c === d[i+2]) return r; // remove tree same letters in a row if (i+2 < d.length && c === d[i+1] && c === d[i+2]) return r; // remove three same letters in a row
return r + c; return r + c;
}, ""); }, "");
@ -95,7 +106,7 @@
if (name.split(" ").some(part => part.length < 2)) name = name.split(" ").map((p,i) => i ? p.toLowerCase() : p).join(""); if (name.split(" ").some(part => part.length < 2)) name = name.split(" ").map((p,i) => i ? p.toLowerCase() : p).join("");
if (name.length < 2) { if (name.length < 2) {
console.error("Name is too short! Random name to be selected"); console.error("Name is too short! Random name will be selected");
name = ra(nameBases[base].b.split(",")); name = ra(nameBases[base].b.split(","));
} }
@ -103,10 +114,10 @@
} }
// generate name for culture // generate name for culture
const getCulture = function(culture, min, max, dupl, multi) { const getCulture = function(culture, min, max, dupl) {
if (culture === undefined) {console.error("Please define a culture"); return;} if (culture === undefined) {console.error("Please define a culture"); return;}
const base = pack.cultures[culture].base; const base = pack.cultures[culture].base;
return getBase(base, min, max, dupl, multi); return getBase(base, min, max, dupl);
} }
// generate short name for culture // generate short name for culture
@ -206,7 +217,7 @@
} }
const getNameBases = function() { const getNameBases = function() {
// name, min length, max length, letters to allow duplication, multi-word name rate // name, min length, max length, letters to allow duplication, multi-word name rate [deprecated]
return [ return [
// real-world bases by Azgaar: // real-world bases by Azgaar:
{name: "German", i: 0, min: 5, max: 12, d: "lt", m: 0, b: "Achern,Aichhalden,Aitern,Albbruck,Alpirsbach,Altensteig,Althengstett,Appenweier,Auggen,Wildbad,Badenen,Badenweiler,Baiersbronn,Ballrechten,Bellingen,Berghaupten,Bernau,Biberach,Biederbach,Binzen,Birkendorf,Birkenfeld,Bischweier,Blumberg,Bollen,Bollschweil,Bonndorf,Bosingen,Braunlingen,Breisach,Breisgau,Breitnau,Brigachtal,Buchenbach,Buggingen,Buhl,Buhlertal,Calw,Dachsberg,Dobel,Donaueschingen,Dornhan,Dornstetten,Dottingen,Dunningen,Durbach,Durrheim,Ebhausen,Ebringen,Efringen,Egenhausen,Ehrenkirchen,Ehrsberg,Eimeldingen,Eisenbach,Elzach,Elztal,Emmendingen,Endingen,Engelsbrand,Enz,Enzklosterle,Eschbronn,Ettenheim,Ettlingen,Feldberg,Fischerbach,Fischingen,Fluorn,Forbach,Freiamt,Freiburg,Freudenstadt,Friedenweiler,Friesenheim,Frohnd,Furtwangen,Gaggenau,Geisingen,Gengenbach,Gernsbach,Glatt,Glatten,Glottertal,Gorwihl,Gottenheim,Grafenhausen,Grenzach,Griesbach,Gutach,Gutenbach,Hag,Haiterbach,Hardt,Harmersbach,Hasel,Haslach,Hausach,Hausen,Hausern,Heitersheim,Herbolzheim,Herrenalb,Herrischried,Hinterzarten,Hochenschwand,Hofen,Hofstetten,Hohberg,Horb,Horben,Hornberg,Hufingen,Ibach,Ihringen,Inzlingen,Kandern,Kappel,Kappelrodeck,Karlsbad,Karlsruhe,Kehl,Keltern,Kippenheim,Kirchzarten,Konigsfeld,Krozingen,Kuppenheim,Kussaberg,Lahr,Lauchringen,Lauf,Laufenburg,Lautenbach,Lauterbach,Lenzkirch,Liebenzell,Loffenau,Loffingen,Lorrach,Lossburg,Mahlberg,Malsburg,Malsch,March,Marxzell,Marzell,Maulburg,Monchweiler,Muhlenbach,Mullheim,Munstertal,Murg,Nagold,Neubulach,Neuenburg,Neuhausen,Neuried,Neuweiler,Niedereschach,Nordrach,Oberharmersbach,Oberkirch,Oberndorf,Oberbach,Oberried,Oberwolfach,Offenburg,Ohlsbach,Oppenau,Ortenberg,otigheim,Ottenhofen,Ottersweier,Peterstal,Pfaffenweiler,Pfalzgrafenweiler,Pforzheim,Rastatt,Renchen,Rheinau,Rheinfelden,Rheinmunster,Rickenbach,Rippoldsau,Rohrdorf,Rottweil,Rummingen,Rust,Sackingen,Sasbach,Sasbachwalden,Schallbach,Schallstadt,Schapbach,Schenkenzell,Schiltach,Schliengen,Schluchsee,Schomberg,Schonach,Schonau,Schonenberg,Schonwald,Schopfheim,Schopfloch,Schramberg,Schuttertal,Schwenningen,Schworstadt,Seebach,Seelbach,Seewald,Sexau,Simmersfeld,Simonswald,Sinzheim,Solden,Staufen,Stegen,Steinach,Steinen,Steinmauern,Straubenhardt,Stuhlingen,Sulz,Sulzburg,Teinach,Tiefenbronn,Tiengen,Titisee,Todtmoos,Todtnau,Todtnauberg,Triberg,Tunau,Tuningen,uhlingen,Unterkirnach,Reichenbach,Utzenfeld,Villingen,Villingendorf,Vogtsburg,Vohrenbach,Waldachtal,Waldbronn,Waldkirch,Waldshut,Wehr,Weil,Weilheim,Weisenbach,Wembach,Wieden,Wiesental,Wildberg,Winzeln,Wittlingen,Wittnau,Wolfach,Wutach,Wutoschingen,Wyhlen,Zavelstein"}, {name: "German", i: 0, min: 5, max: 12, d: "lt", m: 0, b: "Achern,Aichhalden,Aitern,Albbruck,Alpirsbach,Altensteig,Althengstett,Appenweier,Auggen,Wildbad,Badenen,Badenweiler,Baiersbronn,Ballrechten,Bellingen,Berghaupten,Bernau,Biberach,Biederbach,Binzen,Birkendorf,Birkenfeld,Bischweier,Blumberg,Bollen,Bollschweil,Bonndorf,Bosingen,Braunlingen,Breisach,Breisgau,Breitnau,Brigachtal,Buchenbach,Buggingen,Buhl,Buhlertal,Calw,Dachsberg,Dobel,Donaueschingen,Dornhan,Dornstetten,Dottingen,Dunningen,Durbach,Durrheim,Ebhausen,Ebringen,Efringen,Egenhausen,Ehrenkirchen,Ehrsberg,Eimeldingen,Eisenbach,Elzach,Elztal,Emmendingen,Endingen,Engelsbrand,Enz,Enzklosterle,Eschbronn,Ettenheim,Ettlingen,Feldberg,Fischerbach,Fischingen,Fluorn,Forbach,Freiamt,Freiburg,Freudenstadt,Friedenweiler,Friesenheim,Frohnd,Furtwangen,Gaggenau,Geisingen,Gengenbach,Gernsbach,Glatt,Glatten,Glottertal,Gorwihl,Gottenheim,Grafenhausen,Grenzach,Griesbach,Gutach,Gutenbach,Hag,Haiterbach,Hardt,Harmersbach,Hasel,Haslach,Hausach,Hausen,Hausern,Heitersheim,Herbolzheim,Herrenalb,Herrischried,Hinterzarten,Hochenschwand,Hofen,Hofstetten,Hohberg,Horb,Horben,Hornberg,Hufingen,Ibach,Ihringen,Inzlingen,Kandern,Kappel,Kappelrodeck,Karlsbad,Karlsruhe,Kehl,Keltern,Kippenheim,Kirchzarten,Konigsfeld,Krozingen,Kuppenheim,Kussaberg,Lahr,Lauchringen,Lauf,Laufenburg,Lautenbach,Lauterbach,Lenzkirch,Liebenzell,Loffenau,Loffingen,Lorrach,Lossburg,Mahlberg,Malsburg,Malsch,March,Marxzell,Marzell,Maulburg,Monchweiler,Muhlenbach,Mullheim,Munstertal,Murg,Nagold,Neubulach,Neuenburg,Neuhausen,Neuried,Neuweiler,Niedereschach,Nordrach,Oberharmersbach,Oberkirch,Oberndorf,Oberbach,Oberried,Oberwolfach,Offenburg,Ohlsbach,Oppenau,Ortenberg,otigheim,Ottenhofen,Ottersweier,Peterstal,Pfaffenweiler,Pfalzgrafenweiler,Pforzheim,Rastatt,Renchen,Rheinau,Rheinfelden,Rheinmunster,Rickenbach,Rippoldsau,Rohrdorf,Rottweil,Rummingen,Rust,Sackingen,Sasbach,Sasbachwalden,Schallbach,Schallstadt,Schapbach,Schenkenzell,Schiltach,Schliengen,Schluchsee,Schomberg,Schonach,Schonau,Schonenberg,Schonwald,Schopfheim,Schopfloch,Schramberg,Schuttertal,Schwenningen,Schworstadt,Seebach,Seelbach,Seewald,Sexau,Simmersfeld,Simonswald,Sinzheim,Solden,Staufen,Stegen,Steinach,Steinen,Steinmauern,Straubenhardt,Stuhlingen,Sulz,Sulzburg,Teinach,Tiefenbronn,Tiengen,Titisee,Todtmoos,Todtnau,Todtnauberg,Triberg,Tunau,Tuningen,uhlingen,Unterkirnach,Reichenbach,Utzenfeld,Villingen,Villingendorf,Vogtsburg,Vohrenbach,Waldachtal,Waldbronn,Waldkirch,Waldshut,Wehr,Weil,Weilheim,Weisenbach,Wembach,Wieden,Wiesental,Wildberg,Winzeln,Wittlingen,Wittnau,Wolfach,Wutach,Wutoschingen,Wyhlen,Zavelstein"},

View file

@ -28,16 +28,21 @@
if (!start) continue; if (!start) continue;
used[i] = 1; used[i] = 1;
const chain = connectVertices(start, t); // vertices chain to form a path const chain = connectVertices(start, t); // vertices chain to form a path
const relaxation = 1 + t * -2; // select only n-th point if (chain.length < 4) continue;
const relaxed = chain.filter((v, i) => i % relaxation === 0 || vertices.c[v].some(c => c >= pointsN)); const relax = 1 + t * -2; // select only n-th point
const relaxed = chain.filter((v, i) => !(i%relax) || vertices.c[v].some(c => c >= pointsN));
if (relaxed.length < 4) continue;
const points = clipPoly(relaxed.map(v => vertices.p[v]), 1); const points = clipPoly(relaxed.map(v => vertices.p[v]), 1);
if (relaxed.length >= 3) chains.push([t, points]); const inside = d3.polygonContains(points, grid.points[i]);
chains.push([t, points, inside]);
} }
const bbox = `M0,0h${graphWidth}v${graphHeight}h${-graphWidth}Z`;
for (const t of limits) { for (const t of limits) {
const path = chains.filter(c => c[0] === t).map(c => round(lineGen(c[1]))).join(); const layer = chains.filter(c => c[0] === t);
let path = layer.map(c => round(lineGen(c[1]))).join("");
if (layer.every(c => !c[2])) path = bbox + path; // add outer ring if all segments are outside (works not for all cases)
if (path) oceanLayers.append("path").attr("d", path).attr("fill", "#ecf2f9").style("opacity", opacity); if (path) oceanLayers.append("path").attr("d", path).attr("fill", "#ecf2f9").style("opacity", opacity);
// For each layer there should outer ring. If no, layer will be upside down. Need to fix it in the future
} }
// find eligible cell vertex to start path detection // find eligible cell vertex to start path detection

View file

@ -326,6 +326,7 @@ async function loadFromCloud() {
function saveGeoJSON_Cells() { function saveGeoJSON_Cells() {
let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n";
const cells = pack.cells, v = pack.vertices; const cells = pack.cells, v = pack.vertices;
const getPopulation = i => {const [r, u] = getCellPopulation(i); return rn(r+u)};
cells.i.forEach(i => { cells.i.forEach(i => {
data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [["; data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [[";
@ -340,13 +341,13 @@ function saveGeoJSON_Cells() {
data += "["+x+","+y+"]"; data += "["+x+","+y+"]";
data += "]] },\n \"properties\": {\n"; data += "]] },\n \"properties\": {\n";
let height = parseInt(getFriendlyHeight([cells.p[i][0],cells.p[i][1]])); const height = parseInt(getFriendlyHeight([cells.p[i][0],cells.p[i][1]]));
data += " \"id\": \""+i+"\",\n"; data += " \"id\": \""+i+"\",\n";
data += " \"height\": \""+height+"\",\n"; data += " \"height\": \""+height+"\",\n";
data += " \"biome\": \""+cells.biome[i]+"\",\n"; data += " \"biome\": \""+cells.biome[i]+"\",\n";
data += " \"type\": \""+pack.features[cells.f[i]].type+"\",\n"; data += " \"type\": \""+pack.features[cells.f[i]].type+"\",\n";
data += " \"population\": \""+getFriendlyPopulation(i)+"\",\n"; data += " \"population\": \""+getPopulation(i)+"\",\n";
data += " \"state\": \""+cells.state[i]+"\",\n"; data += " \"state\": \""+cells.state[i]+"\",\n";
data += " \"province\": \""+cells.province[i]+"\",\n"; data += " \"province\": \""+cells.province[i]+"\",\n";
data += " \"culture\": \""+cells.culture[i]+"\",\n"; data += " \"culture\": \""+cells.culture[i]+"\",\n";

View file

@ -2,45 +2,35 @@
function showEPForRoute(node) { function showEPForRoute(node) {
const points = []; const points = [];
var prevB=0, i=0, j=0, b=0, ma=0, mi=100, h=0;
debug.select("#controlPoints").selectAll("circle").each(function() { debug.select("#controlPoints").selectAll("circle").each(function() {
i = findCell(this.getAttribute("cx"), this.getAttribute("cy")); const i = findCell(this.getAttribute("cx"), this.getAttribute("cy"));
points.push(i); points.push(i);
}); });
const routeLen = node.getTotalLength() * distanceScaleInput.value; const routeLen = node.getTotalLength() * distanceScaleInput.value;
showElevationProfile(points, routeLen, false); showElevationProfile(points, routeLen, false);
} }
function showEPForRiver(node) { function showEPForRiver(node) {
const points = []; const points = [];
var prevB=0, i=0, j=0, b=0, ma=0, mi=100, h=0;
debug.select("#controlPoints").selectAll("circle").each(function() { debug.select("#controlPoints").selectAll("circle").each(function() {
i = findCell(this.getAttribute("cx"), this.getAttribute("cy")); const i = findCell(this.getAttribute("cx"), this.getAttribute("cy"));
points.push(i); points.push(i);
}); });
const riverLen = (node.getTotalLength() / 2) * distanceScaleInput.value; const riverLen = (node.getTotalLength() / 2) * distanceScaleInput.value;
showElevationProfile(points, riverLen, true); showElevationProfile(points, riverLen, true);
} }
function resizeElevationProfile() { function resizeElevationProfile() {
} }
function closeElevationProfile() {
modules.elevation = false;
}
function showElevationProfile(data, routeLen, isRiver) { function showElevationProfile(data, routeLen, isRiver) {
// data is an array of cell indexes, routeLen is the distance, isRiver should be true for rivers, false otherwise // data is an array of cell indexes, routeLen is the distance, isRiver should be true for rivers, false otherwise
document.getElementById("elevationGraph").innerHTML = ""; document.getElementById("elevationGraph").innerHTML = "";
$("#elevationProfile").dialog({ $("#elevationProfile").dialog({
title: "Elevation profile", resizable: false, title: "Elevation profile", resizable: false, width: window.width,
width: window.width,
close: closeElevationProfile,
position: {my: "left top", at: "left+20 bottom-240", of: window, collision: "fit"} position: {my: "left top", at: "left+20 bottom-240", of: window, collision: "fit"}
}); });

View file

@ -223,16 +223,20 @@ function getRiverInfo(id) {
return r ? `${r.name} ${r.type} (${id})` : "n/a"; return r ? `${r.name} ${r.type} (${id})` : "n/a";
} }
// get user-friendly (real-world) population value from map data function getCellPopulation(i) {
function getFriendlyPopulation(i) {
const rural = pack.cells.pop[i] * populationRate.value; const rural = pack.cells.pop[i] * populationRate.value;
const urban = pack.cells.burg[i] ? pack.burgs[pack.cells.burg[i]].population * populationRate.value * urbanization.value : 0; const urban = pack.cells.burg[i] ? pack.burgs[pack.cells.burg[i]].population * populationRate.value * urbanization.value : 0;
return [rural, urban];
}
// get user-friendly (real-world) population value from map data
function getFriendlyPopulation(i) {
const [rural, urban] = getCellPopulation(i);
return `${si(rural+urban)} (${si(rural)} rural, urban ${si(urban)})`; return `${si(rural+urban)} (${si(rural)} rural, urban ${si(urban)})`;
} }
function getPopulationTip(i) { function getPopulationTip(i) {
const rural = pack.cells.pop[i] * populationRate.value; const [rural, urban] = getCellPopulation(i);
const urban = pack.cells.burg[i] ? pack.burgs[pack.cells.burg[i]].population * populationRate.value * urbanization.value : 0;
return `Cell population: ${si(rural+urban)}; Rural: ${si(rural)}; Urban: ${si(urban)}`; return `Cell population: ${si(rural+urban)}; Rural: ${si(rural)}; Urban: ${si(urban)}`;
} }

View file

@ -260,7 +260,7 @@ function drawTemp() {
temperature.append("path").attr("d", `M0,0 h${svgWidth} v${svgHeight} h${-svgWidth} Z`).attr("fill", scheme(1 - (min - tMin) / delta)).attr("stroke", "none"); temperature.append("path").attr("d", `M0,0 h${svgWidth} v${svgHeight} h${-svgWidth} Z`).attr("fill", scheme(1 - (min - tMin) / delta)).attr("stroke", "none");
for (const t of isolines) { for (const t of isolines) {
const path = chains.filter(c => c[0] === t).map(c => round(lineGen(c[1]))).join(); const path = chains.filter(c => c[0] === t).map(c => round(lineGen(c[1]))).join("");
if (!path) continue; if (!path) continue;
const fill = scheme(1 - (t - tMin) / delta), stroke = d3.color(fill).darker(.2); const fill = scheme(1 - (t - tMin) / delta), stroke = d3.color(fill).darker(.2);
temperature.append("path").attr("d", path).attr("fill", fill).attr("stroke", stroke); temperature.append("path").attr("d", path).attr("fill", fill).attr("stroke", stroke);

View file

@ -16,7 +16,6 @@ function editNamesbase() {
document.getElementById("namesbaseMin").addEventListener("input", updateBaseMin); document.getElementById("namesbaseMin").addEventListener("input", updateBaseMin);
document.getElementById("namesbaseMax").addEventListener("input", updateBaseMax); document.getElementById("namesbaseMax").addEventListener("input", updateBaseMax);
document.getElementById("namesbaseDouble").addEventListener("input", updateBaseDublication); document.getElementById("namesbaseDouble").addEventListener("input", updateBaseDublication);
document.getElementById("namesbaseMulti").addEventListener("input", updateBaseMiltiwordRate);
document.getElementById("namesbaseAdd").addEventListener("click", namesbaseAdd); document.getElementById("namesbaseAdd").addEventListener("click", namesbaseAdd);
document.getElementById("namesbaseAnalize").addEventListener("click", analizeNamesbase); document.getElementById("namesbaseAnalize").addEventListener("click", analizeNamesbase);
document.getElementById("namesbaseDefault").addEventListener("click", namesbaseRestoreDefault); document.getElementById("namesbaseDefault").addEventListener("click", namesbaseRestoreDefault);
@ -46,7 +45,6 @@ function editNamesbase() {
document.getElementById("namesbaseMin").value = nameBases[base].min; document.getElementById("namesbaseMin").value = nameBases[base].min;
document.getElementById("namesbaseMax").value = nameBases[base].max; document.getElementById("namesbaseMax").value = nameBases[base].max;
document.getElementById("namesbaseDouble").value = nameBases[base].d; document.getElementById("namesbaseDouble").value = nameBases[base].d;
document.getElementById("namesbaseMulti").value = nameBases[base].m;
updateExamples(); updateExamples();
} }
@ -67,10 +65,9 @@ function editNamesbase() {
function updateNamesData() { function updateNamesData() {
const base = +document.getElementById("namesbaseSelect").value; const base = +document.getElementById("namesbaseSelect").value;
const b = document.getElementById("namesbaseTextarea").value.replace(/ /g, ""); const b = document.getElementById("namesbaseTextarea").value;
if (b.split(",").length < 3) { if (b.split(",").length < 3) {
tip("The names data provided is not correct", false, "error"); tip("The names data provided is too short of incorrect", false, "error");
document.getElementById("namesbaseTextarea").value = nameBases[base].b;
return; return;
} }
nameBases[base].b = b; nameBases[base].b = b;
@ -101,12 +98,6 @@ function editNamesbase() {
nameBases[base].d = this.value; nameBases[base].d = this.value;
} }
function updateBaseMiltiwordRate() {
if (isNaN(+this.value) || +this.value < 0 || +this.value > 1) {tip("Please provide a number within [0-1] range", false, "error"); return;}
const base = +document.getElementById("namesbaseSelect").value;
nameBases[base].m = +this.value;
}
function analizeNamesbase() { function analizeNamesbase() {
const string = document.getElementById("namesbaseTextarea").value; const string = document.getElementById("namesbaseTextarea").value;
if (!string) {tip("Names data field should not be empty", false, "error"); return;} if (!string) {tip("Names data field should not be empty", false, "error"); return;}
@ -174,7 +165,6 @@ function editNamesbase() {
document.getElementById("namesbaseMin").value = 5; document.getElementById("namesbaseMin").value = 5;
document.getElementById("namesbaseMax").value = 12; document.getElementById("namesbaseMax").value = 12;
document.getElementById("namesbaseDouble").value = ""; document.getElementById("namesbaseDouble").value = "";
document.getElementById("namesbaseMulti").value = 0;
document.getElementById("namesbaseExamples").innerHTML = "Please provide names data"; document.getElementById("namesbaseExamples").innerHTML = "Please provide names data";
} }

View file

@ -69,18 +69,11 @@ document.getElementById("options").querySelector("div.tab").addEventListener("cl
if (id === "aboutTab") aboutContent.style.display = "block"; if (id === "aboutTab") aboutContent.style.display = "block";
}); });
document.getElementById("options").querySelectorAll("i.collapsible").forEach(el => el.addEventListener("click", collapse)); // show popup with a list of Patreon supportes (updated manually, to be replaced with API call)
function collapse(e) { function showSupporters() {
const trigger = e.target; const supporters = "Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, Ben Craigie, Alex Smolin, Endwords";
const section = trigger.parentElement.nextElementSibling; alertMessage.innerHTML = "<ul style='column-count: 3; column-gap: 2em'>" + supporters.split(", ").sort().map(n => `<li>${n}</li>`).join("") + "</ul>";
$("#alert").dialog({resizable: false, title: "Patreon Supporters", width: "30vw", position: {my: "center", at: "center", of: "svg"}});
if (section.style.display === "none") {
section.style.display = "block";
trigger.classList.replace("icon-down-open", "icon-up-open");
} else {
section.style.display = "none";
trigger.classList.replace("icon-up-open", "icon-down-open");
}
} }
// Option listeners // Option listeners

View file

@ -184,7 +184,7 @@ function editStates() {
path.transition().duration(dur).attrTween("stroke-dasharray", function() {return t => i(t)}); path.transition().duration(dur).attrTween("stroke-dasharray", function() {return t => i(t)});
} }
function stateHighlightOff(event) { function stateHighlightOff() {
debug.selectAll(".highlight").each(function() { debug.selectAll(".highlight").each(function() {
d3.select(this).transition().duration(1000).attr("opacity", 0).remove(); d3.select(this).transition().duration(1000).attr("opacity", 0).remove();
}); });
@ -201,6 +201,12 @@ function editStates() {
statesBody.select("#state-gap"+state).attr("stroke", fill); statesBody.select("#state-gap"+state).attr("stroke", fill);
const halo = d3.color(fill) ? d3.color(fill).darker().hex() : "#666666"; const halo = d3.color(fill) ? d3.color(fill).darker().hex() : "#666666";
statesHalo.select("#state-border"+state).attr("stroke", halo); statesHalo.select("#state-border"+state).attr("stroke", halo);
// recolor regiments
const solidColor = fill[0] === "#" ? fill : "#999";
const darkerColor = d3.color(solidColor).darker().hex();
armies.select("#army"+state).attr("fill", solidColor);
armies.select("#army"+state).selectAll("g > rect:nth-of-type(2)").attr("fill", darkerColor);
} }
openPicker(currentFill, callback); openPicker(currentFill, callback);

View file

@ -376,13 +376,13 @@ function common(a, b) {
} }
// clip polygon by graph bbox // clip polygon by graph bbox
function clipPoly(points, secure = false) { function clipPoly(points, secure = 0) {
return polygonclip(points, [0, 0, graphWidth, graphHeight], secure); return polygonclip(points, [0, 0, graphWidth, graphHeight], secure);
} }
// check if char is vowel // check if char is vowel or can serve as vowel
function vowel(c) { function vowel(c) {
return "aeiouy".includes(c); return `aeiouyɑ'əøɛœæɶɒɨɪɔɐʊɤɯаоиеёэыуюяàèìòùỳẁȁȅȉȍȕáéíóúýẃőűâêîôûŷŵäëïöüÿẅãẽĩõũỹąęįǫųāēīōūȳăĕĭŏŭǎěǐǒǔȧėȯẏẇạẹịọụỵẉḛḭṵṳ`.includes(c);
} }
// remove vowels from the end of the string // remove vowels from the end of the string