mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 03:51:23 +01:00
pull master
This commit is contained in:
commit
e6457c4e4e
25 changed files with 930 additions and 447 deletions
83
index.css
83
index.css
|
|
@ -1,3 +1,24 @@
|
||||||
|
:root {
|
||||||
|
--monospace: Consolas, monospace;
|
||||||
|
--serif: Georgia, serif;
|
||||||
|
--sans-serif: Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hide Google translate header */
|
||||||
|
body > .skiptranslate {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hide Google translate in-progress widget */
|
||||||
|
body > .skiptranslate + div {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make translated text wrapper non-blocking */
|
||||||
|
font {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
input,
|
input,
|
||||||
select,
|
select,
|
||||||
button {
|
button {
|
||||||
|
|
@ -119,7 +140,7 @@ a {
|
||||||
}
|
}
|
||||||
|
|
||||||
#temperature {
|
#temperature {
|
||||||
font-family: sans-serif;
|
font-family: var(--sans-serif);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-anchor: middle;
|
text-anchor: middle;
|
||||||
dominant-baseline: central;
|
dominant-baseline: central;
|
||||||
|
|
@ -160,7 +181,7 @@ t,
|
||||||
text-shadow: 0 0 4px #000;
|
text-shadow: 0 0 4px #000;
|
||||||
dominant-baseline: central;
|
dominant-baseline: central;
|
||||||
text-anchor: middle;
|
text-anchor: middle;
|
||||||
font-family: Helvetica;
|
font-family: var(--sans-serif);
|
||||||
fill-opacity: 1;
|
fill-opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,7 +270,7 @@ i.icon-lock {
|
||||||
|
|
||||||
.chartInfo {
|
.chartInfo {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: sans-serif;
|
font-family: var(--sans-serif);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
@ -356,7 +377,7 @@ text.drag {
|
||||||
|
|
||||||
#options {
|
#options {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-family: Consolas, monospace;
|
font-family: var(--monospace);
|
||||||
border: solid 1px #5e4fa2;
|
border: solid 1px #5e4fa2;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
padding-bottom: 0.3em;
|
padding-bottom: 0.3em;
|
||||||
|
|
@ -366,7 +387,7 @@ text.drag {
|
||||||
#options input,
|
#options input,
|
||||||
#options select,
|
#options select,
|
||||||
#options button {
|
#options button {
|
||||||
font-family: Consolas, monospace;
|
font-family: var(--monospace);
|
||||||
}
|
}
|
||||||
|
|
||||||
#collapsible {
|
#collapsible {
|
||||||
|
|
@ -387,7 +408,7 @@ text.drag {
|
||||||
|
|
||||||
div.tab > button#optionsHide {
|
div.tab > button#optionsHide {
|
||||||
width: auto;
|
width: auto;
|
||||||
font-family: Arial;
|
font-family: var(--sans-serif);
|
||||||
padding: 0.6em 0.45em;
|
padding: 0.6em 0.45em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,6 +442,7 @@ button.options:hover {
|
||||||
|
|
||||||
#aboutContent p {
|
#aboutContent p {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
#aboutContent a {
|
#aboutContent a {
|
||||||
|
|
@ -590,6 +612,11 @@ input[type="color"]::-webkit-color-swatch-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#loadGoogleTranslateButton {
|
||||||
|
font-size: smaller;
|
||||||
|
padding: 0.4em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
#options input[type="color"] {
|
#options input[type="color"] {
|
||||||
width: 2em;
|
width: 2em;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
|
|
@ -657,7 +684,7 @@ input[type="color"]::-webkit-color-swatch-wrapper {
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0.45em 0.75em;
|
padding: 0.45em 0.75em;
|
||||||
margin: 0.4em 0;
|
margin: 0.4em 0;
|
||||||
font-family: Consolas, monospace;
|
font-family: var(--monospace);
|
||||||
animation: glowing 2s infinite;
|
animation: glowing 2s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -690,6 +717,11 @@ input[type="color"]::-webkit-color-swatch-wrapper {
|
||||||
margin: 0.35em 0;
|
margin: 0.35em 0;
|
||||||
transition: 0.1s;
|
transition: 0.1s;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
text-transform: capitalize;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabcontent button.pressed {
|
.tabcontent button.pressed {
|
||||||
|
|
@ -743,6 +775,11 @@ fieldset {
|
||||||
float: left;
|
float: left;
|
||||||
width: 28%;
|
width: 28%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
text-transform: capitalize;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabcontent .buttonoff {
|
.tabcontent .buttonoff {
|
||||||
|
|
@ -936,7 +973,7 @@ fieldset {
|
||||||
padding: 0.1em 0.5em;
|
padding: 0.1em 0.5em;
|
||||||
float: left;
|
float: left;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
}
|
}
|
||||||
|
|
||||||
#brushesButtons > button {
|
#brushesButtons > button {
|
||||||
|
|
@ -995,7 +1032,7 @@ fieldset {
|
||||||
background-color: #ffffff95;
|
background-color: #ffffff95;
|
||||||
color: #05044d;
|
color: #05044d;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
}
|
}
|
||||||
|
|
||||||
#templateBody select {
|
#templateBody select {
|
||||||
|
|
@ -1694,7 +1731,7 @@ div.states > div.biomeArea {
|
||||||
#emblemUploadControl,
|
#emblemUploadControl,
|
||||||
#emblemDownloadControl {
|
#emblemDownloadControl {
|
||||||
margin-top: 0.3em;
|
margin-top: 0.3em;
|
||||||
text-align: center;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.editorLine {
|
div.editorLine {
|
||||||
|
|
@ -1721,7 +1758,7 @@ div.editorLine {
|
||||||
fill: #f8ffff;
|
fill: #f8ffff;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: var(--sans-serif);
|
||||||
cursor: move !important;
|
cursor: move !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1734,7 +1771,7 @@ div.editorLine {
|
||||||
#pickerCloseText {
|
#pickerCloseText {
|
||||||
fill: #f8ffff;
|
fill: #f8ffff;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: var(--sans-serif);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1869,7 +1906,7 @@ div.editorLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ruler text {
|
#ruler text {
|
||||||
font-family: "Georgia";
|
font-family: var(--serif);
|
||||||
fill: #3d3d3d;
|
fill: #3d3d3d;
|
||||||
text-anchor: middle;
|
text-anchor: middle;
|
||||||
text-shadow: 0 0 4px white;
|
text-shadow: 0 0 4px white;
|
||||||
|
|
@ -1892,7 +1929,7 @@ div.editorLine {
|
||||||
#scaleBar text {
|
#scaleBar text {
|
||||||
fill: #353540;
|
fill: #353540;
|
||||||
text-anchor: middle;
|
text-anchor: middle;
|
||||||
font-family: Georgia;
|
font-family: var(--serif);
|
||||||
}
|
}
|
||||||
|
|
||||||
#militaryOptionsTable select {
|
#militaryOptionsTable select {
|
||||||
|
|
@ -1918,7 +1955,7 @@ div.editorLine {
|
||||||
|
|
||||||
#coordinateLabels {
|
#coordinateLabels {
|
||||||
fill: #333333;
|
fill: #333333;
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
text-shadow: 0 0 4px white;
|
text-shadow: 0 0 4px white;
|
||||||
stroke-width: 0;
|
stroke-width: 0;
|
||||||
dominant-baseline: central;
|
dominant-baseline: central;
|
||||||
|
|
@ -1973,7 +2010,7 @@ input[type="checkbox"] {
|
||||||
div.textual select,
|
div.textual select,
|
||||||
div.textual textarea,
|
div.textual textarea,
|
||||||
div.textual input {
|
div.textual input {
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
}
|
}
|
||||||
|
|
||||||
div.textual fieldset {
|
div.textual fieldset {
|
||||||
|
|
@ -1988,13 +2025,13 @@ div.textual span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#namesbaseExamples {
|
#namesbaseExamples {
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#markers {
|
#markers {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
text-anchor: middle;
|
text-anchor: middle;
|
||||||
dominant-baseline: central;
|
dominant-baseline: central;
|
||||||
|
|
@ -2054,7 +2091,7 @@ div.textual span,
|
||||||
outline: 0;
|
outline: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 0.6em;
|
padding: 0.6em;
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid #dedede;
|
border: 1px solid #dedede;
|
||||||
color: #000;
|
color: #000;
|
||||||
|
|
@ -2184,14 +2221,14 @@ svg.button {
|
||||||
#globaAxisLabels {
|
#globaAxisLabels {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 9px;
|
font-size: 9px;
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
stroke: none;
|
stroke: none;
|
||||||
fill: #001754;
|
fill: #001754;
|
||||||
}
|
}
|
||||||
|
|
||||||
#globeLatLabels {
|
#globeLatLabels {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
stroke: none;
|
stroke: none;
|
||||||
fill: #001754;
|
fill: #001754;
|
||||||
}
|
}
|
||||||
|
|
@ -2252,7 +2289,7 @@ svg.button {
|
||||||
|
|
||||||
#errorBox {
|
#errorBox {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
font-family: Consolas, monospace;
|
font-family: var(--monospace);
|
||||||
color: #920303;
|
color: #920303;
|
||||||
background-color: #dabdbd91;
|
background-color: #dabdbd91;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
|
@ -2287,7 +2324,7 @@ svg.button {
|
||||||
#promptText {
|
#promptText {
|
||||||
padding: 0 0 0.6em 0;
|
padding: 0 0 0.6em 0;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-family: sans-serif;
|
font-family: var(--sans-serif);
|
||||||
}
|
}
|
||||||
|
|
||||||
#mapOverlay {
|
#mapOverlay {
|
||||||
|
|
|
||||||
151
index.html
151
index.html
|
|
@ -40,6 +40,7 @@
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
top: 0 !important;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +128,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<link rel="preload" href="index.css?v=1.89.13" as="style" onload="this.onload=null; this.rel='stylesheet'" />
|
<link rel="preload" href="index.css?v=1.89.21" as="style" onload="this.onload=null; this.rel='stylesheet'" />
|
||||||
<link rel="preload" href="icons.css" as="style" onload="this.onload=null; this.rel='stylesheet'" />
|
<link rel="preload" href="icons.css" as="style" onload="this.onload=null; this.rel='stylesheet'" />
|
||||||
<link rel="preload" href="libs/jquery-ui.css" as="style" onload="this.onload=null; this.rel='stylesheet'" />
|
<link rel="preload" href="libs/jquery-ui.css" as="style" onload="this.onload=null; this.rel='stylesheet'" />
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -362,10 +363,10 @@
|
||||||
<use href="#rose" x="50%" y="50%" />
|
<use href="#rose" x="50%" y="50%" />
|
||||||
</svg>
|
</svg>
|
||||||
<div id="loading-typography">
|
<div id="loading-typography">
|
||||||
<div id="titleName"><t data-t="titleName">Azgaar's</t></div>
|
<div id="titleName">Azgaar's</div>
|
||||||
<div id="title"><t data-t="title">Fantasy Map Generator</t></div>
|
<div id="title">Fantasy Map Generator</div>
|
||||||
<div id="versionText"><t data-t="version">v</t><span id="version"></span></div>
|
<div id="versionText"></div>
|
||||||
<p id="loading-text"><t data-t="loading">LOADING</t><span>.</span><span>.</span><span>.</span></p>
|
<p id="loading-text">LOADING<span>.</span><span>.</span><span>.</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -373,7 +374,6 @@
|
||||||
<div id="collapsible">
|
<div id="collapsible">
|
||||||
<button
|
<button
|
||||||
id="optionsTrigger"
|
id="optionsTrigger"
|
||||||
data-t="tipOptionsTrigger"
|
|
||||||
data-tip="Click to show the Menu"
|
data-tip="Click to show the Menu"
|
||||||
data-shortcut="Tab"
|
data-shortcut="Tab"
|
||||||
class="options glow"
|
class="options glow"
|
||||||
|
|
@ -383,24 +383,22 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
id="regenerate"
|
id="regenerate"
|
||||||
data-t="tipRegenerate"
|
|
||||||
data-tip="Click to generate a new map"
|
data-tip="Click to generate a new map"
|
||||||
data-shortcut="F2"
|
data-shortcut="F2"
|
||||||
onclick="regeneratePrompt()"
|
onclick="regeneratePrompt()"
|
||||||
class="options"
|
class="options"
|
||||||
style="display: none"
|
style="display: none"
|
||||||
>
|
>
|
||||||
<t data-t="newMap">New Map!</t>
|
New Map!
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="options" style="display: none">
|
<div id="options" style="display: none">
|
||||||
<div class="drag-trigger" data-t="optionsDragTrigger" data-tip="Drag to move the Menu"></div>
|
<div class="drag-trigger" data-tip="Drag to move the Menu"></div>
|
||||||
|
|
||||||
<div class="tab">
|
<div class="tab">
|
||||||
<button
|
<button
|
||||||
id="optionsHide"
|
id="optionsHide"
|
||||||
data-t="optionsHide"
|
|
||||||
data-tip="Click to hide the Menu"
|
data-tip="Click to hide the Menu"
|
||||||
data-shortcut="Tab or Esc"
|
data-shortcut="Tab or Esc"
|
||||||
class="options"
|
class="options"
|
||||||
|
|
@ -408,26 +406,11 @@
|
||||||
>
|
>
|
||||||
◄
|
◄
|
||||||
</button>
|
</button>
|
||||||
<button id="layersTab" data-t="layersTab" data-tip="Click to change map layers" class="options active">
|
<button id="layersTab" data-tip="Click to change map layers" class="options active">Layers</button>
|
||||||
<t data-t="layers">Layers</t>
|
<button id="styleTab" data-tip="Click to open style editor" class="options">Style</button>
|
||||||
</button>
|
<button id="optionsTab" data-tip="Click to change generation and UI options" class="options">Options</button>
|
||||||
<button id="styleTab" data-t="styleTab" data-tip="Click to open style editor" class="options">
|
<button id="toolsTab" data-tip="Click to open tools menu" class="options">Tools</button>
|
||||||
<t data-t="style">Style</t>
|
<button id="aboutTab" data-tip="Click to see Generator info" class="options">About</button>
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
id="optionsTab"
|
|
||||||
data-t="optionsTab"
|
|
||||||
data-tip="Click to change generation and UI options"
|
|
||||||
class="options"
|
|
||||||
>
|
|
||||||
<t data-t="options">Options</t>
|
|
||||||
</button>
|
|
||||||
<button id="toolsTab" data-t="toolsTab" data-tip="Click to open tools menu" class="options">
|
|
||||||
<t data-t="tools">Tools</t>
|
|
||||||
</button>
|
|
||||||
<button id="aboutTab" data-t="aboutTab" data-tip="Click to see Generator info" class="options">
|
|
||||||
<t data-t="about">About</t>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="layersContent" class="tabcontent" style="display: block">
|
<div id="layersContent" class="tabcontent" style="display: block">
|
||||||
|
|
@ -1707,18 +1690,6 @@
|
||||||
Generator settings:
|
Generator settings:
|
||||||
</p>
|
</p>
|
||||||
<table>
|
<table>
|
||||||
<tr data-tip="Set what Generator should do on opening">
|
|
||||||
<td></td>
|
|
||||||
<td>Onload behavior</td>
|
|
||||||
<td>
|
|
||||||
<select id="onloadMap" data-stored="onloadMap">
|
|
||||||
<option value="random" selected>Generate random map</option>
|
|
||||||
<option value="saved">Open last saved map</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr
|
<tr
|
||||||
data-tip="Set user interface size. Please note browser zoom also affects interface size (Ctrl + or Ctrl - to change)"
|
data-tip="Set user interface size. Please note browser zoom also affects interface size (Ctrl + or Ctrl - to change)"
|
||||||
>
|
>
|
||||||
|
|
@ -1767,6 +1738,33 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr data-tip="Set autosave interval in minutes. Set 0 to disable autosave. Map is saved to browser memory">
|
||||||
|
<td></td>
|
||||||
|
<td>Autosave interval</td>
|
||||||
|
<td>
|
||||||
|
<input
|
||||||
|
id="autosaveIntervalInput"
|
||||||
|
data-stored="autosaveInterval"
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="60"
|
||||||
|
step="1"
|
||||||
|
value="15"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input
|
||||||
|
id="autosaveIntervalOutput"
|
||||||
|
data-stored="autosaveInterval"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
max="60"
|
||||||
|
step="1"
|
||||||
|
value="15"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr data-tip="Select speech synthesis voice to pronounce generated names">
|
<tr data-tip="Select speech synthesis voice to pronounce generated names">
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>Speaker voice</td>
|
<td>Speaker voice</td>
|
||||||
|
|
@ -1905,17 +1903,19 @@
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<!-- <tr data-tip="Select language (not all languages are fully supported). Reload the page to apply">
|
<tr
|
||||||
<td></td>
|
data-tip="Load Google Translate and select language. Note that automatic translation can break some page functional. In this case reset the language back to English or refresh the page"
|
||||||
<td>Language</td>
|
>
|
||||||
<td>
|
<td>
|
||||||
<select id="selectLanguage" data-stored="lang">
|
<i data-tip="Reset language to English" id="resetLanguage" class="icon-ccw"></i>
|
||||||
<option value="en" selected>English (100%)</option>
|
</td>
|
||||||
<option value="ru">Русский (1%)</option>
|
<td>Language</td>
|
||||||
</select>
|
<td>
|
||||||
</td>
|
<button id="loadGoogleTranslateButton">Init Google Translate</button>
|
||||||
<td></td>
|
<div id="google_translate_element"></div>
|
||||||
</tr> -->
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -2057,7 +2057,7 @@
|
||||||
>
|
>
|
||||||
Military
|
Military
|
||||||
</button>
|
</button>
|
||||||
<button id="regenerateIce" data-tip="Click to icebergs and glaciers">Ice</button>
|
<button id="regenerateIce" data-tip="Click to regenerate icebergs and glaciers">Ice</button>
|
||||||
<button id="regenerateMarkers" data-tip="Click to regenerate unlocked markers">
|
<button id="regenerateMarkers" data-tip="Click to regenerate unlocked markers">
|
||||||
Markers <i id="configRegenerateMarkers" class="icon-cog" data-tip="Click to set number multiplier"></i>
|
Markers <i id="configRegenerateMarkers" class="icon-cog" data-tip="Click to set number multiplier"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -2257,7 +2257,8 @@
|
||||||
<a data-tip="Click to see list of supporters" onclick="showSupporters()">all supporters</a> on Patreon!
|
<a data-tip="Click to see list of supporters" onclick="showSupporters()">all supporters</a> on Patreon!
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- <div style="display: flex; justify-content: center; padding: 0.4em">
|
|
||||||
|
<!-- <div style="display: flex; justify-content: center; padding: 0.8em 0.4em 0.4em; font-family: cursive">
|
||||||
<a
|
<a
|
||||||
href="https://war.ukraine.ua/support-ukraine"
|
href="https://war.ukraine.ua/support-ukraine"
|
||||||
style="width: 80%"
|
style="width: 80%"
|
||||||
|
|
@ -3254,7 +3255,7 @@
|
||||||
style="margin-left: 0.1em"
|
style="margin-left: 0.1em"
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
<iframe id="mfcgPreview" sandbox="allow-scripts allow-same-origin"></iframe>
|
<iframe id="mfcgPreview" sandbox="allow-scripts"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -4917,7 +4918,10 @@
|
||||||
>
|
>
|
||||||
Any image
|
Any image
|
||||||
</button>
|
</button>
|
||||||
<button id="emblemsUploadSVG" data-tip="Upload prepared SVG image, e.g. SVG from Armoria">
|
<button
|
||||||
|
id="emblemsUploadSVG"
|
||||||
|
data-tip="Upload prepared SVG image (SVG from Armoria or SVG processed with 'Optimize vector' tool)"
|
||||||
|
>
|
||||||
Prepared SVG
|
Prepared SVG
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
|
|
@ -5809,7 +5813,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onclick="quickSave()"
|
onclick="quickSave()"
|
||||||
data-tip="Save the project to browser storage. It can be unreliable"
|
data-tip="Save the project to browser storage. It will overwrite the latest autosave"
|
||||||
data-shortcut="F6"
|
data-shortcut="F6"
|
||||||
>
|
>
|
||||||
browser
|
browser
|
||||||
|
|
@ -7838,9 +7842,10 @@
|
||||||
<script src="libs/d3.min.js"></script>
|
<script src="libs/d3.min.js"></script>
|
||||||
<script src="libs/priority-queue.min.js"></script>
|
<script src="libs/priority-queue.min.js"></script>
|
||||||
<script src="libs/delaunator.min.js"></script>
|
<script src="libs/delaunator.min.js"></script>
|
||||||
|
<script src="libs/indexedDB.js?v=1.89.32"></script>
|
||||||
|
|
||||||
<script src="utils/shorthands.js"></script>
|
<script src="utils/shorthands.js"></script>
|
||||||
<script src="utils/commonUtils.js"></script>
|
<script src="utils/commonUtils.js?v=1.89.29"></script>
|
||||||
<script src="utils/arrayUtils.js"></script>
|
<script src="utils/arrayUtils.js"></script>
|
||||||
<script src="utils/colorUtils.js"></script>
|
<script src="utils/colorUtils.js"></script>
|
||||||
<script src="utils/graphUtils.js?v=1.88.02"></script>
|
<script src="utils/graphUtils.js?v=1.88.02"></script>
|
||||||
|
|
@ -7863,32 +7868,32 @@
|
||||||
<script src="modules/cultures-generator.js?v=1.89.10"></script>
|
<script src="modules/cultures-generator.js?v=1.89.10"></script>
|
||||||
<script src="modules/burgs-and-states.js?v=1.89.07"></script>
|
<script src="modules/burgs-and-states.js?v=1.89.07"></script>
|
||||||
<script src="modules/routes-generator.js"></script>
|
<script src="modules/routes-generator.js"></script>
|
||||||
<script src="modules/religions-generator.js?v=1.89.15"></script>
|
<script src="modules/religions-generator.js?v=1.89.28"></script>
|
||||||
<script src="modules/military-generator.js"></script>
|
<script src="modules/military-generator.js"></script>
|
||||||
<script src="modules/markers-generator.js?v=1.87.13"></script>
|
<script src="modules/markers-generator.js?v=1.89.23"></script>
|
||||||
<script src="modules/coa-generator.js"></script>
|
<script src="modules/coa-generator.js"></script>
|
||||||
<script src="modules/submap.js?v=1.88.05"></script>
|
<script src="modules/submap.js?v=1.88.05"></script>
|
||||||
<script src="libs/polylabel.min.js"></script>
|
<script src="libs/polylabel.min.js"></script>
|
||||||
<script src="libs/lineclip.min.js"></script>
|
<script src="libs/lineclip.min.js"></script>
|
||||||
<script src="libs/alea.min.js"></script>
|
<script src="libs/alea.min.js"></script>
|
||||||
<script src="modules/fonts.js"></script>
|
<script src="modules/fonts.js?v=1.89.18"></script>
|
||||||
<script src="modules/ui/layers.js"></script>
|
<script src="modules/ui/layers.js"></script>
|
||||||
<script src="modules/ui/measurers.js?v=1.87.02"></script>
|
<script src="modules/ui/measurers.js?v=1.87.02"></script>
|
||||||
<script src="modules/ui/stylePresets.js?v=1.89.11"></script>
|
<script src="modules/ui/stylePresets.js?v=1.89.11"></script>
|
||||||
|
|
||||||
<script src="modules/ui/general.js?v=1.87.03"></script>
|
<script src="modules/ui/general.js?v=1.87.03"></script>
|
||||||
<script src="modules/ui/options.js?v=1.88.14"></script>
|
<script src="modules/ui/options.js?v=1.89.19"></script>
|
||||||
<script src="main.js?v=1.89.12"></script>
|
<script src="main.js?v=1.89.32"></script>
|
||||||
|
|
||||||
<script defer src="modules/relief-icons.js"></script>
|
<script defer src="modules/relief-icons.js"></script>
|
||||||
<script defer src="modules/ui/style.js"></script>
|
<script defer src="modules/ui/style.js"></script>
|
||||||
<script defer src="modules/ui/editors.js?v=1.89.12"></script>
|
<script defer src="modules/ui/editors.js?v=1.89.12"></script>
|
||||||
<script defer src="modules/ui/tools.js?v=1.89.13"></script>
|
<script defer src="modules/ui/tools.js?v=1.89.27"></script>
|
||||||
<script defer src="modules/ui/world-configurator.js"></script>
|
<script defer src="modules/ui/world-configurator.js"></script>
|
||||||
<script defer src="modules/ui/heightmap-editor.js?v=1.89.06"></script>
|
<script defer src="modules/ui/heightmap-editor.js?v=1.89.06"></script>
|
||||||
<script defer src="modules/ui/provinces-editor.js?v=1.89.00"></script>
|
<script defer src="modules/ui/provinces-editor.js?v=1.89.00"></script>
|
||||||
<script defer src="modules/ui/biomes-editor.js"></script>
|
<script defer src="modules/ui/biomes-editor.js"></script>
|
||||||
<script defer src="modules/ui/namesbase-editor.js?v=1.87.10"></script>
|
<script defer src="modules/ui/namesbase-editor.js?v=1.89.26"></script>
|
||||||
<script defer src="modules/ui/elevation-profile.js"></script>
|
<script defer src="modules/ui/elevation-profile.js"></script>
|
||||||
<script defer src="modules/ui/temperature-graph.js"></script>
|
<script defer src="modules/ui/temperature-graph.js"></script>
|
||||||
<script defer src="modules/ui/routes-editor.js?v=1.89.04"></script>
|
<script defer src="modules/ui/routes-editor.js?v=1.89.04"></script>
|
||||||
|
|
@ -7904,14 +7909,14 @@
|
||||||
<script defer src="modules/ui/notes-editor.js?v=1.89.03"></script>
|
<script defer src="modules/ui/notes-editor.js?v=1.89.03"></script>
|
||||||
<script defer src="modules/ui/diplomacy-editor.js?v=1.88.04"></script>
|
<script defer src="modules/ui/diplomacy-editor.js?v=1.88.04"></script>
|
||||||
<script defer src="modules/ui/zones-editor.js"></script>
|
<script defer src="modules/ui/zones-editor.js"></script>
|
||||||
<script defer src="modules/ui/burgs-overview.js"></script>
|
<script defer src="modules/ui/burgs-overview.js?v=1.89.20"></script>
|
||||||
<script defer src="modules/ui/rivers-overview.js"></script>
|
<script defer src="modules/ui/rivers-overview.js"></script>
|
||||||
<script defer src="modules/ui/military-overview.js"></script>
|
<script defer src="modules/ui/military-overview.js"></script>
|
||||||
<script defer src="modules/ui/regiments-overview.js"></script>
|
<script defer src="modules/ui/regiments-overview.js?v=1.89.20"></script>
|
||||||
<script defer src="modules/ui/markers-overview.js"></script>
|
<script defer src="modules/ui/markers-overview.js?v=1.89.20"></script>
|
||||||
<script defer src="modules/ui/regiment-editor.js"></script>
|
<script defer src="modules/ui/regiment-editor.js"></script>
|
||||||
<script defer src="modules/ui/battle-screen.js"></script>
|
<script defer src="modules/ui/battle-screen.js"></script>
|
||||||
<script defer src="modules/ui/emblems-editor.js"></script>
|
<script defer src="modules/ui/emblems-editor.js?v=1.89.21"></script>
|
||||||
<script defer src="modules/ui/markers-editor.js"></script>
|
<script defer src="modules/ui/markers-editor.js"></script>
|
||||||
<script defer src="modules/ui/3d.js"></script>
|
<script defer src="modules/ui/3d.js"></script>
|
||||||
<script defer src="modules/ui/submap.js"></script>
|
<script defer src="modules/ui/submap.js"></script>
|
||||||
|
|
@ -7920,10 +7925,10 @@
|
||||||
<script defer src="libs/rgbquant.min.js"></script>
|
<script defer src="libs/rgbquant.min.js"></script>
|
||||||
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
||||||
|
|
||||||
<script defer src="modules/io/save.js"></script>
|
<script defer src="modules/io/save.js?v=1.89.29"></script>
|
||||||
<script defer src="modules/io/load.js?v=1.88.05"></script>
|
<script defer src="modules/io/load.js?v=1.89.30"></script>
|
||||||
<script defer src="modules/io/cloud.js"></script>
|
<script defer src="modules/io/cloud.js"></script>
|
||||||
<script defer src="modules/io/export.js"></script>
|
<script defer src="modules/io/export.js?v=1.89.17"></script>
|
||||||
<script defer src="modules/io/formats.js"></script>
|
<script defer src="modules/io/formats.js"></script>
|
||||||
|
|
||||||
<!-- Web Components -->
|
<!-- Web Components -->
|
||||||
|
|
|
||||||
72
libs/indexedDB.js
Normal file
72
libs/indexedDB.js
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
let db;
|
||||||
|
|
||||||
|
const DATABASE_NAME = "d2";
|
||||||
|
const STORE_NAME = "s";
|
||||||
|
const KEY_PATH = "key";
|
||||||
|
|
||||||
|
const openDatabase = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (db) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
const request = window.indexedDB.open(DATABASE_NAME, 1);
|
||||||
|
|
||||||
|
request.onsuccess = event => {
|
||||||
|
db = event.target.result;
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = event => {
|
||||||
|
console.error("indexedDB request error");
|
||||||
|
console.log(event);
|
||||||
|
reject();
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onupgradeneeded = event => {
|
||||||
|
db = event.target.result;
|
||||||
|
const objectStore = db.createObjectStore(STORE_NAME, {keyPath: KEY_PATH});
|
||||||
|
objectStore.transaction.oncomplete = () => {
|
||||||
|
db = event.target.result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const ldb = {
|
||||||
|
get: key => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!window.indexedDB) return reject("indexedDB not supported");
|
||||||
|
|
||||||
|
openDatabase().then(() => {
|
||||||
|
const hasStore = Array.from(db.objectStoreNames).includes(STORE_NAME);
|
||||||
|
if (!hasStore) return reject("no store found");
|
||||||
|
|
||||||
|
const transaction = db.transaction(STORE_NAME, "readonly");
|
||||||
|
const objectStore = transaction.objectStore(STORE_NAME);
|
||||||
|
const getRequest = objectStore.get(key);
|
||||||
|
|
||||||
|
getRequest.onsuccess = event => {
|
||||||
|
const result = event.target.result?.value || null;
|
||||||
|
resolve(result);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
set: (key, value) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!window.indexedDB) return reject("indexedDB not supported");
|
||||||
|
|
||||||
|
openDatabase().then(() => {
|
||||||
|
const transaction = db.transaction(STORE_NAME, "readwrite");
|
||||||
|
const objectStore = transaction.objectStore(STORE_NAME);
|
||||||
|
const putRequest = objectStore.put({key, value});
|
||||||
|
|
||||||
|
putRequest.onsuccess = () => {
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
4
libs/jquery-ui.css
vendored
4
libs/jquery-ui.css
vendored
|
|
@ -421,13 +421,13 @@ body .ui-dialog {
|
||||||
/* Component containers
|
/* Component containers
|
||||||
----------------------------------*/
|
----------------------------------*/
|
||||||
.ui-widget {
|
.ui-widget {
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: var(--sans-serif);
|
||||||
}
|
}
|
||||||
.ui-widget input,
|
.ui-widget input,
|
||||||
.ui-widget select,
|
.ui-widget select,
|
||||||
.ui-widget textarea,
|
.ui-widget textarea,
|
||||||
.ui-widget button {
|
.ui-widget button {
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: var(--sans-serif);
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
}
|
}
|
||||||
.ui-widget button[class^="icon-"] {
|
.ui-widget button[class^="icon-"] {
|
||||||
|
|
|
||||||
50
main.js
50
main.js
|
|
@ -29,7 +29,7 @@ if (PRODUCTION && "serviceWorker" in navigator) {
|
||||||
"beforeinstallprompt",
|
"beforeinstallprompt",
|
||||||
async event => {
|
async event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const Installation = await import("./modules/dynamic/installation.js");
|
const Installation = await import("./modules/dynamic/installation.js?v=1.89.19");
|
||||||
Installation.init(event);
|
Installation.init(event);
|
||||||
},
|
},
|
||||||
{once: true}
|
{once: true}
|
||||||
|
|
@ -221,8 +221,7 @@ oceanLayers
|
||||||
document.addEventListener("DOMContentLoaded", async () => {
|
document.addEventListener("DOMContentLoaded", async () => {
|
||||||
if (!location.hostname) {
|
if (!location.hostname) {
|
||||||
const wiki = "https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Run-FMG-locally";
|
const wiki = "https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Run-FMG-locally";
|
||||||
alertMessage.innerHTML = /* html */ `Fantasy Map Generator cannot run serverless. Follow the <a href="${wiki}" target="_blank">instructions</a> on how you can
|
alertMessage.innerHTML = /* html */ `Fantasy Map Generator cannot run serverless. Follow the <a href="${wiki}" target="_blank">instructions</a> on how you can easily run a local web-server`;
|
||||||
easily run a local web-server`;
|
|
||||||
|
|
||||||
$("#alert").dialog({
|
$("#alert").dialog({
|
||||||
resizable: false,
|
resizable: false,
|
||||||
|
|
@ -240,6 +239,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||||
await checkLoadParameters();
|
await checkLoadParameters();
|
||||||
}
|
}
|
||||||
restoreDefaultEvents(); // apply default viewbox events
|
restoreDefaultEvents(); // apply default viewbox events
|
||||||
|
initiateAutosave();
|
||||||
});
|
});
|
||||||
|
|
||||||
function hideLoading() {
|
function hideLoading() {
|
||||||
|
|
@ -280,36 +280,20 @@ async function checkLoadParameters() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// open latest map if option is active and map is stored
|
// check if there is a map saved to indexedDB
|
||||||
const loadLastMap = () =>
|
try {
|
||||||
new Promise((resolve, reject) => {
|
const blob = await ldb.get("lastMap");
|
||||||
ldb.get("lastMap", blob => {
|
if (blob) {
|
||||||
if (blob) {
|
WARN && console.warn("Loading last stored map");
|
||||||
WARN && console.warn("Load last saved map");
|
uploadMap(blob);
|
||||||
try {
|
return;
|
||||||
uploadMap(blob);
|
|
||||||
resolve();
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reject("No map stored");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (onloadMap.value === "saved") {
|
|
||||||
try {
|
|
||||||
await loadLastMap();
|
|
||||||
} catch (error) {
|
|
||||||
ERROR && console.error(error);
|
|
||||||
WARN && console.warn("Cannot load stored map, random map to be generated");
|
|
||||||
await generateMapOnLoad();
|
|
||||||
}
|
}
|
||||||
} else {
|
} catch (error) {
|
||||||
WARN && console.warn("Generate random map");
|
console.error(error);
|
||||||
await generateMapOnLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WARN && console.warn("Generate random map");
|
||||||
|
generateMapOnLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateMapOnLoad() {
|
async function generateMapOnLoad() {
|
||||||
|
|
@ -909,7 +893,7 @@ function addLakesInDeepDepressions() {
|
||||||
TIME && console.timeEnd("addLakesInDeepDepressions");
|
TIME && console.timeEnd("addLakesInDeepDepressions");
|
||||||
}
|
}
|
||||||
|
|
||||||
// near sea lakes usually get a lot of water inflow, most of them should brake threshold and flow out to sea (see Ancylus Lake)
|
// near sea lakes usually get a lot of water inflow, most of them should break threshold and flow out to sea (see Ancylus Lake)
|
||||||
function openNearSeaLakes() {
|
function openNearSeaLakes() {
|
||||||
if (byId("templateInput").value === "Atoll") return; // no need for Atolls
|
if (byId("templateInput").value === "Atoll") return; // no need for Atolls
|
||||||
|
|
||||||
|
|
@ -924,7 +908,7 @@ function openNearSeaLakes() {
|
||||||
if (features[lake].type !== "lake") continue; // not a lake cell
|
if (features[lake].type !== "lake") continue; // not a lake cell
|
||||||
|
|
||||||
check_neighbours: for (const c of cells.c[i]) {
|
check_neighbours: for (const c of cells.c[i]) {
|
||||||
if (cells.t[c] !== 1 || cells.h[c] > LIMIT) continue; // water cannot brake this
|
if (cells.t[c] !== 1 || cells.h[c] > LIMIT) continue; // water cannot break this
|
||||||
|
|
||||||
for (const n of cells.c[c]) {
|
for (const n of cells.c[c]) {
|
||||||
const ocean = cells.f[n];
|
const ocean = cells.f[n];
|
||||||
|
|
|
||||||
|
|
@ -119,17 +119,17 @@ window.Cultures = (function () {
|
||||||
function selectCultures(culturesNumber) {
|
function selectCultures(culturesNumber) {
|
||||||
let def = getDefault(culturesNumber);
|
let def = getDefault(culturesNumber);
|
||||||
const cultures = [];
|
const cultures = [];
|
||||||
|
|
||||||
pack.cultures?.forEach(function (culture) {
|
pack.cultures?.forEach(function (culture) {
|
||||||
if (culture.lock) cultures.push(culture);
|
if (culture.lock) cultures.push(culture);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!cultures.length) {
|
if (!cultures.length) {
|
||||||
if (culturesNumber === def.length) return def;
|
if (culturesNumber === def.length) return def;
|
||||||
if (def.every(d => d.odd === 1)) return def.splice(0, culturesNumber);
|
if (def.every(d => d.odd === 1)) return def.splice(0, culturesNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let culture, rnd, i = 0; cultures.length < culturesNumber && def.length > 0;) {
|
for (let culture, rnd, i = 0; cultures.length < culturesNumber && def.length > 0; ) {
|
||||||
do {
|
do {
|
||||||
rnd = rand(def.length - 1);
|
rnd = rand(def.length - 1);
|
||||||
culture = def[rnd];
|
culture = def[rnd];
|
||||||
|
|
@ -511,89 +511,97 @@ window.Cultures = (function () {
|
||||||
TIME && console.time("expandCultures");
|
TIME && console.time("expandCultures");
|
||||||
const {cells, cultures} = pack;
|
const {cells, cultures} = pack;
|
||||||
|
|
||||||
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
const queue = new PriorityQueue({comparator: (a, b) => a.priority - b.priority});
|
||||||
const cost = [];
|
const cost = [];
|
||||||
|
|
||||||
const neutralRate = byId("neutralRate")?.valueAsNumber || 1;
|
const neutralRate = byId("neutralRate")?.valueAsNumber || 1;
|
||||||
const neutral = cells.i.length * 0.6 * neutralRate; // limit cost for culture growth
|
const maxExpansionCost = cells.i.length * 0.6 * neutralRate; // limit cost for culture growth
|
||||||
|
|
||||||
// remove culture from all cells except of locked
|
// remove culture from all cells except of locked
|
||||||
for (const cellId of cells.i) {
|
const hasLocked = cultures.some(c => !c.removed && c.lock);
|
||||||
const culture = cultures[cells.culture[cellId]];
|
if (hasLocked) {
|
||||||
if (culture.lock) continue;
|
for (const cellId of cells.i) {
|
||||||
cells.culture[cellId] = 0;
|
const culture = cultures[cells.culture[cellId]];
|
||||||
|
if (culture.lock) continue;
|
||||||
|
cells.culture[cellId] = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cells.culture = new Uint16Array(cells.i.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const culture of cultures) {
|
for (const culture of cultures) {
|
||||||
if (!culture.i || culture.removed) continue;
|
if (!culture.i || culture.removed || culture.lock) continue;
|
||||||
queue.queue({e: culture.center, p: 0, c: culture.i});
|
queue.queue({cellId: culture.center, cultureId: culture.i, priority: 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
const {e, p, c} = queue.dequeue();
|
const {cellId, priority, cultureId} = queue.dequeue();
|
||||||
const {type} = pack.cultures[c];
|
const {type, expansionism} = cultures[cultureId];
|
||||||
|
|
||||||
cells.c[e].forEach(e => {
|
cells.c[cellId].forEach(neibCellId => {
|
||||||
const culture = cells.culture[e];
|
if (hasLocked) {
|
||||||
if (culture?.lock) return; // do not overwrite cell of locked culture
|
const neibCultureId = cells.culture[neibCellId];
|
||||||
|
if (neibCultureId && cultures[neibCultureId].lock) return; // do not overwrite cell of locked culture
|
||||||
|
}
|
||||||
|
|
||||||
const biome = cells.biome[e];
|
const biome = cells.biome[neibCellId];
|
||||||
const biomeCost = getBiomeCost(c, biome, type);
|
const biomeCost = getBiomeCost(cultureId, biome, type);
|
||||||
const biomeChangeCost = biome === cells.biome[e] ? 0 : 20; // penalty on biome change
|
const biomeChangeCost = biome === cells.biome[neibCellId] ? 0 : 20; // penalty on biome change
|
||||||
const heightCost = getHeightCost(e, cells.h[e], type);
|
const heightCost = getHeightCost(neibCellId, cells.h[neibCellId], type);
|
||||||
const riverCost = getRiverCost(cells.r[e], e, type);
|
const riverCost = getRiverCost(cells.r[neibCellId], neibCellId, type);
|
||||||
const typeCost = getTypeCost(cells.t[e], type);
|
const typeCost = getTypeCost(cells.t[neibCellId], type);
|
||||||
const totalCost =
|
|
||||||
p + (biomeCost + biomeChangeCost + heightCost + riverCost + typeCost) / pack.cultures[c].expansionism;
|
|
||||||
|
|
||||||
if (totalCost > neutral) return;
|
const cellCost = (biomeCost + biomeChangeCost + heightCost + riverCost + typeCost) / expansionism;
|
||||||
|
const totalCost = priority + cellCost;
|
||||||
|
|
||||||
if (!cost[e] || totalCost < cost[e]) {
|
if (totalCost > maxExpansionCost) return;
|
||||||
if (cells.s[e] > 0) cells.culture[e] = c; // assign culture to populated cell
|
|
||||||
cost[e] = totalCost;
|
if (!cost[neibCellId] || totalCost < cost[neibCellId]) {
|
||||||
queue.queue({e, p: totalCost, c});
|
if (cells.pop[neibCellId] > 0) cells.culture[neibCellId] = cultureId; // assign culture to populated cell
|
||||||
|
cost[neibCellId] = totalCost;
|
||||||
|
queue.queue({cellId: neibCellId, cultureId, priority: totalCost});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBiomeCost(c, biome, type) {
|
||||||
|
if (cells.biome[cultures[c].center] === biome) return 10; // tiny penalty for native biome
|
||||||
|
if (type === "Hunting") return biomesData.cost[biome] * 5; // non-native biome penalty for hunters
|
||||||
|
if (type === "Nomadic" && biome > 4 && biome < 10) return biomesData.cost[biome] * 10; // forest biome penalty for nomads
|
||||||
|
return biomesData.cost[biome] * 2; // general non-native biome penalty
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHeightCost(i, h, type) {
|
||||||
|
const f = pack.features[cells.f[i]],
|
||||||
|
a = cells.area[i];
|
||||||
|
if (type === "Lake" && f.type === "lake") return 10; // no lake crossing penalty for Lake cultures
|
||||||
|
if (type === "Naval" && h < 20) return a * 2; // low sea/lake crossing penalty for Naval cultures
|
||||||
|
if (type === "Nomadic" && h < 20) return a * 50; // giant sea/lake crossing penalty for Nomads
|
||||||
|
if (h < 20) return a * 6; // general sea/lake crossing penalty
|
||||||
|
if (type === "Highland" && h < 44) return 3000; // giant penalty for highlanders on lowlands
|
||||||
|
if (type === "Highland" && h < 62) return 200; // giant penalty for highlanders on lowhills
|
||||||
|
if (type === "Highland") return 0; // no penalty for highlanders on highlands
|
||||||
|
if (h >= 67) return 200; // general mountains crossing penalty
|
||||||
|
if (h >= 44) return 30; // general hills crossing penalty
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRiverCost(riverId, cellId, type) {
|
||||||
|
if (type === "River") return riverId ? 0 : 100; // penalty for river cultures
|
||||||
|
if (!riverId) return 0; // no penalty for others if there is no river
|
||||||
|
return minmax(cells.fl[cellId] / 10, 20, 100); // river penalty from 20 to 100 based on flux
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTypeCost(t, type) {
|
||||||
|
if (t === 1) return type === "Naval" || type === "Lake" ? 0 : type === "Nomadic" ? 60 : 20; // penalty for coastline
|
||||||
|
if (t === 2) return type === "Naval" || type === "Nomadic" ? 30 : 0; // low penalty for land level 2 for Navals and nomads
|
||||||
|
if (t !== -1) return type === "Naval" || type === "Lake" ? 100 : 0; // penalty for mainland for navals
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
TIME && console.timeEnd("expandCultures");
|
TIME && console.timeEnd("expandCultures");
|
||||||
};
|
};
|
||||||
|
|
||||||
function getBiomeCost(c, biome, type) {
|
|
||||||
if (cells.biome[pack.cultures[c].center] === biome) return 10; // tiny penalty for native biome
|
|
||||||
if (type === "Hunting") return biomesData.cost[biome] * 5; // non-native biome penalty for hunters
|
|
||||||
if (type === "Nomadic" && biome > 4 && biome < 10) return biomesData.cost[biome] * 10; // forest biome penalty for nomads
|
|
||||||
return biomesData.cost[biome] * 2; // general non-native biome penalty
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHeightCost(i, h, type) {
|
|
||||||
const f = pack.features[cells.f[i]],
|
|
||||||
a = cells.area[i];
|
|
||||||
if (type === "Lake" && f.type === "lake") return 10; // no lake crossing penalty for Lake cultures
|
|
||||||
if (type === "Naval" && h < 20) return a * 2; // low sea/lake crossing penalty for Naval cultures
|
|
||||||
if (type === "Nomadic" && h < 20) return a * 50; // giant sea/lake crossing penalty for Nomads
|
|
||||||
if (h < 20) return a * 6; // general sea/lake crossing penalty
|
|
||||||
if (type === "Highland" && h < 44) return 3000; // giant penalty for highlanders on lowlands
|
|
||||||
if (type === "Highland" && h < 62) return 200; // giant penalty for highlanders on lowhills
|
|
||||||
if (type === "Highland") return 0; // no penalty for highlanders on highlands
|
|
||||||
if (h >= 67) return 200; // general mountains crossing penalty
|
|
||||||
if (h >= 44) return 30; // general hills crossing penalty
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRiverCost(r, i, type) {
|
|
||||||
if (type === "River") return r ? 0 : 100; // penalty for river cultures
|
|
||||||
if (!r) return 0; // no penalty for others if there is no river
|
|
||||||
return minmax(cells.fl[i] / 10, 20, 100); // river penalty from 20 to 100 based on flux
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTypeCost(t, type) {
|
|
||||||
if (t === 1) return type === "Naval" || type === "Lake" ? 0 : type === "Nomadic" ? 60 : 20; // penalty for coastline
|
|
||||||
if (t === 2) return type === "Naval" || type === "Nomadic" ? 30 : 0; // low penalty for land level 2 for Navals and nomads
|
|
||||||
if (t !== -1) return type === "Naval" || type === "Lake" ? 100 : 0; // penalty for mainland for navals
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getRandomShield = function () {
|
const getRandomShield = function () {
|
||||||
const type = rw(COA.shields.types);
|
const type = rw(COA.shields.types);
|
||||||
return rw(COA.shields[type]);
|
return rw(COA.shields[type]);
|
||||||
|
|
|
||||||
|
|
@ -670,13 +670,13 @@ async function showHierarchy() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function recalculateCultures(must) {
|
function recalculateCultures(force) {
|
||||||
if (!must && !culturesAutoChange.checked) return;
|
if (force || culturesAutoChange.checked) {
|
||||||
|
Cultures.expand();
|
||||||
Cultures.expand();
|
drawCultures();
|
||||||
drawCultures();
|
pack.burgs.forEach(b => (b.culture = pack.cells.culture[b.cell]));
|
||||||
pack.burgs.forEach(b => (b.culture = pack.cells.culture[b.cell]));
|
refreshCulturesEditor();
|
||||||
refreshCulturesEditor();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function enterCultureManualAssignent() {
|
function enterCultureManualAssignent() {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ function createButton() {
|
||||||
button.innerHTML = "Install";
|
button.innerHTML = "Install";
|
||||||
button.onclick = openDialog;
|
button.onclick = openDialog;
|
||||||
button.onmouseenter = () => tip("Install the Application");
|
button.onmouseenter = () => tip("Install the Application");
|
||||||
document.querySelector("body").appendChild(button);
|
document.getElementById("optionsContainer").appendChild(button);
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -426,19 +426,18 @@ function renderChart({id, entity, plotBy, groupBy, sorting, type}) {
|
||||||
})
|
})
|
||||||
.flat();
|
.flat();
|
||||||
|
|
||||||
|
const sortedData = sortData(chartData, sorting);
|
||||||
const colors = getColors();
|
const colors = getColors();
|
||||||
const {offset, formatX = formatTicks} = plotTypeMap[type];
|
const {offset, formatX = formatTicks} = plotTypeMap[type];
|
||||||
|
|
||||||
const $chart = createStackedBarChart(chartData, {sorting, colors, tooltip, offset, formatX});
|
const $chart = createStackedBarChart(sortedData, {colors, tooltip, offset, formatX});
|
||||||
insertChart(id, $chart, title);
|
insertChart(id, sortedData, $chart, title);
|
||||||
|
|
||||||
byId("chartsOverview__charts").lastChild.scrollIntoView();
|
byId("chartsOverview__charts").lastChild.scrollIntoView();
|
||||||
}
|
}
|
||||||
|
|
||||||
// based on observablehq.com/@d3/stacked-horizontal-bar-chart
|
// based on observablehq.com/@d3/stacked-horizontal-bar-chart
|
||||||
function createStackedBarChart(data, {sorting, colors, tooltip, offset, formatX}) {
|
function createStackedBarChart(sortedData, {colors, tooltip, offset, formatX}) {
|
||||||
const sortedData = sortData(data, sorting);
|
|
||||||
|
|
||||||
const X = sortedData.map(d => d.value);
|
const X = sortedData.map(d => d.value);
|
||||||
const Y = sortedData.map(d => d.name);
|
const Y = sortedData.map(d => d.name);
|
||||||
const Z = sortedData.map(d => d.group);
|
const Z = sortedData.map(d => d.group);
|
||||||
|
|
@ -568,7 +567,7 @@ function createStackedBarChart(data, {sorting, colors, tooltip, offset, formatX}
|
||||||
return svg.node();
|
return svg.node();
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertChart(id, $chart, title) {
|
function insertChart(id, sortedData, $chart, title) {
|
||||||
const $chartContainer = byId("chartsOverview__charts");
|
const $chartContainer = byId("chartsOverview__charts");
|
||||||
|
|
||||||
const $figure = document.createElement("figure");
|
const $figure = document.createElement("figure");
|
||||||
|
|
@ -580,7 +579,8 @@ function insertChart(id, $chart, title) {
|
||||||
<strong>Figure ${figureNo}</strong>. ${title}
|
<strong>Figure ${figureNo}</strong>. ${title}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button data-tip="Download the chart in svg format (can open in browser or Inkscape)" class="icon-download"></button>
|
<button data-tip="Download chart data as a text file (.csv)" class="icon-download"></button>
|
||||||
|
<button data-tip="Download the chart in svg format (can open in browser or Inkscape)" class="icon-chart-bar"></button>
|
||||||
<button data-tip="Remove the chart" class="icon-trash"></button>
|
<button data-tip="Remove the chart" class="icon-trash"></button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
@ -589,7 +589,14 @@ function insertChart(id, $chart, title) {
|
||||||
$figure.appendChild($caption);
|
$figure.appendChild($caption);
|
||||||
$chartContainer.appendChild($figure);
|
$chartContainer.appendChild($figure);
|
||||||
|
|
||||||
const downloadChart = () => {
|
const downloadChartData = () => {
|
||||||
|
const name = `${getFileName(title)}.csv`;
|
||||||
|
const headers = "Name,Group,Value\n";
|
||||||
|
const values = sortedData.map(({name, group, value}) => `${name},${group},${value}`).join("\n");
|
||||||
|
downloadFile(headers + values, name);
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadChartSvg = () => {
|
||||||
const name = `${getFileName(title)}.svg`;
|
const name = `${getFileName(title)}.svg`;
|
||||||
downloadFile($chart.outerHTML, name);
|
downloadFile($chart.outerHTML, name);
|
||||||
};
|
};
|
||||||
|
|
@ -600,7 +607,8 @@ function insertChart(id, $chart, title) {
|
||||||
updateDialogPosition();
|
updateDialogPosition();
|
||||||
};
|
};
|
||||||
|
|
||||||
$figure.querySelector("button.icon-download").on("click", downloadChart);
|
$figure.querySelector("button.icon-download").on("click", downloadChartData);
|
||||||
|
$figure.querySelector("button.icon-chart-bar").on("click", downloadChartSvg);
|
||||||
$figure.querySelector("button.icon-trash").on("click", removeChart);
|
$figure.querySelector("button.icon-trash").on("click", removeChart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -478,4 +478,44 @@ Rei
|
||||||
Fondue
|
Fondue
|
||||||
Paavi1
|
Paavi1
|
||||||
Wil Sisney
|
Wil Sisney
|
||||||
David Patterson`;
|
David Patterson
|
||||||
|
L
|
||||||
|
Justin Scheffers
|
||||||
|
Commieboo
|
||||||
|
Garrison Wood
|
||||||
|
Emsiron
|
||||||
|
Frosty
|
||||||
|
John Joseph Adams
|
||||||
|
The_Lone_Wanderer
|
||||||
|
Andrew Stein
|
||||||
|
Groonfish
|
||||||
|
soup
|
||||||
|
Bruno Haack Vilar
|
||||||
|
Ian Burke
|
||||||
|
Tentacle Shogun
|
||||||
|
Andrew Chandler
|
||||||
|
Fritz Wulfram
|
||||||
|
Doom Chupacabra
|
||||||
|
Zakharov
|
||||||
|
Dylan Fox
|
||||||
|
Alfred Piccioni
|
||||||
|
Avery Vreeland
|
||||||
|
Kennedy
|
||||||
|
Zack Wolf
|
||||||
|
Matjam
|
||||||
|
Jeff Johnston
|
||||||
|
Hunter Hawthorne
|
||||||
|
Sunsette
|
||||||
|
Travis Love
|
||||||
|
Dakian Delomast
|
||||||
|
Kyle
|
||||||
|
Davis Walker
|
||||||
|
Naomi
|
||||||
|
Clément D
|
||||||
|
Jake Herr
|
||||||
|
ReV0LT
|
||||||
|
Jack Dawson
|
||||||
|
Queso y Libertad
|
||||||
|
RadioJay21H
|
||||||
|
NEO
|
||||||
|
Crecs`;
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,19 @@
|
||||||
|
|
||||||
const fonts = [
|
const fonts = [
|
||||||
{family: "Arial"},
|
{family: "Arial"},
|
||||||
{family: "Times New Roman"},
|
{family: "Brush Script MT"},
|
||||||
{family: "Georgia"},
|
{family: "Century Gothic"},
|
||||||
{family: "Garamond"},
|
|
||||||
{family: "Lucida Sans Unicode"},
|
|
||||||
{family: "Courier New"},
|
|
||||||
{family: "Verdana"},
|
|
||||||
{family: "Impact"},
|
|
||||||
{family: "Comic Sans MS"},
|
{family: "Comic Sans MS"},
|
||||||
|
{family: "Copperplate"},
|
||||||
|
{family: "Courier New"},
|
||||||
|
{family: "Garamond"},
|
||||||
|
{family: "Georgia"},
|
||||||
|
{family: "Herculanum"},
|
||||||
|
{family: "Impact"},
|
||||||
{family: "Papyrus"},
|
{family: "Papyrus"},
|
||||||
|
{family: "Party LET"},
|
||||||
|
{family: "Times New Roman"},
|
||||||
|
{family: "Verdana"},
|
||||||
{
|
{
|
||||||
family: "Almendra SC",
|
family: "Almendra SC",
|
||||||
src: "url(https://fonts.gstatic.com/s/almendrasc/v13/Iure6Yx284eebowr7hbyTaZOrLQ.woff2)",
|
src: "url(https://fonts.gstatic.com/s/almendrasc/v13/Iure6Yx284eebowr7hbyTaZOrLQ.woff2)",
|
||||||
|
|
@ -38,12 +42,14 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "Architects Daughter",
|
family: "Architects Daughter",
|
||||||
src: "url(https://fonts.gstatic.com/s/architectsdaughter/v8/RXTgOOQ9AAtaVOHxx0IUBM3t7GjCYufj5TXV5VnA2p8.woff2)",
|
src: "url(https://fonts.gstatic.com/s/architectsdaughter/v8/RXTgOOQ9AAtaVOHxx0IUBM3t7GjCYufj5TXV5VnA2p8.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Bitter",
|
family: "Bitter",
|
||||||
src: "url(https://fonts.gstatic.com/s/bitter/v12/zfs6I-5mjWQ3nxqccMoL2A.woff2)",
|
src: "url(https://fonts.gstatic.com/s/bitter/v12/zfs6I-5mjWQ3nxqccMoL2A.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Caesar Dressing",
|
family: "Caesar Dressing",
|
||||||
|
|
@ -54,12 +60,14 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "Cinzel",
|
family: "Cinzel",
|
||||||
src: "url(https://fonts.gstatic.com/s/cinzel/v7/zOdksD_UUTk1LJF9z4tURA.woff2)",
|
src: "url(https://fonts.gstatic.com/s/cinzel/v7/zOdksD_UUTk1LJF9z4tURA.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Dancing Script",
|
family: "Dancing Script",
|
||||||
src: "url(https://fonts.gstatic.com/s/dancingscript/v9/KGBfwabt0ZRLA5W1ywjowUHdOuSHeh0r6jGTOGdAKHA.woff2)",
|
src: "url(https://fonts.gstatic.com/s/dancingscript/v9/KGBfwabt0ZRLA5W1ywjowUHdOuSHeh0r6jGTOGdAKHA.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Faster One",
|
family: "Faster One",
|
||||||
|
|
@ -82,12 +90,14 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "Gloria Hallelujah",
|
family: "Gloria Hallelujah",
|
||||||
src: "url(https://fonts.gstatic.com/s/gloriahallelujah/v9/CA1k7SlXcY5kvI81M_R28cNDay8z-hHR7F16xrcXsJw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/gloriahallelujah/v9/CA1k7SlXcY5kvI81M_R28cNDay8z-hHR7F16xrcXsJw.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Great Vibes",
|
family: "Great Vibes",
|
||||||
src: "url(https://fonts.gstatic.com/s/greatvibes/v5/6q1c0ofG6NKsEhAc2eh-3Y4P5ICox8Kq3LLUNMylGO4.woff2)",
|
src: "url(https://fonts.gstatic.com/s/greatvibes/v5/6q1c0ofG6NKsEhAc2eh-3Y4P5ICox8Kq3LLUNMylGO4.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Henny Penny",
|
family: "Henny Penny",
|
||||||
|
|
@ -98,7 +108,8 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "IM Fell English",
|
family: "IM Fell English",
|
||||||
src: "url(https://fonts.gstatic.com/s/imfellenglish/v7/xwIisCqGFi8pff-oa9uSVAkYLEKE0CJQa8tfZYc_plY.woff2)",
|
src: "url(https://fonts.gstatic.com/s/imfellenglish/v7/xwIisCqGFi8pff-oa9uSVAkYLEKE0CJQa8tfZYc_plY.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Kelly Slab",
|
family: "Kelly Slab",
|
||||||
|
|
@ -121,7 +132,8 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "Kaushan Script",
|
family: "Kaushan Script",
|
||||||
src: "url(https://fonts.gstatic.com/s/kaushanscript/v6/qx1LSqts-NtiKcLw4N03IEd0sm1ffa_JvZxsF_BEwQk.woff2)",
|
src: "url(https://fonts.gstatic.com/s/kaushanscript/v6/qx1LSqts-NtiKcLw4N03IEd0sm1ffa_JvZxsF_BEwQk.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Macondo",
|
family: "Macondo",
|
||||||
|
|
@ -150,7 +162,8 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "Montez",
|
family: "Montez",
|
||||||
src: "url(https://fonts.gstatic.com/s/montez/v8/aq8el3-0osHIcFK6bXAPkw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/montez/v8/aq8el3-0osHIcFK6bXAPkw.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Nova Script",
|
family: "Nova Script",
|
||||||
|
|
@ -161,7 +174,8 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "Orbitron",
|
family: "Orbitron",
|
||||||
src: "url(https://fonts.gstatic.com/s/orbitron/v9/HmnHiRzvcnQr8CjBje6GQvesZW2xOQ-xsNqO47m55DA.woff2)",
|
src: "url(https://fonts.gstatic.com/s/orbitron/v9/HmnHiRzvcnQr8CjBje6GQvesZW2xOQ-xsNqO47m55DA.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Oregano",
|
family: "Oregano",
|
||||||
|
|
@ -184,12 +198,14 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "Satisfy",
|
family: "Satisfy",
|
||||||
src: "url(https://fonts.gstatic.com/s/satisfy/v8/2OzALGYfHwQjkPYWELy-cw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/satisfy/v8/2OzALGYfHwQjkPYWELy-cw.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Shadows Into Light",
|
family: "Shadows Into Light",
|
||||||
src: "url(https://fonts.gstatic.com/s/shadowsintolight/v7/clhLqOv7MXn459PTh0gXYFK2TSYBz0eNcHnp4YqE4Ts.woff2)",
|
src: "url(https://fonts.gstatic.com/s/shadowsintolight/v7/clhLqOv7MXn459PTh0gXYFK2TSYBz0eNcHnp4YqE4Ts.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Tapestry",
|
family: "Tapestry",
|
||||||
|
|
@ -218,7 +234,8 @@ const fonts = [
|
||||||
{
|
{
|
||||||
family: "Yellowtail",
|
family: "Yellowtail",
|
||||||
src: "url(https://fonts.gstatic.com/s/yellowtail/v8/GcIHC9QEwVkrA19LJU1qlPk_vArhqVIZ0nv9q090hN8.woff2)",
|
src: "url(https://fonts.gstatic.com/s/yellowtail/v8/GcIHC9QEwVkrA19LJU1qlPk_vArhqVIZ0nv9q090hN8.woff2)",
|
||||||
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
unicodeRange:
|
||||||
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,12 @@ async function saveSVG() {
|
||||||
link.href = url;
|
link.href = url;
|
||||||
link.click();
|
link.click();
|
||||||
|
|
||||||
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000);
|
tip(
|
||||||
|
`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`,
|
||||||
|
true,
|
||||||
|
"success",
|
||||||
|
5000
|
||||||
|
);
|
||||||
TIME && console.timeEnd("saveSVG");
|
TIME && console.timeEnd("saveSVG");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,7 +41,12 @@ async function savePNG() {
|
||||||
window.setTimeout(function () {
|
window.setTimeout(function () {
|
||||||
canvas.remove();
|
canvas.remove();
|
||||||
window.URL.revokeObjectURL(link.href);
|
window.URL.revokeObjectURL(link.href);
|
||||||
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000);
|
tip(
|
||||||
|
`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`,
|
||||||
|
true,
|
||||||
|
"success",
|
||||||
|
5000
|
||||||
|
);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -140,7 +150,15 @@ async function saveTiles() {
|
||||||
|
|
||||||
// parse map svg to object url
|
// parse map svg to object url
|
||||||
async function getMapURL(type, options = {}) {
|
async function getMapURL(type, options = {}) {
|
||||||
const {debug = false, globe = false, noLabels = false, noWater = false, noScaleBar = false, noIce = false, fullMap = false} = options;
|
const {
|
||||||
|
debug = false,
|
||||||
|
globe = false,
|
||||||
|
noLabels = false,
|
||||||
|
noWater = false,
|
||||||
|
noScaleBar = false,
|
||||||
|
noIce = false,
|
||||||
|
fullMap = false
|
||||||
|
} = options;
|
||||||
|
|
||||||
if (fullMap) drawScaleBar(1);
|
if (fullMap) drawScaleBar(1);
|
||||||
|
|
||||||
|
|
@ -222,12 +240,14 @@ async function getMapURL(type, options = {}) {
|
||||||
if (location.hostname && cloneEl.getElementById("oceanicPattern")) {
|
if (location.hostname && cloneEl.getElementById("oceanicPattern")) {
|
||||||
const el = cloneEl.getElementById("oceanicPattern");
|
const el = cloneEl.getElementById("oceanicPattern");
|
||||||
const url = el.getAttribute("href");
|
const url = el.getAttribute("href");
|
||||||
await new Promise(resolve => {
|
if (url) {
|
||||||
getBase64(url, base64 => {
|
await new Promise(resolve => {
|
||||||
el.setAttribute("href", base64);
|
getBase64(url, base64 => {
|
||||||
resolve();
|
el.setAttribute("href", base64);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add relief icons
|
// add relief icons
|
||||||
|
|
@ -315,7 +335,8 @@ async function getMapURL(type, options = {}) {
|
||||||
|
|
||||||
clone.remove();
|
clone.remove();
|
||||||
|
|
||||||
const serialized = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + new XMLSerializer().serializeToString(cloneEl);
|
const serialized =
|
||||||
|
`<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + new XMLSerializer().serializeToString(cloneEl);
|
||||||
const blob = new Blob([serialized], {type: "image/svg+xml;charset=utf-8"});
|
const blob = new Blob([serialized], {type: "image/svg+xml;charset=utf-8"});
|
||||||
const url = window.URL.createObjectURL(blob);
|
const url = window.URL.createObjectURL(blob);
|
||||||
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
|
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
|
||||||
|
|
@ -461,7 +482,7 @@ function saveGeoJSON_Markers() {
|
||||||
const coordinates = getCoordinates(x, y, 4);
|
const coordinates = getCoordinates(x, y, 4);
|
||||||
const id = `marker${i}`;
|
const id = `marker${i}`;
|
||||||
const note = notes.find(note => note.id === id);
|
const note = notes.find(note => note.id === id);
|
||||||
const properties = {id, type, icon, ...note, size, fill, stroke};
|
const properties = {id, type, icon, x, y, ...note, size, fill, stroke};
|
||||||
return {type: "Feature", geometry: {type: "Point", coordinates}, properties};
|
return {type: "Feature", geometry: {type: "Point", coordinates}, properties};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
// Functions to load and parse .map files
|
// Functions to load and parse .map files
|
||||||
|
|
||||||
function quickLoad() {
|
async function quickLoad() {
|
||||||
ldb.get("lastMap", blob => {
|
const blob = await ldb.get("lastMap");
|
||||||
if (blob) {
|
if (blob) loadMapPrompt(blob);
|
||||||
loadMapPrompt(blob);
|
else {
|
||||||
} else {
|
tip("No map stored. Save map to browser storage first", true, "error", 2000);
|
||||||
tip("No map stored. Save map to storage first", true, "error", 2000);
|
ERROR && console.error("No map stored");
|
||||||
ERROR && console.error("No map stored");
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadFromDropbox() {
|
async function loadFromDropbox() {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
// prepare map data for saving
|
// prepare map data for saving
|
||||||
function getMapData() {
|
function getMapData() {
|
||||||
TIME && console.time("createMapData");
|
|
||||||
|
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
|
const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
|
||||||
const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
|
const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
|
||||||
|
|
@ -116,13 +114,13 @@ function getMapData() {
|
||||||
fonts,
|
fonts,
|
||||||
markers
|
markers
|
||||||
].join("\r\n");
|
].join("\r\n");
|
||||||
TIME && console.timeEnd("createMapData");
|
|
||||||
return mapData;
|
return mapData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download .map file
|
// Download .map file
|
||||||
function dowloadMap() {
|
function dowloadMap() {
|
||||||
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
|
if (customization)
|
||||||
|
return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
|
||||||
closeDialogs("#alert");
|
closeDialogs("#alert");
|
||||||
|
|
||||||
const mapData = getMapData();
|
const mapData = getMapData();
|
||||||
|
|
@ -137,7 +135,8 @@ function dowloadMap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveToDropbox() {
|
async function saveToDropbox() {
|
||||||
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
|
if (customization)
|
||||||
|
return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
|
||||||
closeDialogs("#alert");
|
closeDialogs("#alert");
|
||||||
const mapData = getMapData();
|
const mapData = getMapData();
|
||||||
const filename = getFileName() + ".map";
|
const filename = getFileName() + ".map";
|
||||||
|
|
@ -150,12 +149,36 @@ async function saveToDropbox() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function quickSave() {
|
async function initiateAutosave() {
|
||||||
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
|
const MINUTE = 60000; // munite in milliseconds
|
||||||
|
let lastSavedAt = Date.now();
|
||||||
|
|
||||||
|
async function autosave() {
|
||||||
|
const timeoutMinutes = byId("autosaveIntervalOutput").valueAsNumber;
|
||||||
|
if (!timeoutMinutes) return;
|
||||||
|
|
||||||
|
const diffInMinutes = (Date.now() - lastSavedAt) / MINUTE;
|
||||||
|
if (diffInMinutes < timeoutMinutes) return;
|
||||||
|
if (customization) return tip("Autosave: map cannot be saved in edit mode", false, "warning", 2000);
|
||||||
|
|
||||||
|
tip("Autosave: saving map...", false, "warning", 3000);
|
||||||
|
const mapData = getMapData();
|
||||||
|
const blob = new Blob([mapData], {type: "text/plain"});
|
||||||
|
await ldb.set("lastMap", blob);
|
||||||
|
console.log("Autosaved at", new Date().toLocaleTimeString());
|
||||||
|
lastSavedAt = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(autosave, MINUTE / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function quickSave() {
|
||||||
|
if (customization)
|
||||||
|
return tip("Map cannot be saved when edit mode is active, please exit the mode first", false, "error");
|
||||||
|
|
||||||
const mapData = getMapData();
|
const mapData = getMapData();
|
||||||
const blob = new Blob([mapData], {type: "text/plain"});
|
const blob = new Blob([mapData], {type: "text/plain"});
|
||||||
if (blob) ldb.set("lastMap", blob); // auto-save map
|
await ldb.set("lastMap", blob); // auto-save map
|
||||||
tip("Map is saved to browser memory. Please also save as .map file to secure progress", true, "success", 2000);
|
tip("Map is saved to browser memory. Please also save as .map file to secure progress", true, "success", 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ window.Markers = (function () {
|
||||||
return [
|
return [
|
||||||
{type: "volcanoes", icon: "🌋", dx: 52, px: 13, min: 10, each: 500, multiplier: 1, list: listVolcanoes, add: addVolcano},
|
{type: "volcanoes", icon: "🌋", dx: 52, px: 13, min: 10, each: 500, multiplier: 1, list: listVolcanoes, add: addVolcano},
|
||||||
{type: "hot-springs", icon: "♨️", dy: 52, min: 30, each: 1200, multiplier: 1, list: listHotSprings, add: addHotSpring},
|
{type: "hot-springs", icon: "♨️", dy: 52, min: 30, each: 1200, multiplier: 1, list: listHotSprings, add: addHotSpring},
|
||||||
|
{type: "water-sources", icon: "💧", min: 1, each: 1000, multiplier: 1, list: listWaterSources, add: addWaterSource},
|
||||||
{type: "mines", icon: "⛏️", dx: 48, px: 13, min: 1, each: 15, multiplier: 1, list: listMines, add: addMine},
|
{type: "mines", icon: "⛏️", dx: 48, px: 13, min: 1, each: 15, multiplier: 1, list: listMines, add: addMine},
|
||||||
{type: "bridges", icon: "🌉", px: 14, min: 1, each: 5, multiplier: 1, list: listBridges, add: addBridge},
|
{type: "bridges", icon: "🌉", px: 14, min: 1, each: 5, multiplier: 1, list: listBridges, add: addBridge},
|
||||||
{type: "inns", icon: "🍻", px: 14, min: 1, each: 100, multiplier: 1, list: listInns, add: addInn},
|
{type: "inns", icon: "🍻", px: 14, min: 1, each: 100, multiplier: 1, list: listInns, add: addInn},
|
||||||
|
|
@ -42,15 +43,19 @@ window.Markers = (function () {
|
||||||
{type: "pirates", icon: "🏴☠️", dx: 51, min: 40, each: 300, multiplier: 1, list: listPirates, add: addPirates},
|
{type: "pirates", icon: "🏴☠️", dx: 51, min: 40, each: 300, multiplier: 1, list: listPirates, add: addPirates},
|
||||||
{type: "statues", icon: "🗿", min: 80, each: 1200, multiplier: 1, list: listStatues, add: addStatue},
|
{type: "statues", icon: "🗿", min: 80, each: 1200, multiplier: 1, list: listStatues, add: addStatue},
|
||||||
{type: "ruins", icon: "🏺", min: 80, each: 1200, multiplier: 1, list: listRuins, add: addRuins},
|
{type: "ruins", icon: "🏺", min: 80, each: 1200, multiplier: 1, list: listRuins, add: addRuins},
|
||||||
{type: "circuses", icon: "🎪", min: 80, each: 1000, multiplier: 1, list: listCircuses, add: addCircuses},
|
{type: "libraries", icon: "📚", min: 10, each: 1200, multiplier: 1, list: listLibraries, add: addLibrary},
|
||||||
{type: "jousts", icon: "🤺", dx: 48, min: 5, each: 500, multiplier: 1, list: listJousts, add: addJousts},
|
{type: "circuses", icon: "🎪", min: 80, each: 1000, multiplier: 1, list: listCircuses, add: addCircuse},
|
||||||
{type: "canoes", icon: "🛶", min: 1000, each: 2000, multiplier: 1, list: listCanoes, add: addCanoes},
|
{type: "jousts", icon: "🤺", dx: 48, min: 5, each: 500, multiplier: 1, list: listJousts, add: addJoust},
|
||||||
{type: "migration", icon: "🐗", min: 20, each: 1000, multiplier: 1, list: listMigrations, add: addMigrations},
|
{type: "fairs", icon: "🎠", min: 50, each: 1000, multiplier: 1, list: listFairs, add: addFair},
|
||||||
{type: "dances", icon: "💃🏽", min: 5, each: 60, multiplier: 1, list: listDances, add: addDances},
|
{type: "canoes", icon: "🛶", min: 500, each: 2000, multiplier: 1, list: listCanoes, add: addCanoe},
|
||||||
|
{type: "migration", icon: "🐗", min: 20, each: 1000, multiplier: 1, list: listMigrations, add: addMigration},
|
||||||
|
{type: "dances", icon: "💃🏽", min: 50, each: 1000, multiplier: 1, list: listDances, add: addDances},
|
||||||
{type: "mirage", icon: "💦", min: 10, each: 400, multiplier: 1, list: listMirage, add: addMirage},
|
{type: "mirage", icon: "💦", min: 10, each: 400, multiplier: 1, list: listMirage, add: addMirage},
|
||||||
{type: "caves", icon:"🦇", min: 60, each: 1000, multiplier: 1, list: listCaves, add: addCaves},
|
{type: "caves", icon:"🦇", min: 60, each: 1000, multiplier: 1, list: listCaves, add: addCave},
|
||||||
{type: "portals", icon: "🌀", px: 14, min: 16, each: 8, multiplier: +isFantasy, list: listPortals, add: addPortal},
|
{type: "portals", icon: "🌀", px: 14, min: 16, each: 8, multiplier: +isFantasy, list: listPortals, add: addPortal},
|
||||||
{type: "rifts", icon: "🎆", min: 1, each: 3000, multiplier: +isFantasy, list: listRifts, add: addRifts}
|
{type: "rifts", icon: "🎆", min: 5, each: 3000, multiplier: +isFantasy, list: listRifts, add: addRift},
|
||||||
|
{type: "disturbed-burials", icon: "💀", min: 20, each: 3000, multiplier: +isFantasy, list: listDisturbedBurial, add: addDisturbedBurial},
|
||||||
|
{type: "necropolises", icon: "🪦", min: 20, each: 1000, multiplier: 1, list: listNecropolis, add: addNecropolis},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,7 +177,7 @@ window.Markers = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function listHotSprings({cells}) {
|
function listHotSprings({cells}) {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.h[i] > 50);
|
return cells.i.filter(i => !occupied[i] && cells.h[i] > 50 && cells.culture[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addHotSpring(id, cell) {
|
function addHotSpring(id, cell) {
|
||||||
|
|
@ -180,12 +185,37 @@ window.Markers = (function () {
|
||||||
|
|
||||||
const proper = Names.getCulture(cells.culture[cell]);
|
const proper = Names.getCulture(cells.culture[cell]);
|
||||||
const temp = convertTemperature(gauss(35, 15, 20, 100));
|
const temp = convertTemperature(gauss(35, 15, 20, 100));
|
||||||
const status = P(0.6) ? "geothermal" : P(0.4) ? "springwater" : "natural";
|
const name = P(0.3) ? "Hot Springs of " + proper : P(0.7) ? proper + " Hot Springs" : proper;
|
||||||
notes.push({
|
const legend = `A geothermal springs with naturally heated water that provide relaxation and medicinal benefits. Average temperature is ${temp}.`;
|
||||||
id,
|
|
||||||
name: proper + " Hot Springs",
|
notes.push({id, name, legend});
|
||||||
legend: `A ${status} hot springs area. Average temperature: ${temp}.`
|
}
|
||||||
|
|
||||||
|
function listWaterSources({cells}) {
|
||||||
|
return cells.i.filter(i => !occupied[i] && cells.h[i] > 30 && cells.r[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWaterSource(id, cell) {
|
||||||
|
const {cells} = pack;
|
||||||
|
|
||||||
|
const type = rw({
|
||||||
|
"Healing Spring": 5,
|
||||||
|
"Purifying Well": 2,
|
||||||
|
"Enchanted Reservoir": 1,
|
||||||
|
"Creek of Luck": 1,
|
||||||
|
"Fountain of Youth": 1,
|
||||||
|
"Wisdom Spring": 1,
|
||||||
|
"Spring of Life": 1,
|
||||||
|
"Spring of Youth": 1,
|
||||||
|
"Healing Stream": 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const proper = Names.getCulture(cells.culture[cell]);
|
||||||
|
const name = `${proper} ${type}`;
|
||||||
|
const legend =
|
||||||
|
"This legendary water source is whispered about in ancient tales and believed to possess mystical properties. The spring emanates crystal-clear water, shimmering with an otherworldly iridescence that sparkles even in the dimmest light.";
|
||||||
|
|
||||||
|
notes.push({id, name, legend});
|
||||||
}
|
}
|
||||||
|
|
||||||
function listMines({cells}) {
|
function listMines({cells}) {
|
||||||
|
|
@ -728,7 +758,7 @@ window.Markers = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSacredForest(id, cell) {
|
function addSacredForest(id, cell) {
|
||||||
const {cells, cultures, religions} = pack;
|
const {cells, religions} = pack;
|
||||||
|
|
||||||
const culture = cells.culture[cell];
|
const culture = cells.culture[cell];
|
||||||
const religion = cells.religion[cell];
|
const religion = cells.religion[cell];
|
||||||
|
|
@ -743,7 +773,7 @@ window.Markers = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSacredPinery(id, cell) {
|
function addSacredPinery(id, cell) {
|
||||||
const {cells, cultures, religions} = pack;
|
const {cells, religions} = pack;
|
||||||
|
|
||||||
const culture = cells.culture[cell];
|
const culture = cells.culture[cell];
|
||||||
const religion = cells.religion[cell];
|
const religion = cells.religion[cell];
|
||||||
|
|
@ -766,7 +796,7 @@ window.Markers = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSacredPalmGrove(id, cell) {
|
function addSacredPalmGrove(id, cell) {
|
||||||
const {cells, cultures, religions} = pack;
|
const {cells, religions} = pack;
|
||||||
|
|
||||||
const culture = cells.culture[cell];
|
const culture = cells.culture[cell];
|
||||||
const religion = cells.religion[cell];
|
const religion = cells.religion[cell];
|
||||||
|
|
@ -842,8 +872,8 @@ window.Markers = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPirates(id, cell) {
|
function addPirates(id, cell) {
|
||||||
const name = `Pirates`;
|
const name = "Pirates";
|
||||||
const legend = `Pirate ships have been spotted in these waters.`;
|
const legend = "Pirate ships have been spotted in these waters.";
|
||||||
notes.push({id, name, legend});
|
notes.push({id, name, legend});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -869,7 +899,7 @@ window.Markers = (function () {
|
||||||
"Idol"
|
"Idol"
|
||||||
];
|
];
|
||||||
const scripts = {
|
const scripts = {
|
||||||
cypriot: "𐠁𐠂𐠃𐠄𐠅𐠈𐠊𐠋𐠌𐠍𐠎𐠏𐠐𐠑𐠒𐠓𐠔𐠕𐠖𐠗𐠘𐠙𐠚𐠛𐠜𐠝𐠞𐠟𐠠𐠡𐠢𐠣𐠤𐠥𐠦𐠧𐠨𐠩𐠪𐠫𐠬𐠭𐠮𐠯𐠰𐠱𐠲𐠳𐠴𐠵𐠷𐠸𐠼𐠿 ",
|
cypriot: "𐠁𐠂𐠃𐠄𐠅𐠈𐠊𐠋𐠌𐠍𐠎𐠏𐠐𐠑𐠒𐠓𐠔𐠕𐠖𐠗𐠘𐠙𐠚𐠛𐠜𐠝𐠞𐠟𐠠𐠡𐠢𐠣𐠤𐠥𐠦𐠧𐠨𐠩𐠪𐠫𐠬𐠭𐠮𐠯𐠰𐠱𐠲𐠳𐠴𐠵𐠷𐠸𐠼𐠿 ",
|
||||||
geez: "ሀለሐመሠረሰቀበተኀነአከወዐዘየደገጠጰጸፀፈፐ ",
|
geez: "ሀለሐመሠረሰቀበተኀነአከወዐዘየደገጠጰጸፀፈፐ ",
|
||||||
coptic: "ⲲⲴⲶⲸⲺⲼⲾⳀⳁⳂⳃⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢⳤ⳥⳧⳩⳪ⳫⳬⳭⳲ⳹⳾ ",
|
coptic: "ⲲⲴⲶⲸⲺⲼⲾⳀⳁⳂⳃⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢⳤ⳥⳧⳩⳪ⳫⳬⳭⳲ⳹⳾ ",
|
||||||
tibetan: "ༀ༁༂༃༄༅༆༇༈༉༊་༌༐༑༒༓༔༕༖༗༘༙༚༛༜༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿",
|
tibetan: "ༀ༁༂༃༄༅༆༇༈༉༊་༌༐༑༒༓༔༕༖༗༘༙༚༛༜༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿",
|
||||||
|
|
@ -917,11 +947,25 @@ window.Markers = (function () {
|
||||||
notes.push({id, name, legend});
|
notes.push({id, name, legend});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listLibraries({cells}) {
|
||||||
|
return cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.burg[i] && cells.pop[i] > 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addLibrary(id, cell) {
|
||||||
|
const {cells} = pack;
|
||||||
|
|
||||||
|
const type = rw({Library: 3, Archive: 1, Collection: 1});
|
||||||
|
const name = `${Names.getCulture(cells.culture[cell])} ${type}`;
|
||||||
|
const legend = "A vast collection of knowledge, including many rare and ancient tomes.";
|
||||||
|
|
||||||
|
notes.push({id, name, legend});
|
||||||
|
}
|
||||||
|
|
||||||
function listCircuses({cells}) {
|
function listCircuses({cells}) {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.h[i] >= 20 && pack.cells.road[i]);
|
return cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.h[i] >= 20 && pack.cells.road[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addCircuses(id, cell) {
|
function addCircuse(id, cell) {
|
||||||
const adjectives = [
|
const adjectives = [
|
||||||
"Fantastical",
|
"Fantastical",
|
||||||
"Wonderous",
|
"Wonderous",
|
||||||
|
|
@ -943,7 +987,7 @@ window.Markers = (function () {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.burg[i] && burgs[cells.burg[i]].population > 20);
|
return cells.i.filter(i => !occupied[i] && cells.burg[i] && burgs[cells.burg[i]].population > 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addJousts(id, cell) {
|
function addJoust(id, cell) {
|
||||||
const {cells, burgs} = pack;
|
const {cells, burgs} = pack;
|
||||||
const types = ["Joust", "Competition", "Melee", "Tournament", "Contest"];
|
const types = ["Joust", "Competition", "Melee", "Tournament", "Contest"];
|
||||||
const virtues = ["cunning", "might", "speed", "the greats", "acumen", "brutality"];
|
const virtues = ["cunning", "might", "speed", "the greats", "acumen", "brutality"];
|
||||||
|
|
@ -958,11 +1002,29 @@ window.Markers = (function () {
|
||||||
notes.push({id, name, legend});
|
notes.push({id, name, legend});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listFairs({cells, burgs}) {
|
||||||
|
return cells.i.filter(
|
||||||
|
i => !occupied[i] && cells.burg[i] && burgs[cells.burg[i]].population < 20 && burgs[cells.burg[i]].population < 5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFair(id, cell) {
|
||||||
|
const {cells, burgs} = pack;
|
||||||
|
if (!cells.burg[cell]) return;
|
||||||
|
|
||||||
|
const burgName = burgs[cells.burg[cell]].name;
|
||||||
|
const type = "Fair";
|
||||||
|
|
||||||
|
const name = `${burgName} ${type}`;
|
||||||
|
const legend = `A fair is being held in ${burgName}, with all manner of local and foreign goods and services on offer.`;
|
||||||
|
notes.push({id, name, legend});
|
||||||
|
}
|
||||||
|
|
||||||
function listCanoes({cells}) {
|
function listCanoes({cells}) {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.r[i]);
|
return cells.i.filter(i => !occupied[i] && cells.r[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addCanoes(id, cell) {
|
function addCanoe(id, cell) {
|
||||||
const river = pack.rivers.find(r => r.i === pack.cells.r[cell]);
|
const river = pack.rivers.find(r => r.i === pack.cells.r[cell]);
|
||||||
|
|
||||||
const name = `Minor Jetty`;
|
const name = `Minor Jetty`;
|
||||||
|
|
@ -975,7 +1037,7 @@ window.Markers = (function () {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.h[i] >= 20 && cells.pop[i] <= 2);
|
return cells.i.filter(i => !occupied[i] && cells.h[i] >= 20 && cells.pop[i] <= 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMigrations(id, cell) {
|
function addMigration(id, cell) {
|
||||||
const animals = [
|
const animals = [
|
||||||
"Antelopes",
|
"Antelopes",
|
||||||
"Apes",
|
"Apes",
|
||||||
|
|
@ -1053,7 +1115,10 @@ window.Markers = (function () {
|
||||||
"exhibition",
|
"exhibition",
|
||||||
"carnival",
|
"carnival",
|
||||||
"festival",
|
"festival",
|
||||||
"jubilee"
|
"jubilee",
|
||||||
|
"celebration",
|
||||||
|
"gathering",
|
||||||
|
"fete"
|
||||||
];
|
];
|
||||||
const people = [
|
const people = [
|
||||||
"great and the good",
|
"great and the good",
|
||||||
|
|
@ -1089,7 +1154,7 @@ window.Markers = (function () {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.h[i] >= 50 && cells.pop[i]);
|
return cells.i.filter(i => !occupied[i] && cells.h[i] >= 50 && cells.pop[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addCaves(id, cell) {
|
function addCave(id, cell) {
|
||||||
const {cells} = pack;
|
const {cells} = pack;
|
||||||
|
|
||||||
const formations = {
|
const formations = {
|
||||||
|
|
@ -1144,7 +1209,7 @@ window.Markers = (function () {
|
||||||
return cells.i.filter(i => !occupied[i] && pack.cells.pop[i] <= 3 && biomesData.habitability[pack.cells.biome[i]]);
|
return cells.i.filter(i => !occupied[i] && pack.cells.pop[i] <= 3 && biomesData.habitability[pack.cells.biome[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRifts(id, cell) {
|
function addRift(id, cell) {
|
||||||
const types = ["Demonic", "Interdimensional", "Abyssal", "Cosmic", "Cataclysmic", "Subterranean", "Ancient"];
|
const types = ["Demonic", "Interdimensional", "Abyssal", "Cosmic", "Cataclysmic", "Subterranean", "Ancient"];
|
||||||
|
|
||||||
const descriptions = [
|
const descriptions = [
|
||||||
|
|
@ -1161,5 +1226,49 @@ window.Markers = (function () {
|
||||||
notes.push({id, name, legend});
|
notes.push({id, name, legend});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listDisturbedBurial({cells}) {
|
||||||
|
return cells.i.filter(i => !occupied[i] && cells.h[i] >= 20 && cells.pop[i] > 2);
|
||||||
|
}
|
||||||
|
function addDisturbedBurial(id, cell) {
|
||||||
|
const name = "Disturbed Burial";
|
||||||
|
const legend = "A burial site has been disturbed in this area, causing the dead to rise and attack the living.";
|
||||||
|
notes.push({id, name, legend});
|
||||||
|
}
|
||||||
|
|
||||||
|
function listNecropolis({cells}) {
|
||||||
|
return cells.i.filter(i => !occupied[i] && cells.h[i] >= 20 && cells.pop[i] < 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addNecropolis(id, cell) {
|
||||||
|
const {cells} = pack;
|
||||||
|
|
||||||
|
const toponym = Names.getCulture(cells.culture[cell]);
|
||||||
|
const type = rw({
|
||||||
|
Necropolis: 5,
|
||||||
|
Crypt: 2,
|
||||||
|
Tomb: 2,
|
||||||
|
Graveyard: 1,
|
||||||
|
Cemetery: 2,
|
||||||
|
Mausoleum: 1,
|
||||||
|
Sepulchre: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
const name = `${toponym} ${type}`;
|
||||||
|
const legend = ra([
|
||||||
|
"A foreboding necropolis shrouded in perpetual darkness, where eerie whispers echo through the winding corridors and spectral guardians stand watch over the tombs of long-forgotten souls",
|
||||||
|
"A towering necropolis adorned with macabre sculptures and guarded by formidable undead sentinels. Its ancient halls house the remains of fallen heroes, entombed alongside their cherished relics",
|
||||||
|
"This ethereal necropolis seems suspended between the realms of the living and the dead. Wisps of mist dance around the tombstones, while haunting melodies linger in the air, commemorating the departed",
|
||||||
|
"Rising from the desolate landscape, this sinister necropolis is a testament to necromantic power. Its skeletal spires cast ominous shadows, concealing forbidden knowledge and arcane secrets",
|
||||||
|
"An eerie necropolis where nature intertwines with death. Overgrown tombstones are entwined by thorny vines, and mournful spirits wander among the fading petals of once-vibrant flowers",
|
||||||
|
"A labyrinthine necropolis where each step echoes with haunting murmurs. The walls are adorned with ancient runes, and restless spirits guide or hinder those who dare to delve into its depths",
|
||||||
|
"This cursed necropolis is veiled in perpetual twilight, perpetuating a sense of impending doom. Dark enchantments shroud the tombs, and the moans of anguished souls resound through its crumbling halls",
|
||||||
|
"A sprawling necropolis built within a labyrinthine network of catacombs. Its halls are lined with countless alcoves, each housing the remains of the departed, while the distant sound of rattling bones fills the air",
|
||||||
|
"A desolate necropolis where an eerie stillness reigns. Time seems frozen amidst the decaying mausoleums, and the silence is broken only by the whispers of the wind and the rustle of tattered banners",
|
||||||
|
"A foreboding necropolis perched atop a jagged cliff, overlooking a desolate wasteland. Its towering walls harbor restless spirits, and the imposing gates bear the marks of countless battles and ancient curses"
|
||||||
|
]);
|
||||||
|
|
||||||
|
notes.push({id, name, legend});
|
||||||
|
}
|
||||||
|
|
||||||
return {add, generate, regenerate, getConfig, setConfig, deleteMarker};
|
return {add, generate, regenerate, getConfig, setConfig, deleteMarker};
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,16 @@ window.Religions = (function () {
|
||||||
being: [
|
being: [
|
||||||
"Ancestor",
|
"Ancestor",
|
||||||
"Ancient",
|
"Ancient",
|
||||||
|
"Avatar",
|
||||||
"Brother",
|
"Brother",
|
||||||
|
"Champion",
|
||||||
"Chief",
|
"Chief",
|
||||||
"Council",
|
"Council",
|
||||||
"Creator",
|
"Creator",
|
||||||
"Deity",
|
"Deity",
|
||||||
|
"Divine One",
|
||||||
"Elder",
|
"Elder",
|
||||||
|
"Enlightened Being",
|
||||||
"Father",
|
"Father",
|
||||||
"Forebear",
|
"Forebear",
|
||||||
"Forefather",
|
"Forefather",
|
||||||
|
|
@ -45,17 +49,25 @@ window.Religions = (function () {
|
||||||
"God",
|
"God",
|
||||||
"Goddess",
|
"Goddess",
|
||||||
"Guardian",
|
"Guardian",
|
||||||
|
"Guide",
|
||||||
|
"Hierach",
|
||||||
"Lady",
|
"Lady",
|
||||||
"Lord",
|
"Lord",
|
||||||
"Maker",
|
"Maker",
|
||||||
"Master",
|
"Master",
|
||||||
"Mother",
|
"Mother",
|
||||||
"Numen",
|
"Numen",
|
||||||
|
"Oracle",
|
||||||
"Overlord",
|
"Overlord",
|
||||||
|
"Protector",
|
||||||
"Reaper",
|
"Reaper",
|
||||||
"Ruler",
|
"Ruler",
|
||||||
|
"Sage",
|
||||||
|
"Seer",
|
||||||
"Sister",
|
"Sister",
|
||||||
"Spirit",
|
"Spirit",
|
||||||
|
"Supreme Being",
|
||||||
|
"Transcendent",
|
||||||
"Virgin"
|
"Virgin"
|
||||||
],
|
],
|
||||||
animal: [
|
animal: [
|
||||||
|
|
@ -71,36 +83,47 @@ window.Religions = (function () {
|
||||||
"Camel",
|
"Camel",
|
||||||
"Cat",
|
"Cat",
|
||||||
"Centaur",
|
"Centaur",
|
||||||
|
"Cerberus",
|
||||||
"Chimera",
|
"Chimera",
|
||||||
"Cobra",
|
"Cobra",
|
||||||
|
"Cockatrice",
|
||||||
"Crane",
|
"Crane",
|
||||||
"Crocodile",
|
"Crocodile",
|
||||||
"Crow",
|
"Crow",
|
||||||
"Cyclope",
|
"Cyclope",
|
||||||
"Deer",
|
"Deer",
|
||||||
"Dog",
|
"Dog",
|
||||||
|
"Direwolf",
|
||||||
|
"Drake",
|
||||||
"Dragon",
|
"Dragon",
|
||||||
"Eagle",
|
"Eagle",
|
||||||
|
"Elephant",
|
||||||
"Elk",
|
"Elk",
|
||||||
"Falcon",
|
"Falcon",
|
||||||
"Fox",
|
"Fox",
|
||||||
"Goat",
|
"Goat",
|
||||||
"Goose",
|
"Goose",
|
||||||
|
"Gorgon",
|
||||||
|
"Gryphon",
|
||||||
"Hare",
|
"Hare",
|
||||||
"Hawk",
|
"Hawk",
|
||||||
"Heron",
|
"Heron",
|
||||||
|
"Hippogriff",
|
||||||
"Horse",
|
"Horse",
|
||||||
"Hound",
|
"Hound",
|
||||||
"Hyena",
|
"Hyena",
|
||||||
"Ibis",
|
"Ibis",
|
||||||
"Jackal",
|
"Jackal",
|
||||||
"Jaguar",
|
"Jaguar",
|
||||||
|
"Kitsune",
|
||||||
"Kraken",
|
"Kraken",
|
||||||
"Lark",
|
"Lark",
|
||||||
"Leopard",
|
"Leopard",
|
||||||
"Lion",
|
"Lion",
|
||||||
|
"Manticore",
|
||||||
"Mantis",
|
"Mantis",
|
||||||
"Marten",
|
"Marten",
|
||||||
|
"Minotaur",
|
||||||
"Moose",
|
"Moose",
|
||||||
"Mule",
|
"Mule",
|
||||||
"Narwhal",
|
"Narwhal",
|
||||||
|
|
@ -109,8 +132,10 @@ window.Religions = (function () {
|
||||||
"Panther",
|
"Panther",
|
||||||
"Pegasus",
|
"Pegasus",
|
||||||
"Phoenix",
|
"Phoenix",
|
||||||
|
"Python",
|
||||||
"Rat",
|
"Rat",
|
||||||
"Raven",
|
"Raven",
|
||||||
|
"Roc",
|
||||||
"Rook",
|
"Rook",
|
||||||
"Scorpion",
|
"Scorpion",
|
||||||
"Serpent",
|
"Serpent",
|
||||||
|
|
@ -129,7 +154,8 @@ window.Religions = (function () {
|
||||||
"Wolf",
|
"Wolf",
|
||||||
"Wolverine",
|
"Wolverine",
|
||||||
"Worm",
|
"Worm",
|
||||||
"Wyvern"
|
"Wyvern",
|
||||||
|
"Yeti"
|
||||||
],
|
],
|
||||||
adjective: [
|
adjective: [
|
||||||
"Aggressive",
|
"Aggressive",
|
||||||
|
|
@ -146,6 +172,7 @@ window.Religions = (function () {
|
||||||
"Brutal",
|
"Brutal",
|
||||||
"Burning",
|
"Burning",
|
||||||
"Calm",
|
"Calm",
|
||||||
|
"Celestial",
|
||||||
"Cheerful",
|
"Cheerful",
|
||||||
"Crazy",
|
"Crazy",
|
||||||
"Cruel",
|
"Cruel",
|
||||||
|
|
@ -157,6 +184,10 @@ window.Religions = (function () {
|
||||||
"Divine",
|
"Divine",
|
||||||
"Dying",
|
"Dying",
|
||||||
"Eternal",
|
"Eternal",
|
||||||
|
"Ethernal",
|
||||||
|
"Empyreal",
|
||||||
|
"Enigmatic",
|
||||||
|
"Enlightened",
|
||||||
"Evil",
|
"Evil",
|
||||||
"Explicit",
|
"Explicit",
|
||||||
"Fair",
|
"Fair",
|
||||||
|
|
@ -177,7 +208,9 @@ window.Religions = (function () {
|
||||||
"Honest",
|
"Honest",
|
||||||
"Huge",
|
"Huge",
|
||||||
"Hungry",
|
"Hungry",
|
||||||
|
"Illustrious",
|
||||||
"Immutable",
|
"Immutable",
|
||||||
|
"Ineffable",
|
||||||
"Infallible",
|
"Infallible",
|
||||||
"Inherent",
|
"Inherent",
|
||||||
"Last",
|
"Last",
|
||||||
|
|
@ -190,31 +223,46 @@ window.Religions = (function () {
|
||||||
"Main",
|
"Main",
|
||||||
"Major",
|
"Major",
|
||||||
"Marine",
|
"Marine",
|
||||||
|
"Mythical",
|
||||||
|
"Mystical",
|
||||||
"Naval",
|
"Naval",
|
||||||
"New",
|
"New",
|
||||||
|
"Noble",
|
||||||
"Old",
|
"Old",
|
||||||
|
"Otherworldly",
|
||||||
"Patient",
|
"Patient",
|
||||||
"Peaceful",
|
"Peaceful",
|
||||||
"Pregnant",
|
"Pregnant",
|
||||||
"Prime",
|
"Prime",
|
||||||
"Proud",
|
"Proud",
|
||||||
"Pure",
|
"Pure",
|
||||||
|
"Radiant",
|
||||||
|
"Resplendent",
|
||||||
"Sacred",
|
"Sacred",
|
||||||
|
"Sacrosanct",
|
||||||
"Sad",
|
"Sad",
|
||||||
"Scary",
|
"Scary",
|
||||||
"Secret",
|
"Secret",
|
||||||
"Selected",
|
"Selected",
|
||||||
|
"Serene",
|
||||||
"Severe",
|
"Severe",
|
||||||
"Silent",
|
"Silent",
|
||||||
"Sleeping",
|
"Sleeping",
|
||||||
"Slumbering",
|
"Slumbering",
|
||||||
|
"Sovereign",
|
||||||
"Strong",
|
"Strong",
|
||||||
"Sunny",
|
"Sunny",
|
||||||
"Superior",
|
"Superior",
|
||||||
|
"Supernatural",
|
||||||
"Sustainable",
|
"Sustainable",
|
||||||
|
"Transcendent",
|
||||||
|
"Transcendental",
|
||||||
"Troubled",
|
"Troubled",
|
||||||
|
"Unearthly",
|
||||||
|
"Unfathomable",
|
||||||
"Unhappy",
|
"Unhappy",
|
||||||
"Unknown",
|
"Unknown",
|
||||||
|
"Unseen",
|
||||||
"Waking",
|
"Waking",
|
||||||
"Wild",
|
"Wild",
|
||||||
"Wise",
|
"Wise",
|
||||||
|
|
@ -282,26 +330,61 @@ window.Religions = (function () {
|
||||||
"Black",
|
"Black",
|
||||||
"Blue",
|
"Blue",
|
||||||
"Bright",
|
"Bright",
|
||||||
|
"Bronze",
|
||||||
"Brown",
|
"Brown",
|
||||||
|
"Coral",
|
||||||
|
"Crimson",
|
||||||
"Dark",
|
"Dark",
|
||||||
|
"Emerald",
|
||||||
"Golden",
|
"Golden",
|
||||||
"Green",
|
"Green",
|
||||||
"Grey",
|
"Grey",
|
||||||
|
"Indigo",
|
||||||
|
"Lavender",
|
||||||
"Light",
|
"Light",
|
||||||
|
"Magenta",
|
||||||
|
"Maroon",
|
||||||
"Orange",
|
"Orange",
|
||||||
"Pink",
|
"Pink",
|
||||||
|
"Plum",
|
||||||
"Purple",
|
"Purple",
|
||||||
"Red",
|
"Red",
|
||||||
|
"Ruby",
|
||||||
|
"Sapphire",
|
||||||
|
"Teal",
|
||||||
|
"Turquoise",
|
||||||
"White",
|
"White",
|
||||||
"Yellow"
|
"Yellow"
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const forms = {
|
const forms = {
|
||||||
Folk: {Shamanism: 2, Animism: 2, "Ancestor worship": 1, Polytheism: 2},
|
Folk: {
|
||||||
Organized: {Polytheism: 5, Dualism: 1, Monotheism: 4, "Non-theism": 1},
|
Shamanism: 4,
|
||||||
Cult: {Cult: 1, "Dark Cult": 1},
|
Animism: 4,
|
||||||
Heresy: {Heresy: 1}
|
Polytheism: 4,
|
||||||
|
Totemism: 2,
|
||||||
|
Druidism: 1,
|
||||||
|
"Ancestor Worship": 1,
|
||||||
|
"Nature Worship": 1
|
||||||
|
},
|
||||||
|
Organized: {
|
||||||
|
Polytheism: 14,
|
||||||
|
Monotheism: 12,
|
||||||
|
Dualism: 6,
|
||||||
|
Pantheism: 6,
|
||||||
|
"Non-theism": 4,
|
||||||
|
Henotheism: 1,
|
||||||
|
Panentheism: 1
|
||||||
|
},
|
||||||
|
Cult: {
|
||||||
|
Cult: 2,
|
||||||
|
"Dark Cult": 2,
|
||||||
|
Sect: 1
|
||||||
|
},
|
||||||
|
Heresy: {
|
||||||
|
Heresy: 1
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const namingMethods = {
|
const namingMethods = {
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,9 @@ function overviewBurgs() {
|
||||||
data-type="${type}"
|
data-type="${type}"
|
||||||
>
|
>
|
||||||
<span data-tip="Click to zoom into view" class="icon-dot-circled pointer"></span>
|
<span data-tip="Click to zoom into view" class="icon-dot-circled pointer"></span>
|
||||||
<input data-tip="Burg name. Click and type to change" class="burgName" value="${b.name}" autocorrect="off" spellcheck="false" />
|
<input data-tip="Burg name. Click and type to change" class="burgName" value="${
|
||||||
|
b.name
|
||||||
|
}" autocorrect="off" spellcheck="false" />
|
||||||
<input data-tip="Burg province" class="burgState" value="${province}" disabled />
|
<input data-tip="Burg province" class="burgState" value="${province}" disabled />
|
||||||
<input data-tip="Burg state" class="burgState" value="${state}" disabled />
|
<input data-tip="Burg state" class="burgState" value="${state}" disabled />
|
||||||
<select data-tip="Dominant culture. Click to change burg culture (to change cell culture use Cultures Editor)" class="stateCulture">
|
<select data-tip="Dominant culture. Click to change burg culture (to change cell culture use Cultures Editor)" class="stateCulture">
|
||||||
|
|
@ -106,10 +108,14 @@ function overviewBurgs() {
|
||||||
data-tip="${b.capital ? " This burg is a state capital" : "Click to assign a capital status"}"
|
data-tip="${b.capital ? " This burg is a state capital" : "Click to assign a capital status"}"
|
||||||
class="icon-star-empty${b.capital ? "" : " inactive pointer"}"
|
class="icon-star-empty${b.capital ? "" : " inactive pointer"}"
|
||||||
></span>
|
></span>
|
||||||
<span data-tip="Click to toggle port status" class="icon-anchor pointer${b.port ? "" : " inactive"}" style="font-size:.9em"></span>
|
<span data-tip="Click to toggle port status" class="icon-anchor pointer${
|
||||||
|
b.port ? "" : " inactive"
|
||||||
|
}" style="font-size:.9em"></span>
|
||||||
</div>
|
</div>
|
||||||
<span data-tip="Edit burg" class="icon-pencil"></span>
|
<span data-tip="Edit burg" class="icon-pencil"></span>
|
||||||
<span class="locks pointer ${b.lock ? "icon-lock" : "icon-lock-open inactive"}" onmouseover="showElementLockTip(event)"></span>
|
<span class="locks pointer ${
|
||||||
|
b.lock ? "icon-lock" : "icon-lock-open inactive"
|
||||||
|
}" onmouseover="showElementLockTip(event)"></span>
|
||||||
<span data-tip="Remove burg" class="icon-trash-empty"></span>
|
<span data-tip="Remove burg" class="icon-trash-empty"></span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
@ -125,8 +131,12 @@ function overviewBurgs() {
|
||||||
body.querySelectorAll("div > input.burgName").forEach(el => el.addEventListener("input", changeBurgName));
|
body.querySelectorAll("div > input.burgName").forEach(el => el.addEventListener("input", changeBurgName));
|
||||||
body.querySelectorAll("div > span.icon-dot-circled").forEach(el => el.addEventListener("click", zoomIntoBurg));
|
body.querySelectorAll("div > span.icon-dot-circled").forEach(el => el.addEventListener("click", zoomIntoBurg));
|
||||||
body.querySelectorAll("div > select.stateCulture").forEach(el => el.addEventListener("change", changeBurgCulture));
|
body.querySelectorAll("div > select.stateCulture").forEach(el => el.addEventListener("change", changeBurgCulture));
|
||||||
body.querySelectorAll("div > input.burgPopulation").forEach(el => el.addEventListener("change", changeBurgPopulation));
|
body
|
||||||
body.querySelectorAll("div > span.icon-star-empty").forEach(el => el.addEventListener("click", toggleCapitalStatus));
|
.querySelectorAll("div > input.burgPopulation")
|
||||||
|
.forEach(el => el.addEventListener("change", changeBurgPopulation));
|
||||||
|
body
|
||||||
|
.querySelectorAll("div > span.icon-star-empty")
|
||||||
|
.forEach(el => el.addEventListener("click", toggleCapitalStatus));
|
||||||
body.querySelectorAll("div > span.icon-anchor").forEach(el => el.addEventListener("click", togglePortStatus));
|
body.querySelectorAll("div > span.icon-anchor").forEach(el => el.addEventListener("click", togglePortStatus));
|
||||||
body.querySelectorAll("div > span.locks").forEach(el => el.addEventListener("click", toggleBurgLockStatus));
|
body.querySelectorAll("div > span.locks").forEach(el => el.addEventListener("click", toggleBurgLockStatus));
|
||||||
body.querySelectorAll("div > span.icon-pencil").forEach(el => el.addEventListener("click", openBurgEditor));
|
body.querySelectorAll("div > span.icon-pencil").forEach(el => el.addEventListener("click", openBurgEditor));
|
||||||
|
|
@ -137,7 +147,9 @@ function overviewBurgs() {
|
||||||
|
|
||||||
function getCultureOptions(culture) {
|
function getCultureOptions(culture) {
|
||||||
let options = "";
|
let options = "";
|
||||||
pack.cultures.filter(c => !c.removed).forEach(c => (options += `<option ${c.i === culture ? "selected" : ""} value="${c.i}">${c.name}</option>`));
|
pack.cultures
|
||||||
|
.filter(c => !c.removed)
|
||||||
|
.forEach(c => (options += `<option ${c.i === culture ? "selected" : ""} value="${c.i}">${c.name}</option>`));
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,7 +240,8 @@ function overviewBurgs() {
|
||||||
|
|
||||||
function triggerBurgRemove() {
|
function triggerBurgRemove() {
|
||||||
const burg = +this.parentNode.dataset.id;
|
const burg = +this.parentNode.dataset.id;
|
||||||
if (pack.burgs[burg].capital) return tip("You cannot remove the capital. Please change the capital first", false, "error");
|
if (pack.burgs[burg].capital)
|
||||||
|
return tip("You cannot remove the capital. Please change the capital first", false, "error");
|
||||||
|
|
||||||
confirmationDialog({
|
confirmationDialog({
|
||||||
title: "Remove burg",
|
title: "Remove burg",
|
||||||
|
|
@ -266,8 +279,10 @@ function overviewBurgs() {
|
||||||
function addBurgOnClick() {
|
function addBurgOnClick() {
|
||||||
const point = d3.mouse(this);
|
const point = d3.mouse(this);
|
||||||
const cell = findCell(point[0], point[1]);
|
const cell = findCell(point[0], point[1]);
|
||||||
if (pack.cells.h[cell] < 20) return tip("You cannot place state into the water. Please click on a land cell", false, "error");
|
if (pack.cells.h[cell] < 20)
|
||||||
if (pack.cells.burg[cell]) return tip("There is already a burg in this cell. Please select a free cell", false, "error");
|
return tip("You cannot place state into the water. Please click on a land cell", false, "error");
|
||||||
|
if (pack.cells.burg[cell])
|
||||||
|
return tip("There is already a burg in this cell. Please select a free cell", false, "error");
|
||||||
|
|
||||||
addBurg(point); // add new burg
|
addBurg(point); // add new burg
|
||||||
|
|
||||||
|
|
@ -301,7 +316,19 @@ function overviewBurgs() {
|
||||||
const capital = b.capital;
|
const capital = b.capital;
|
||||||
const province = pack.cells.province[b.cell];
|
const province = pack.cells.province[b.cell];
|
||||||
const parent = province ? province + states.length - 1 : b.state;
|
const parent = province ? province + states.length - 1 : b.state;
|
||||||
return {id, i: b.i, state: b.state, culture: b.culture, province, parent, name: b.name, population, capital, x: b.x, y: b.y};
|
return {
|
||||||
|
id,
|
||||||
|
i: b.i,
|
||||||
|
state: b.state,
|
||||||
|
culture: b.culture,
|
||||||
|
province,
|
||||||
|
parent,
|
||||||
|
name: b.name,
|
||||||
|
population,
|
||||||
|
capital,
|
||||||
|
x: b.x,
|
||||||
|
y: b.y
|
||||||
|
};
|
||||||
});
|
});
|
||||||
const data = states.concat(burgs);
|
const data = states.concat(burgs);
|
||||||
if (data.length < 2) return tip("No burgs to show", false, "error");
|
if (data.length < 2) return tip("No burgs to show", false, "error");
|
||||||
|
|
@ -452,7 +479,7 @@ function overviewBurgs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadBurgsData() {
|
function downloadBurgsData() {
|
||||||
let data = `Id,Burg,Province,Province Full Name,State,State Full Name,Culture,Religion,Population,Latitude,Longitude,Elevation (${heightUnit.value}),Capital,Port,Citadel,Walls,Plaza,Temple,Shanty Town`; // headers
|
let data = `Id,Burg,Province,Province Full Name,State,State Full Name,Culture,Religion,Population,X,Y,Latitude,Longitude,Elevation (${heightUnit.value}),Capital,Port,Citadel,Walls,Plaza,Temple,Shanty Town`; // headers
|
||||||
if (options.showMFCGMap) data += `,City Generator Link`;
|
if (options.showMFCGMap) data += `,City Generator Link`;
|
||||||
data += "\n";
|
data += "\n";
|
||||||
|
|
||||||
|
|
@ -471,6 +498,8 @@ function overviewBurgs() {
|
||||||
data += rn(b.population * populationRate * urbanization) + ",";
|
data += rn(b.population * populationRate * urbanization) + ",";
|
||||||
|
|
||||||
// add geography data
|
// add geography data
|
||||||
|
data += b.x + ",";
|
||||||
|
data += b.y + ",";
|
||||||
data += getLatitude(b.y, 2) + ",";
|
data += getLatitude(b.y, 2) + ",";
|
||||||
data += getLongitude(b.x, 2) + ",";
|
data += getLongitude(b.x, 2) + ",";
|
||||||
data += parseInt(getHeight(pack.cells.h[b.cell])) + ",";
|
data += parseInt(getHeight(pack.cells.h[b.cell])) + ",";
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,12 @@ function editEmblem(type, id, el) {
|
||||||
|
|
||||||
function defineEmblemData(e) {
|
function defineEmblemData(e) {
|
||||||
const parent = e.target.parentNode;
|
const parent = e.target.parentNode;
|
||||||
const [g, t] = parent.id === "burgEmblems" ? [pack.burgs, "burg"] : parent.id === "provinceEmblems" ? [pack.provinces, "province"] : [pack.states, "state"];
|
const [g, t] =
|
||||||
|
parent.id === "burgEmblems"
|
||||||
|
? [pack.burgs, "burg"]
|
||||||
|
: parent.id === "provinceEmblems"
|
||||||
|
? [pack.provinces, "province"]
|
||||||
|
: [pack.states, "state"];
|
||||||
const i = +e.target.dataset.i;
|
const i = +e.target.dataset.i;
|
||||||
type = t;
|
type = t;
|
||||||
id = type + "COA" + i;
|
id = type + "COA" + i;
|
||||||
|
|
@ -88,8 +93,12 @@ function editEmblem(type, id, el) {
|
||||||
|
|
||||||
emblemBurgs.options.length = 0;
|
emblemBurgs.options.length = 0;
|
||||||
emblemBurgs.options.add(new Option("", 0, false, !burg));
|
emblemBurgs.options.add(new Option("", 0, false, !burg));
|
||||||
const burgList = validBurgs.filter(burg => (province ? pack.cells.province[burg.cell] === province : burg.state === state));
|
const burgList = validBurgs.filter(burg =>
|
||||||
burgList.forEach(b => emblemBurgs.options.add(new Option(b.capital ? "👑 " + b.name : b.name, b.i, false, b.i === burg)));
|
province ? pack.cells.province[burg.cell] === province : burg.state === state
|
||||||
|
);
|
||||||
|
burgList.forEach(b =>
|
||||||
|
emblemBurgs.options.add(new Option(b.capital ? "👑 " + b.name : b.name, b.i, false, b.i === burg))
|
||||||
|
);
|
||||||
emblemBurgs.options[0].disabled = true;
|
emblemBurgs.options[0].disabled = true;
|
||||||
|
|
||||||
COArenderer.trigger(id, el.coa);
|
COArenderer.trigger(id, el.coa);
|
||||||
|
|
@ -224,12 +233,15 @@ function editEmblem(type, id, el) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function upload(type) {
|
function upload(type) {
|
||||||
const input = type === "image" ? document.getElementById("emblemImageToLoad") : document.getElementById("emblemSVGToLoad");
|
const input =
|
||||||
|
type === "image" ? document.getElementById("emblemImageToLoad") : document.getElementById("emblemSVGToLoad");
|
||||||
const file = input.files[0];
|
const file = input.files[0];
|
||||||
input.value = "";
|
input.value = "";
|
||||||
|
|
||||||
if (file.size > 500000) {
|
if (file.size > 500000) {
|
||||||
tip(`File is too big, please optimize file size up to 500kB and re-upload. Recommended size is 200x200 px and up to 100kB`, true, "error", 5000);
|
const message =
|
||||||
|
"File is too big, please optimize file size up to 500kB and re-upload. Recommended size is 200x200 px and up to 100kB";
|
||||||
|
tip(message, true, "error", 5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,36 +250,37 @@ function editEmblem(type, id, el) {
|
||||||
reader.onload = function (readerEvent) {
|
reader.onload = function (readerEvent) {
|
||||||
const result = readerEvent.target.result;
|
const result = readerEvent.target.result;
|
||||||
const defs = document.getElementById("defs-emblems");
|
const defs = document.getElementById("defs-emblems");
|
||||||
const coa = document.getElementById(id); // old emblem
|
const oldEmblem = document.getElementById(id);
|
||||||
|
|
||||||
if (type === "image") {
|
let href = result; // raster images
|
||||||
const svg = `<svg id="${id}" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><image x="0" y="0" width="200" height="200" href="${result}"/></svg>`;
|
if (type === "svg") {
|
||||||
defs.insertAdjacentHTML("beforeend", svg);
|
|
||||||
} else {
|
|
||||||
const el = document.createElement("html");
|
const el = document.createElement("html");
|
||||||
el.innerHTML = result;
|
el.innerHTML = result;
|
||||||
|
|
||||||
// remove sodipodi and inkscape attributes
|
|
||||||
el.querySelectorAll("*").forEach(el => {
|
el.querySelectorAll("*").forEach(el => {
|
||||||
const attributes = el.getAttributeNames();
|
if (el.id === "adobe_illustrator_pgf") el.remove(); // remove Adobe Illustrator inner data
|
||||||
attributes.forEach(attr => {
|
|
||||||
|
el.getAttributeNames().forEach(attr => {
|
||||||
|
// remove sodipodi and inkscape attributes
|
||||||
if (attr.includes("inkscape") || attr.includes("sodipodi")) el.removeAttribute(attr);
|
if (attr.includes("inkscape") || attr.includes("sodipodi")) el.removeAttribute(attr);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const svg = el.querySelector("svg");
|
const svg = el.querySelector("svg");
|
||||||
if (!svg) {
|
if (!svg) {
|
||||||
tip("The file should be prepated for load to FMG. Please use Armoria or other relevant tools", false, "error");
|
const message = "The file is not a valid SVG. Please use Armoria or other relevant tools";
|
||||||
|
tip(message, false, "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newEmblem = defs.appendChild(svg);
|
const serialized = new XMLSerializer().serializeToString(svg);
|
||||||
newEmblem.id = id;
|
href = "data:image/svg+xml;base64," + window.btoa(serialized);
|
||||||
newEmblem.setAttribute("width", 200);
|
|
||||||
newEmblem.setAttribute("height", 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coa) coa.remove(); // remove old emblem
|
const svg = `<svg id="${id}" viewBox="0 0 200 200"><image width="200" height="200" href="${href}"/></svg>`;
|
||||||
|
defs.insertAdjacentHTML("beforeend", svg);
|
||||||
|
|
||||||
|
if (oldEmblem) oldEmblem.remove();
|
||||||
el.coa = "custom";
|
el.coa = "custom";
|
||||||
emblemShapeSelector.disabled = true;
|
emblemShapeSelector.disabled = true;
|
||||||
};
|
};
|
||||||
|
|
@ -351,7 +364,9 @@ function editEmblem(type, id, el) {
|
||||||
validStates
|
validStates
|
||||||
.map(state => {
|
.map(state => {
|
||||||
const el = document.getElementById("stateCOA" + state.i);
|
const el = document.getElementById("stateCOA" + state.i);
|
||||||
return `<figure id="state_${state.i}"><a href="#provinces_${state.i}"><figcaption>${state.fullName}</figcaption>${getSVG(el, 200)}</a></figure>`;
|
return `<figure id="state_${state.i}"><a href="#provinces_${state.i}"><figcaption>${
|
||||||
|
state.fullName
|
||||||
|
}</figcaption>${getSVG(el, 200)}</a></figure>`;
|
||||||
})
|
})
|
||||||
.join("") +
|
.join("") +
|
||||||
`</div>`;
|
`</div>`;
|
||||||
|
|
@ -362,13 +377,14 @@ function editEmblem(type, id, el) {
|
||||||
const figures = stateProvinces
|
const figures = stateProvinces
|
||||||
.map(province => {
|
.map(province => {
|
||||||
const el = document.getElementById("provinceCOA" + province.i);
|
const el = document.getElementById("provinceCOA" + province.i);
|
||||||
return `<figure id="province_${province.i}"><a href="#burgs_${province.i}"><figcaption>${province.fullName}</figcaption>${getSVG(
|
return `<figure id="province_${province.i}"><a href="#burgs_${province.i}"><figcaption>${
|
||||||
el,
|
province.fullName
|
||||||
200
|
}</figcaption>${getSVG(el, 200)}</a></figure>`;
|
||||||
)}</a></figure>`;
|
|
||||||
})
|
})
|
||||||
.join("");
|
.join("");
|
||||||
return stateProvinces.length ? `<div id="provinces_${state.i}">${back}<h2>${state.fullName} provinces</h2>${figures}</div>` : "";
|
return stateProvinces.length
|
||||||
|
? `<div id="provinces_${state.i}">${back}<h2>${state.fullName} provinces</h2>${figures}</div>`
|
||||||
|
: "";
|
||||||
})
|
})
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
|
|
@ -385,7 +401,9 @@ function editEmblem(type, id, el) {
|
||||||
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${getSVG(el, 200)}</figure>`;
|
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${getSVG(el, 200)}</figure>`;
|
||||||
})
|
})
|
||||||
.join("");
|
.join("");
|
||||||
return provinceBurgs.length ? `<div id="burgs_${province.i}">${back}<h2>${province.fullName} burgs</h2>${provinceBurgFigures}</div>` : "";
|
return provinceBurgs.length
|
||||||
|
? `<div id="burgs_${province.i}">${back}<h2>${province.fullName} burgs</h2>${provinceBurgFigures}</div>`
|
||||||
|
: "";
|
||||||
})
|
})
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
|
|
@ -464,7 +482,7 @@ function editEmblem(type, id, el) {
|
||||||
}
|
}
|
||||||
div > a {
|
div > a {
|
||||||
float: right;
|
float: right;
|
||||||
font-family: monospace;
|
font-family: var(--monospace);
|
||||||
margin-top: 0.8em;
|
margin-top: 0.8em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,12 @@ function overviewMarkers() {
|
||||||
<div data-tip="Marker icon and type" style="width:12em">${icon} ${type}</div>
|
<div data-tip="Marker icon and type" style="width:12em">${icon} ${type}</div>
|
||||||
<span style="padding-right:.1em" data-tip="Edit marker" class="icon-pencil"></span>
|
<span style="padding-right:.1em" data-tip="Edit marker" class="icon-pencil"></span>
|
||||||
<span style="padding-right:.1em" data-tip="Focus on marker position" class="icon-dot-circled pointer"></span>
|
<span style="padding-right:.1em" data-tip="Focus on marker position" class="icon-dot-circled pointer"></span>
|
||||||
<span style="padding-right:.1em" data-tip="Pin marker (display only pinned markers)" class="icon-pin ${pinned ? "" : "inactive"}" pointer"></span>
|
<span style="padding-right:.1em" data-tip="Pin marker (display only pinned markers)" class="icon-pin ${
|
||||||
<span style="padding-right:.1em" class="locks pointer ${lock ? "icon-lock" : "icon-lock-open inactive"}" onmouseover="showElementLockTip(event)"></span>
|
pinned ? "" : "inactive"
|
||||||
|
}" pointer"></span>
|
||||||
|
<span style="padding-right:.1em" class="locks pointer ${
|
||||||
|
lock ? "icon-lock" : "icon-lock-open inactive"
|
||||||
|
}" onmouseover="showElementLockTip(event)"></span>
|
||||||
<span data-tip="Remove marker" class="icon-trash-empty"></span>
|
<span data-tip="Remove marker" class="icon-trash-empty"></span>
|
||||||
</div>`;
|
</div>`;
|
||||||
})
|
})
|
||||||
|
|
@ -170,16 +174,20 @@ function overviewMarkers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportMarkers() {
|
function exportMarkers() {
|
||||||
const headers = "Id,Type,Icon,Name,Note,X,Y\n";
|
const headers = "Id,Type,Icon,Name,Note,X,Y,Latitude,Longitude\n";
|
||||||
const quote = s => '"' + s.replaceAll('"', '""') + '"';
|
const quote = s => '"' + s.replaceAll('"', '""') + '"';
|
||||||
|
|
||||||
const body = pack.markers.map(marker => {
|
const body = pack.markers.map(marker => {
|
||||||
const {i, type, icon, x, y} = marker;
|
const {i, type, icon, x, y} = marker;
|
||||||
const id = `marker${i}`;
|
const id = `marker${i}`;
|
||||||
const note = notes.find(note => note.id === id);
|
const note = notes.find(note => note.id === id);
|
||||||
const name = note ? quote(note.name) : 'Unknown';
|
const name = note ? quote(note.name) : "Unknown";
|
||||||
const legend = note ? quote(note.legend) : '';
|
const legend = note ? quote(note.legend) : "";
|
||||||
return [id, type, icon, name, legend, x, y].join(",");
|
|
||||||
|
const lat = getLatitude(y, 2);
|
||||||
|
const lon = getLongitude(x, 2);
|
||||||
|
|
||||||
|
return [id, type, icon, name, legend, x, y, lat, lon].join(",");
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = headers + body.join("\n");
|
const data = headers + body.join("\n");
|
||||||
|
|
|
||||||
|
|
@ -23,23 +23,11 @@ function editNamesbase() {
|
||||||
|
|
||||||
const uploader = document.getElementById("namesbaseToLoad");
|
const uploader = document.getElementById("namesbaseToLoad");
|
||||||
document.getElementById("namesbaseUpload").addEventListener("click", () => {
|
document.getElementById("namesbaseUpload").addEventListener("click", () => {
|
||||||
uploader.addEventListener(
|
uploader.addEventListener("change", e => uploadFile(e.target, d => namesbaseUpload(d, true)), {once: true});
|
||||||
"change",
|
|
||||||
function (event) {
|
|
||||||
uploadFile(event.target, d => namesbaseUpload(d, true));
|
|
||||||
},
|
|
||||||
{once: true}
|
|
||||||
);
|
|
||||||
uploader.click();
|
uploader.click();
|
||||||
});
|
});
|
||||||
document.getElementById("namesbaseUploadExtend").addEventListener("click", () => {
|
document.getElementById("namesbaseUploadExtend").addEventListener("click", () => {
|
||||||
uploader.addEventListener(
|
uploader.addEventListener("change", e => uploadFile(e.target, d => namesbaseUpload(d, false)), {once: true});
|
||||||
"change",
|
|
||||||
function (event) {
|
|
||||||
uploadFile(event.target, d => namesbaseUpload(d, false));
|
|
||||||
},
|
|
||||||
{once: true}
|
|
||||||
);
|
|
||||||
uploader.click();
|
uploader.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -92,11 +80,13 @@ function editNamesbase() {
|
||||||
|
|
||||||
function updateNamesData() {
|
function updateNamesData() {
|
||||||
const base = +document.getElementById("namesbaseSelect").value;
|
const base = +document.getElementById("namesbaseSelect").value;
|
||||||
const rawInput = document.getElementById("namesbaseTextarea").value;
|
const input = document.getElementById("namesbaseTextarea");
|
||||||
if (rawInput.split(",").length < 3) return tip("The names data provided is too short of incorrect", false, "error");
|
if (input.value.split(",").length < 3)
|
||||||
|
return tip("The names data provided is too short of incorrect", false, "error");
|
||||||
|
|
||||||
const namesData = rawInput.replace(/[/|]/g, "");
|
const securedNamesData = input.value.replace(/[/|]/g, "");
|
||||||
nameBases[base].b = namesData;
|
nameBases[base].b = securedNamesData;
|
||||||
|
input.value = securedNamesData;
|
||||||
Names.updateChain(base);
|
Names.updateChain(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,19 +103,13 @@ function editNamesbase() {
|
||||||
|
|
||||||
function updateBaseMin() {
|
function updateBaseMin() {
|
||||||
const base = +document.getElementById("namesbaseSelect").value;
|
const base = +document.getElementById("namesbaseSelect").value;
|
||||||
if (+this.value > nameBases[base].max) {
|
if (+this.value > nameBases[base].max) return tip("Minimal length cannot be greater than maximal", false, "error");
|
||||||
tip("Minimal length cannot be greater than maximal", false, "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nameBases[base].min = +this.value;
|
nameBases[base].min = +this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBaseMax() {
|
function updateBaseMax() {
|
||||||
const base = +document.getElementById("namesbaseSelect").value;
|
const base = +document.getElementById("namesbaseSelect").value;
|
||||||
if (+this.value < nameBases[base].min) {
|
if (+this.value < nameBases[base].min) return tip("Maximal length should be greater than minimal", false, "error");
|
||||||
tip("Maximal length should be greater than minimal", false, "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nameBases[base].max = +this.value;
|
nameBases[base].max = +this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,16 +240,15 @@ function editNamesbase() {
|
||||||
|
|
||||||
function namesbaseUpload(dataLoaded, override = true) {
|
function namesbaseUpload(dataLoaded, override = true) {
|
||||||
const data = dataLoaded.split("\r\n");
|
const data = dataLoaded.split("\r\n");
|
||||||
if (!data || !data[0]) {
|
if (!data || !data[0]) return tip("Cannot load a namesbase. Please check the data format", false, "error");
|
||||||
tip("Cannot load a namesbase. Please check the data format", false, "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Names.clearChains();
|
Names.clearChains();
|
||||||
if (override) nameBases = [];
|
if (override) nameBases = [];
|
||||||
data.forEach(d => {
|
|
||||||
const e = d.split("|");
|
data.forEach(base => {
|
||||||
nameBases.push({name: e[0], min: e[1], max: e[2], d: e[3], m: e[4], b: e[5]});
|
const [name, min, max, d, m, names] = base.split("|");
|
||||||
|
const secureNames = names.replace(/[/|]/g, "");
|
||||||
|
nameBases.push({name, min, max, d, m, b: secureNames});
|
||||||
});
|
});
|
||||||
|
|
||||||
createBasesList();
|
createBasesList();
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ document
|
||||||
|
|
||||||
// show popup with a list of Patreon supportes (updated manually)
|
// show popup with a list of Patreon supportes (updated manually)
|
||||||
async function showSupporters() {
|
async function showSupporters() {
|
||||||
const {supporters} = await import("../dynamic/supporters.js?v=19062022");
|
const {supporters} = await import("../dynamic/supporters.js?v=1.89.15");
|
||||||
const list = supporters.split("\n").sort();
|
const list = supporters.split("\n").sort();
|
||||||
const columns = window.innerWidth < 800 ? 2 : 5;
|
const columns = window.innerWidth < 800 ? 2 : 5;
|
||||||
|
|
||||||
|
|
@ -157,6 +157,8 @@ optionsContent.addEventListener("click", function (event) {
|
||||||
else if (id === "translateExtent") toggleTranslateExtent(event.target);
|
else if (id === "translateExtent") toggleTranslateExtent(event.target);
|
||||||
else if (id === "speakerTest") testSpeaker();
|
else if (id === "speakerTest") testSpeaker();
|
||||||
else if (id === "themeColorRestore") restoreDefaultThemeColor();
|
else if (id === "themeColorRestore") restoreDefaultThemeColor();
|
||||||
|
else if (id === "loadGoogleTranslateButton") loadGoogleTranslate();
|
||||||
|
else if (id === "resetLanguage") resetLanguage();
|
||||||
});
|
});
|
||||||
|
|
||||||
function mapSizeInputChange() {
|
function mapSizeInputChange() {
|
||||||
|
|
@ -474,6 +476,44 @@ function changeDialogsTheme(themeColor, transparency) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadGoogleTranslate() {
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "https://translate.google.com/translate_a/element.js?cb=initGoogleTranslate";
|
||||||
|
script.onload = () => {
|
||||||
|
document.getElementById("loadGoogleTranslateButton")?.remove();
|
||||||
|
|
||||||
|
// replace mapLayers underline <u> with bare text to avoid translation issue
|
||||||
|
document
|
||||||
|
.getElementById("mapLayers")
|
||||||
|
.querySelectorAll("li")
|
||||||
|
.forEach(el => {
|
||||||
|
const text = el.innerHTML.replace(/<u>(.+)<\/u>/g, "$1");
|
||||||
|
el.innerHTML = text;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initGoogleTranslate() {
|
||||||
|
new google.translate.TranslateElement(
|
||||||
|
{pageLanguage: "en", layout: google.translate.TranslateElement.InlineLayout.VERTICAL},
|
||||||
|
"google_translate_element"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetLanguage() {
|
||||||
|
const languageSelect = document.querySelector("#google_translate_element select");
|
||||||
|
if (!languageSelect.value) return;
|
||||||
|
|
||||||
|
languageSelect.value = "en";
|
||||||
|
languageSelect.dispatchEvent(new Event("change"));
|
||||||
|
|
||||||
|
// do once again to actually reset the language
|
||||||
|
languageSelect.value = "en";
|
||||||
|
languageSelect.dispatchEvent(new Event("change"));
|
||||||
|
}
|
||||||
|
|
||||||
function changeZoomExtent(value) {
|
function changeZoomExtent(value) {
|
||||||
if (+zoomExtentMin.value > +zoomExtentMax.value) {
|
if (+zoomExtentMin.value > +zoomExtentMax.value) {
|
||||||
[zoomExtentMin.value, zoomExtentMax.value] = [zoomExtentMax.value, zoomExtentMin.value];
|
[zoomExtentMin.value, zoomExtentMax.value] = [zoomExtentMax.value, zoomExtentMin.value];
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,9 @@ function overviewRegiments(state) {
|
||||||
const insert = html => document.getElementById("regimentsTotal").insertAdjacentHTML("beforebegin", html);
|
const insert = html => document.getElementById("regimentsTotal").insertAdjacentHTML("beforebegin", html);
|
||||||
for (const u of options.military) {
|
for (const u of options.military) {
|
||||||
const label = capitalize(u.name.replace(/_/g, " "));
|
const label = capitalize(u.name.replace(/_/g, " "));
|
||||||
insert(`<div data-tip="Regiment ${u.name} units number. Click to sort" class="sortable removable" data-sortby="${u.name}">${label} </div>`);
|
insert(
|
||||||
|
`<div data-tip="Regiment ${u.name} units number. Click to sort" class="sortable removable" data-sortby="${u.name}">${label} </div>`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
header.querySelectorAll(".removable").forEach(function (e) {
|
header.querySelectorAll(".removable").forEach(function (e) {
|
||||||
e.addEventListener("click", function () {
|
e.addEventListener("click", function () {
|
||||||
|
|
@ -60,10 +62,12 @@ function overviewRegiments(state) {
|
||||||
for (const r of s.military) {
|
for (const r of s.military) {
|
||||||
const sortData = options.military.map(u => `data-${u.name}=${r.u[u.name] || 0}`).join(" ");
|
const sortData = options.military.map(u => `data-${u.name}=${r.u[u.name] || 0}`).join(" ");
|
||||||
const lineData = options.military
|
const lineData = options.military
|
||||||
.map(u => `<div data-type="${u.name}" data-tip="${capitalize(u.name)} units number">${r.u[u.name] || 0}</div>`)
|
.map(
|
||||||
|
u => `<div data-type="${u.name}" data-tip="${capitalize(u.name)} units number">${r.u[u.name] || 0}</div>`
|
||||||
|
)
|
||||||
.join(" ");
|
.join(" ");
|
||||||
|
|
||||||
lines += /* html */ `<div class="states" data-id=${r.i} data-s="${s.i}" data-state="${s.name}" data-name="${r.name}" ${sortData} data-total="${r.a}">
|
lines += /* html */ `<div class="states" data-id="${r.i}" data-s="${s.i}" data-state="${s.name}" data-name="${r.name}" ${sortData} data-total="${r.a}">
|
||||||
<fill-box data-tip="${s.fullName}" fill="${s.color}" disabled></fill-box>
|
<fill-box data-tip="${s.fullName}" fill="${s.color}" disabled></fill-box>
|
||||||
<input data-tip="${s.fullName}" style="width:6em" value="${s.name}" readonly />
|
<input data-tip="${s.fullName}" style="width:6em" value="${s.name}" readonly />
|
||||||
<span data-tip="Regiment's emblem" style="width:1em">${r.icon}</span>
|
<span data-tip="Regiment's emblem" style="width:1em">${r.icon}</span>
|
||||||
|
|
@ -79,7 +83,9 @@ function overviewRegiments(state) {
|
||||||
|
|
||||||
lines += /* html */ `<div id="regimentsTotalLine" class="totalLine" data-tip="Total of all displayed regiments">
|
lines += /* html */ `<div id="regimentsTotalLine" class="totalLine" data-tip="Total of all displayed regiments">
|
||||||
<div style="width: 21em; margin-left: 1em">Regiments: ${regiments.length}</div>
|
<div style="width: 21em; margin-left: 1em">Regiments: ${regiments.length}</div>
|
||||||
${options.military.map(u => `<div style="width:5em">${si(d3.sum(regiments.map(r => r.u[u.name] || 0)))}</div>`).join(" ")}
|
${options.military
|
||||||
|
.map(u => `<div style="width:5em">${si(d3.sum(regiments.map(r => r.u[u.name] || 0)))}</div>`)
|
||||||
|
.join(" ")}
|
||||||
<div style="width:5em">${si(d3.sum(regiments.map(r => r.a)))}</div>
|
<div style="width:5em">${si(d3.sum(regiments.map(r => r.a)))}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
|
@ -92,7 +98,9 @@ function overviewRegiments(state) {
|
||||||
|
|
||||||
// add listeners
|
// add listeners
|
||||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseenter", ev => regimentHighlightOn(ev)));
|
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseenter", ev => regimentHighlightOn(ev)));
|
||||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseleave", ev => regimentHighlightOff(ev)));
|
body
|
||||||
|
.querySelectorAll("div.states")
|
||||||
|
.forEach(el => el.addEventListener("mouseleave", ev => regimentHighlightOff(ev)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFilter(state) {
|
function updateFilter(state) {
|
||||||
|
|
@ -158,10 +166,7 @@ function overviewRegiments(state) {
|
||||||
|
|
||||||
function addRegimentOnClick() {
|
function addRegimentOnClick() {
|
||||||
const state = +regimentsFilter.value;
|
const state = +regimentsFilter.value;
|
||||||
if (state === -1) {
|
if (state === -1) return tip("Please select state from the list", false, "error");
|
||||||
tip("Please select state from the list", false, "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const point = d3.mouse(this);
|
const point = d3.mouse(this);
|
||||||
const cell = findCell(point[0], point[1]);
|
const cell = findCell(point[0], point[1]);
|
||||||
|
|
@ -180,15 +185,32 @@ function overviewRegiments(state) {
|
||||||
|
|
||||||
function downloadRegimentsData() {
|
function downloadRegimentsData() {
|
||||||
const units = options.military.map(u => u.name);
|
const units = options.military.map(u => u.name);
|
||||||
let data = "State,Id,Name," + units.map(u => capitalize(u)).join(",") + ",Total\n"; // headers
|
let data =
|
||||||
|
"State,Id,Icon,Name," +
|
||||||
|
units.map(u => capitalize(u)).join(",") +
|
||||||
|
",X,Y,Latitude,Longitude,Base X,Base Y,Base Latitude,Base Longitude\n"; // headers
|
||||||
|
|
||||||
body.querySelectorAll(":scope > div:not(.totalLine)").forEach(function (el) {
|
for (const s of pack.states) {
|
||||||
data += el.dataset.state + ",";
|
if (!s.i || s.removed || !s.military.length) continue;
|
||||||
data += el.dataset.id + ",";
|
|
||||||
data += el.dataset.name + ",";
|
for (const r of s.military) {
|
||||||
data += units.map(u => el.dataset[u]).join(",") + ",";
|
data += s.name + ",";
|
||||||
data += el.dataset.total + "\n";
|
data += r.i + ",";
|
||||||
});
|
data += r.icon + ",";
|
||||||
|
data += r.name + ",";
|
||||||
|
data += units.map(unit => r.u[unit]).join(",") + ",";
|
||||||
|
|
||||||
|
data += r.x + ",";
|
||||||
|
data += r.y + ",";
|
||||||
|
data += getLatitude(r.y, 2) + ",";
|
||||||
|
data += getLongitude(r.x, 2) + ",";
|
||||||
|
|
||||||
|
data += r.bx + ",";
|
||||||
|
data += r.by + ",";
|
||||||
|
data += getLatitude(r.by, 2) + ",";
|
||||||
|
data += getLongitude(r.bx, 2) + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const name = getFileName("Regiments") + ".csv";
|
const name = getFileName("Regiments") + ".csv";
|
||||||
downloadFile(data, name);
|
downloadFile(data, name);
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,10 @@ function recalculatePopulation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function regenerateStates() {
|
function regenerateStates() {
|
||||||
recreateStates();
|
const newStates = recreateStates();
|
||||||
|
if (!newStates) return;
|
||||||
|
|
||||||
|
pack.states = newStates;
|
||||||
BurgsAndStates.expandStates();
|
BurgsAndStates.expandStates();
|
||||||
BurgsAndStates.normalizeStates();
|
BurgsAndStates.normalizeStates();
|
||||||
BurgsAndStates.collectStatistics();
|
BurgsAndStates.collectStatistics();
|
||||||
|
|
@ -165,21 +168,32 @@ function recreateStates() {
|
||||||
Math.random = aleaPRNG(localSeed);
|
Math.random = aleaPRNG(localSeed);
|
||||||
|
|
||||||
const statesCount = +regionsOutput.value;
|
const statesCount = +regionsOutput.value;
|
||||||
|
if (!statesCount) {
|
||||||
|
tip(`<i>States Number</i> option value is zero. No counties are generated`, false, "error");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const validBurgs = pack.burgs.filter(b => b.i && !b.removed);
|
const validBurgs = pack.burgs.filter(b => b.i && !b.removed);
|
||||||
|
if (!validBurgs.length) {
|
||||||
|
tip("There are no any burgs to generate states. Please create burgs first", false, "error");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!validBurgs.length)
|
if (validBurgs.length < statesCount) {
|
||||||
return tip("There are no any burgs to generate states. Please create burgs first", false, "error");
|
const message = `Not enough burgs to generate ${statesCount} states. Will generate only ${validBurgs.length} states`;
|
||||||
if (validBurgs.length < statesCount)
|
tip(message, false, "warn");
|
||||||
tip(
|
}
|
||||||
`Not enough burgs to generate ${statesCount} states. Will generate only ${validBurgs.length} states`,
|
|
||||||
false,
|
|
||||||
"warn"
|
|
||||||
);
|
|
||||||
|
|
||||||
const lockedStates = pack.states.filter(s => s.i && !s.removed && s.lock);
|
const validStates = pack.states.filter(s => s.i && !s.removed);
|
||||||
|
const lockedStates = validStates.filter(s => s.lock);
|
||||||
const lockedStatesIds = lockedStates.map(s => s.i);
|
const lockedStatesIds = lockedStates.map(s => s.i);
|
||||||
const lockedStatesCapitals = lockedStates.map(s => s.capital);
|
const lockedStatesCapitals = lockedStates.map(s => s.capital);
|
||||||
|
|
||||||
|
if (lockedStates.length === validStates.length) {
|
||||||
|
tip("Unable to regenerate as all states are locked", false, "error");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// turn all old capitals into towns, except for the capitals of locked states
|
// turn all old capitals into towns, except for the capitals of locked states
|
||||||
for (const burg of validBurgs) {
|
for (const burg of validBurgs) {
|
||||||
if (!burg.capital) continue;
|
if (!burg.capital) continue;
|
||||||
|
|
@ -229,7 +243,7 @@ function recreateStates() {
|
||||||
// restore locked states
|
// restore locked states
|
||||||
lockedStates.forEach(state => {
|
lockedStates.forEach(state => {
|
||||||
const newId = newStates.length;
|
const newId = newStates.length;
|
||||||
const {x, y} = validBurgs[state.capital];
|
const {x, y} = pack.burgs[state.capital];
|
||||||
capitalsTree.add([x, y]);
|
capitalsTree.add([x, y]);
|
||||||
|
|
||||||
// update label id reference
|
// update label id reference
|
||||||
|
|
@ -300,9 +314,7 @@ function recreateStates() {
|
||||||
newStates.push({i, name, type, capital: capital.i, center: capital.cell, culture, expansionism, coa});
|
newStates.push({i, name, type, capital: capital.i, center: capital.cell, culture, expansionism, coa});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statesCount) tip(`<i>States Number</i> option is set to zero. No counties are generated`, false, "warn");
|
return newStates;
|
||||||
|
|
||||||
pack.states = newStates;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function regenerateProvinces() {
|
function regenerateProvinces() {
|
||||||
|
|
@ -920,6 +932,6 @@ function viewCellDetails() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function overviewCharts() {
|
async function overviewCharts() {
|
||||||
const Overview = await import("../dynamic/overview/charts-overview.js?v=1.87.03");
|
const Overview = await import("../dynamic/overview/charts-overview.js?v=1.89.24");
|
||||||
Overview.open();
|
Overview.open();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,11 @@ function isCtrlClick(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateDate(from = 100, to = 1000) {
|
function generateDate(from = 100, to = 1000) {
|
||||||
return new Date(rand(from, to), rand(12), rand(31)).toLocaleDateString("en", {year: "numeric", month: "long", day: "numeric"});
|
return new Date(rand(from, to), rand(12), rand(31)).toLocaleDateString("en", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "long",
|
||||||
|
day: "numeric"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLongitude(x, decimals = 2) {
|
function getLongitude(x, decimals = 2) {
|
||||||
|
|
@ -158,7 +162,8 @@ void (function () {
|
||||||
const defaultOptions = {default: 1, step: 0.01, min: 0, max: 100, required: true};
|
const defaultOptions = {default: 1, step: 0.01, min: 0, max: 100, required: true};
|
||||||
|
|
||||||
window.prompt = function (promptText = defaultText, options = defaultOptions, callback) {
|
window.prompt = function (promptText = defaultText, options = defaultOptions, callback) {
|
||||||
if (options.default === undefined) return ERROR && console.error("Prompt: options object does not have default value defined");
|
if (options.default === undefined)
|
||||||
|
return ERROR && console.error("Prompt: options object does not have default value defined");
|
||||||
|
|
||||||
const input = prompt.querySelector("#promptInput");
|
const input = prompt.querySelector("#promptInput");
|
||||||
prompt.querySelector("#promptText").innerHTML = promptText;
|
prompt.querySelector("#promptText").innerHTML = promptText;
|
||||||
|
|
@ -192,41 +197,3 @@ void (function () {
|
||||||
prompt.style.display = "none";
|
prompt.style.display = "none";
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// indexedDB; ldb object
|
|
||||||
void (function () {
|
|
||||||
function e(t, o) {
|
|
||||||
return n
|
|
||||||
? void (n.transaction("s").objectStore("s").get(t).onsuccess = function (e) {
|
|
||||||
var t = (e.target.result && e.target.result.v) || null;
|
|
||||||
o(t);
|
|
||||||
})
|
|
||||||
: void setTimeout(function () {
|
|
||||||
e(t, o);
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
var t = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
|
|
||||||
if (!t) return void ERROR && console.error("indexedDB not supported");
|
|
||||||
var n,
|
|
||||||
o = {k: "", v: ""},
|
|
||||||
r = t.open("d2", 1);
|
|
||||||
(r.onsuccess = function (e) {
|
|
||||||
n = this.result;
|
|
||||||
}),
|
|
||||||
(r.onerror = function (e) {
|
|
||||||
ERROR && console.error("indexedDB request error"), INFO && console.log(e);
|
|
||||||
}),
|
|
||||||
(r.onupgradeneeded = function (e) {
|
|
||||||
n = null;
|
|
||||||
var t = e.target.result.createObjectStore("s", {keyPath: "k"});
|
|
||||||
t.transaction.oncomplete = function (e) {
|
|
||||||
n = e.target.db;
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
(window.ldb = {
|
|
||||||
get: e,
|
|
||||||
set: function (e, t) {
|
|
||||||
(o.k = e), (o.v = t), n.transaction("s", "readwrite").objectStore("s").put(o);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// version and caching control
|
// version and caching control
|
||||||
const version = "1.89.15"; // generator version, update each time
|
const version = "1.89.33"; // generator version, update each time
|
||||||
|
|
||||||
{
|
{
|
||||||
document.title += " v" + version;
|
document.title += " v" + version;
|
||||||
const loadingScreenVersion = document.getElementById("version");
|
const loadingScreenVersion = document.getElementById("versionText");
|
||||||
if (loadingScreenVersion) loadingScreenVersion.innerHTML = version;
|
if (loadingScreenVersion) loadingScreenVersion.innerText = `v${version}`;
|
||||||
|
|
||||||
const versionNumber = parseFloat(version);
|
const versionNumber = parseFloat(version);
|
||||||
const storedVersion = localStorage.getItem("version") ? parseFloat(localStorage.getItem("version")) : 0;
|
const storedVersion = localStorage.getItem("version") ? parseFloat(localStorage.getItem("version")) : 0;
|
||||||
|
|
@ -28,15 +28,14 @@ const version = "1.89.15"; // generator version, update each time
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<strong>Latest changes:</strong>
|
<strong>Latest changes:</strong>
|
||||||
|
<li>Autosave feature (in Options)</li>
|
||||||
|
<li>Google translation support (in Options)</li>
|
||||||
<li>Religions can be edited and redrawn like cultures</li>
|
<li>Religions can be edited and redrawn like cultures</li>
|
||||||
<li>Lock states, provinces, cultures, and religions from regeneration</li>
|
<li>Lock states, provinces, cultures, and religions from regeneration</li>
|
||||||
<li>Heightmap brushes: linear edit option</li>
|
<li>Heightmap brushes: linear edit option</li>
|
||||||
<li>Data Charts screen</li>
|
<li>Data Charts screen</li>
|
||||||
<li>Сultures and religions can have multiple parents in hierarchy tree</li>
|
<li>Сultures and religions can have multiple parents in hierarchy tree</li>
|
||||||
<li>Heightmap selection screen</li>
|
<li>Heightmap selection screen</li>
|
||||||
<li>Dialogs optimization for mobile</li>
|
|
||||||
<li>New heightmap template: Fractious</li>
|
|
||||||
<li>Template Editor: mask and invert tools</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Join our <a href="${discord}" target="_blank">Discord server</a> and <a href="${reddit}" target="_blank">Reddit community</a> to ask questions, share maps, discuss the Generator and Worlbuilding, report bugs and propose new features.</p>
|
<p>Join our <a href="${discord}" target="_blank">Discord server</a> and <a href="${reddit}" target="_blank">Reddit community</a> to ask questions, share maps, discuss the Generator and Worlbuilding, report bugs and propose new features.</p>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue