mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
diplomacy - change relations screen
This commit is contained in:
parent
05217d176d
commit
865afdc2aa
5 changed files with 259 additions and 162 deletions
68
index.css
68
index.css
|
|
@ -29,6 +29,11 @@ input:read-only {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type="radio"] {
|
||||||
|
vertical-align: bottom;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
text-indent: 1px;
|
text-indent: 1px;
|
||||||
|
|
@ -834,75 +839,79 @@ fieldset {
|
||||||
}
|
}
|
||||||
|
|
||||||
.matrix-table {
|
.matrix-table {
|
||||||
width: 100%;
|
max-height: 80vh;
|
||||||
font-size: smaller;
|
max-width: 85vw;
|
||||||
text-align: center;
|
scrollbar-width: thin;
|
||||||
border-collapse: collapse;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table th,
|
.matrix-table > table {
|
||||||
table.matrix-table td {
|
text-align: center;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-table > table th,
|
||||||
|
.matrix-table > table td {
|
||||||
border: 1px solid var(--dark-solid);
|
border: 1px solid var(--dark-solid);
|
||||||
height: 2em;
|
height: 2em;
|
||||||
padding: 0.2em;
|
padding: 0.2em;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table th {
|
.matrix-table > table th {
|
||||||
background-color: #302a2a;
|
background-color: #302a2a;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table tr:hover th {
|
.matrix-table > table td:hover {
|
||||||
background: #3e3636;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.matrix-table td:hover {
|
|
||||||
outline: 2px solid var(--dark-solid);
|
outline: 2px solid var(--dark-solid);
|
||||||
outline-offset: -1px;
|
outline-offset: -1px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Ally {
|
.matrix-table > table td.Ally {
|
||||||
background-color: #73ec73;
|
background-color: #73ec73;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Friendly {
|
.matrix-table > table td.Friendly {
|
||||||
background-color: #d4f8aa;
|
background-color: #d4f8aa;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Neutral {
|
.matrix-table > table td.Neutral {
|
||||||
background-color: #d8d9d3;
|
background-color: #d8d9d3;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Suspicion {
|
.matrix-table > table td.Suspicion {
|
||||||
background-color: #eeafaa;
|
background-color: #eeafaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Enemy {
|
.matrix-table > table td.Enemy {
|
||||||
background-color: #ffa39c;
|
background-color: #ffa39c;
|
||||||
color: #af0d23;
|
color: #af0d23;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Unknown {
|
.matrix-table > table td.Unknown {
|
||||||
background-color: #c1bfbf;
|
background-color: #c1bfbf;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Rival {
|
.matrix-table > table td.Rival {
|
||||||
background-color: #bd845c;
|
background-color: #bd845c;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Vassal {
|
.matrix-table > table td.Vassal {
|
||||||
background-color: #87cefa;
|
background-color: #87cefa;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.Suzerain {
|
.matrix-table > table td.Suzerain {
|
||||||
background-color: #8f8fe1;
|
background-color: #8f8fe1;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.matrix-table td.x {
|
.matrix-table > table td.x {
|
||||||
background-color: #d4ca94;
|
background-color: #d4ca94;
|
||||||
|
cursor: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sizeOutput {
|
#sizeOutput {
|
||||||
|
|
@ -1310,19 +1319,23 @@ div.slider .ui-slider-handle {
|
||||||
}
|
}
|
||||||
|
|
||||||
#alertMessage::-webkit-scrollbar,
|
#alertMessage::-webkit-scrollbar,
|
||||||
.table::-webkit-scrollbar {
|
.table::-webkit-scrollbar,
|
||||||
|
.matrix-table::-webkit-scrollbar {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#alertMessage::-webkit-scrollbar-thumb,
|
#alertMessage::-webkit-scrollbar-thumb,
|
||||||
.table::-webkit-scrollbar-thumb {
|
.table::-webkit-scrollbar-thumb,
|
||||||
|
.matrix-table::-webkit-scrollbar-thumb {
|
||||||
background-color: #aaa;
|
background-color: #aaa;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#alertMessage::-webkit-scrollbar-thumb:hover,
|
#alertMessage::-webkit-scrollbar-thumb:hover,
|
||||||
.table::-webkit-scrollbar-thumb:hover {
|
.table::-webkit-scrollbar-thumb:hover,
|
||||||
|
.matrix-table::-webkit-scrollbar-thumb:hover {
|
||||||
background: #666;
|
background: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1504,15 +1517,14 @@ div.states > .riverType {
|
||||||
width: 5em;
|
width: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.states > .coaIcon {
|
.coaIcon {
|
||||||
stroke-width: 3;
|
stroke-width: 3;
|
||||||
width: 1.4em;
|
width: 1.4em;
|
||||||
height: 1.4em;
|
height: 1.4em;
|
||||||
margin: -0.3em 0;
|
margin: -0.3em 0;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.states > .coaIcon > use {
|
.coaIcon > use {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
23
index.html
23
index.html
|
|
@ -2735,33 +2735,25 @@
|
||||||
<div id="diplomacyEditor" class="dialog stable" style="display: none">
|
<div id="diplomacyEditor" class="dialog stable" style="display: none">
|
||||||
<div id="diplomacyHeader" class="header">
|
<div id="diplomacyHeader" class="header">
|
||||||
<div style="left:.2em" data-tip="Click to sort by state name" class="sortable alphabetically" data-sortby="name">State </div>
|
<div style="left:.2em" data-tip="Click to sort by state name" class="sortable alphabetically" data-sortby="name">State </div>
|
||||||
<div style="left:13.4em" data-tip="Click to sort by diplomatical relations" class="sortable alphabetically" data-sortby="relations">Relations </div>
|
<div style="left:14.4em" data-tip="Click to sort by diplomatical relations" class="sortable alphabetically" data-sortby="relations">Relations </div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="diplomacyBodySection" class="table"></div>
|
<div id="diplomacyBodySection" class="table"></div>
|
||||||
|
|
||||||
<div id="diplomacySelect">
|
|
||||||
<div data-tip="Ally means states formed a defensive pact and will protect each other in case of third party aggression">Ally</div>
|
|
||||||
<div data-tip="State is friendly to anouther state when they share some common interests">Friendly</div>
|
|
||||||
<div data-tip="Neutral means states relations are neither positive nor negative">Neutral</div>
|
|
||||||
<div data-tip="Suspicion means state has a cautious distrust of another state">Suspicion</div>
|
|
||||||
<div data-tip="Enemies are states at war with each other">Enemy</div>
|
|
||||||
<div data-tip="Relations are unknown if states do not have enough information about each other">Unknown</div>
|
|
||||||
<div data-tip="Rivalry is a state of competing for dominance in the region">Rival</div>
|
|
||||||
<div data-tip="Vassal is a state having obligation to its suzerain">Vassal</div>
|
|
||||||
<div data-tip="Suzerain is a state having some control over its vassals">Suzerain</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="diplomacyBottom" style="margin-top: .1em">
|
<div id="diplomacyBottom" style="margin-top: .1em">
|
||||||
<button id="diplomacyEditorRefresh" data-tip="Refresh the Editor" class="icon-cw"></button>
|
<button id="diplomacyEditorRefresh" data-tip="Refresh the Editor" class="icon-cw"></button>
|
||||||
<button id="diplomacyEditStyle" data-tip="Edit states (including diplomacy view) style in Style Editor" class="icon-adjust"></button>
|
<button id="diplomacyEditStyle" data-tip="Edit states (including diplomacy view) style in Style Editor" class="icon-adjust"></button>
|
||||||
<button id="diplomacyRegenerate" data-tip="Regenerate diplomatical relations" class="icon-retweet"></button>
|
<button id="diplomacyRegenerate" data-tip="Regenerate diplomatical relations" class="icon-retweet"></button>
|
||||||
<button id="diplomacyHistory" data-tip="Show relations history" class="icon-hourglass-1"></button>
|
<button id="diplomacyHistory" data-tip="Show relations history" class="icon-hourglass-1"></button>
|
||||||
<button id="diplomacyMatrix" data-tip="Show relations matrix" class="icon-list-bullet"></button>
|
<button id="diplomacyShowMatrix" data-tip="Show relations matrix" class="icon-list-bullet"></button>
|
||||||
<button id="diplomacyExport" data-tip="Save state relations matrix as a text file (.csv)" class="icon-download"></button>
|
<button id="diplomacyExport" data-tip="Save state relations matrix as a text file (.csv)" class="icon-download"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="diplomacyMatrix" class="dialog" style="display: none">
|
||||||
|
<div id="diplomacyMatrixBody" class="matrix-table"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="provinceNameEditor" class="dialog" data-province="0" style="display: none">
|
<div id="provinceNameEditor" class="dialog" data-province="0" style="display: none">
|
||||||
<div>
|
<div>
|
||||||
<div data-tip="Province short name" class="label">Short name:</div>
|
<div data-tip="Province short name" class="label">Short name:</div>
|
||||||
|
|
@ -3636,8 +3628,7 @@
|
||||||
<div data-tip="Image scale relative to image size (e.g. 5x)" style="margin-bottom: .3em">
|
<div data-tip="Image scale relative to image size (e.g. 5x)" style="margin-bottom: .3em">
|
||||||
<div class="label">Scale:</div>
|
<div class="label">Scale:</div>
|
||||||
<input id="tileScaleInput" data-stored="tileScale" type="range" min=1 max=4 value=1 style="width: 10em">
|
<input id="tileScaleInput" data-stored="tileScale" type="range" min=1 max=4 value=1 style="width: 10em">
|
||||||
<input id="tileScaleOutput" data-stored="tileScale" type="number" min=1 value=1
|
<input id="tileScaleOutput" data-stored="tileScale" type="number" min=1 value=1 >
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div data-tip="Calculated size of image if combined" style="margin-bottom: .3em">
|
<div data-tip="Calculated size of image if combined" style="margin-bottom: .3em">
|
||||||
<div class="label">Total size:</div>
|
<div class="label">Total size:</div>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
function editDiplomacy() {
|
function editDiplomacy() {
|
||||||
if (customization) return;
|
if (customization) return;
|
||||||
if (pack.states.filter(s => s.i && !s.removed).length < 2) {
|
if (pack.states.filter(s => s.i && !s.removed).length < 2) return tip("There should be at least 2 states to edit the diplomacy", false, "error");
|
||||||
tip("There should be at least 2 states to edit the diplomacy", false, "error");
|
|
||||||
return;
|
const body = document.getElementById("diplomacyBodySection");
|
||||||
}
|
|
||||||
|
|
||||||
closeDialogs("#diplomacyEditor, .stable");
|
closeDialogs("#diplomacyEditor, .stable");
|
||||||
if (!layerIsOn("toggleStates")) toggleStates();
|
if (!layerIsOn("toggleStates")) toggleStates();
|
||||||
|
|
@ -14,11 +13,22 @@ function editDiplomacy() {
|
||||||
if (layerIsOn("toggleBiomes")) toggleBiomes();
|
if (layerIsOn("toggleBiomes")) toggleBiomes();
|
||||||
if (layerIsOn("toggleReligions")) toggleReligions();
|
if (layerIsOn("toggleReligions")) toggleReligions();
|
||||||
|
|
||||||
const body = document.getElementById("diplomacyBodySection");
|
const relations = {
|
||||||
const statuses = ["Ally", "Friendly", "Neutral", "Suspicion", "Enemy", "Unknown", "Rival", "Vassal", "Suzerain"];
|
Ally: {
|
||||||
const description = [" is an ally of ", " is friendly to ", " is neutral to ", " is suspicious of ",
|
inText: "is an ally of",
|
||||||
" is at war with ", " does not know about ", " is a rival of ", " is a vassal of ", " is suzerain to "];
|
color: "#00b300",
|
||||||
const colors = ["#00b300", "#d4f8aa", "#edeee8", "#eeafaa", "#e64b40", "#a9a9a9", "#ad5a1f", "#87CEFA", "#00008B"];
|
tip: "Ally means states formed a defensive pact and will protect each other in case of third party aggression"
|
||||||
|
},
|
||||||
|
Friendly: {inText: "is friendly to", color: "#d4f8aa", tip: "State is friendly to anouther state when they share some common interests"},
|
||||||
|
Neutral: {inText: "is neutral to", color: "#edeee8", tip: "Neutral means states relations are neither positive nor negative"},
|
||||||
|
Suspicion: {inText: "is suspicious of", color: "#eeafaa", tip: "Suspicion means state has a cautious distrust of another state"},
|
||||||
|
Enemy: {inText: "is at war with", color: "#e64b40", tip: "Enemies are states at war with each other"},
|
||||||
|
Unknown: {inText: "does not know about", color: "#a9a9a9", tip: "Relations are unknown if states do not have enough information about each other"},
|
||||||
|
Rival: {inText: "is a rival of", color: "#ad5a1f", tip: "Rivalry is a state of competing for dominance in the region"},
|
||||||
|
Vassal: {inText: "is a vassal of", color: "#87CEFA", tip: "Vassal is a state having obligation to its suzerain"},
|
||||||
|
Suzerain: {inText: "is suzerain to", color: "#00008B", tip: "Suzerain is a state having some control over its vassals"}
|
||||||
|
};
|
||||||
|
|
||||||
refreshDiplomacyEditor();
|
refreshDiplomacyEditor();
|
||||||
|
|
||||||
tip("Click on a state to see its diplomatic relations", false, "warning");
|
tip("Click on a state to see its diplomatic relations", false, "warning");
|
||||||
|
|
@ -28,7 +38,10 @@ function editDiplomacy() {
|
||||||
modules.editDiplomacy = true;
|
modules.editDiplomacy = true;
|
||||||
|
|
||||||
$("#diplomacyEditor").dialog({
|
$("#diplomacyEditor").dialog({
|
||||||
title: "Diplomacy Editor", resizable: false, width: fitContent(), close: closeDiplomacyEditor,
|
title: "Diplomacy Editor",
|
||||||
|
resizable: false,
|
||||||
|
width: fitContent(),
|
||||||
|
close: closeDiplomacyEditor,
|
||||||
position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}
|
position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -36,10 +49,29 @@ function editDiplomacy() {
|
||||||
document.getElementById("diplomacyEditorRefresh").addEventListener("click", refreshDiplomacyEditor);
|
document.getElementById("diplomacyEditorRefresh").addEventListener("click", refreshDiplomacyEditor);
|
||||||
document.getElementById("diplomacyEditStyle").addEventListener("click", () => editStyle("regions"));
|
document.getElementById("diplomacyEditStyle").addEventListener("click", () => editStyle("regions"));
|
||||||
document.getElementById("diplomacyRegenerate").addEventListener("click", regenerateRelations);
|
document.getElementById("diplomacyRegenerate").addEventListener("click", regenerateRelations);
|
||||||
document.getElementById("diplomacyMatrix").addEventListener("click", showRelationsMatrix);
|
document.getElementById("diplomacyShowMatrix").addEventListener("click", showRelationsMatrix);
|
||||||
document.getElementById("diplomacyHistory").addEventListener("click", showRelationsHistory);
|
document.getElementById("diplomacyHistory").addEventListener("click", showRelationsHistory);
|
||||||
document.getElementById("diplomacyExport").addEventListener("click", downloadDiplomacyData);
|
document.getElementById("diplomacyExport").addEventListener("click", downloadDiplomacyData);
|
||||||
document.getElementById("diplomacySelect").addEventListener("mouseup", diplomacyChangeRelations);
|
|
||||||
|
body.addEventListener("click", function (ev) {
|
||||||
|
const el = ev.target;
|
||||||
|
if (el.parentElement.classList.contains("Self")) return;
|
||||||
|
|
||||||
|
if (el.classList.contains("changeRelations")) {
|
||||||
|
const line = el.parentElement;
|
||||||
|
const subjectId = +line.dataset.id;
|
||||||
|
const objectId = +body.querySelector("div.Self").dataset.id;
|
||||||
|
const currentRelation = line.dataset.relations;
|
||||||
|
|
||||||
|
selectRelation(subjectId, objectId, currentRelation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// select state of clicked line
|
||||||
|
body.querySelector("div.Self").classList.remove("Self");
|
||||||
|
el.parentElement.classList.add("Self");
|
||||||
|
refreshDiplomacyEditor();
|
||||||
|
});
|
||||||
|
|
||||||
function refreshDiplomacyEditor() {
|
function refreshDiplomacyEditor() {
|
||||||
diplomacyEditorAddLines();
|
diplomacyEditorAddLines();
|
||||||
|
|
@ -50,33 +82,32 @@ function editDiplomacy() {
|
||||||
function diplomacyEditorAddLines() {
|
function diplomacyEditorAddLines() {
|
||||||
const states = pack.states;
|
const states = pack.states;
|
||||||
const selectedLine = body.querySelector("div.Self");
|
const selectedLine = body.querySelector("div.Self");
|
||||||
const sel = selectedLine ? +selectedLine.dataset.id : states.find(s => s.i && !s.removed).i;
|
const selectedId = selectedLine ? +selectedLine.dataset.id : states.find(s => s.i && !s.removed).i;
|
||||||
const selName = states[sel].fullName;
|
const selectedName = states[selectedId].fullName;
|
||||||
diplomacySelect.style.display = "none";
|
|
||||||
|
|
||||||
COArenderer.trigger("stateCOA"+sel, states[sel].coa);
|
COArenderer.trigger("stateCOA" + selectedId, states[selectedId].coa);
|
||||||
let lines = `<div class="states Self" data-id=${sel} data-tip="List below shows relations to ${selName}">
|
let lines = `<div class="states Self" data-id=${selectedId} data-tip="List below shows relations to ${selectedName}">
|
||||||
<div style="width: max-content">${selName}</div>
|
<div style="width: max-content">${selectedName}</div>
|
||||||
<svg class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${sel}"></use></svg>
|
<svg class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${selectedId}"></use></svg>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
for (const s of states) {
|
for (const state of states) {
|
||||||
if (!s.i || s.removed || s.i === sel) continue;
|
if (!state.i || state.removed || state.i === selectedId) continue;
|
||||||
const relation = s.diplomacy[sel];
|
const relation = state.diplomacy[selectedId];
|
||||||
const index = statuses.indexOf(relation);
|
const {color, inText} = relations[relation];
|
||||||
const color = colors[index];
|
|
||||||
const tip = s.fullName + description[index] + selName;
|
|
||||||
const tipSelect = `${tip}. Click to see relations to ${s.name}`;
|
|
||||||
const tipChange = `${tip}. Click to change relations to ${selName}`;
|
|
||||||
COArenderer.trigger("stateCOA"+s.i, s.coa);
|
|
||||||
|
|
||||||
lines += `<div class="states" data-id=${s.i} data-name="${s.fullName}" data-relations="${relation}">
|
const tip = `${state.fullName} ${inText} ${selectedName}`;
|
||||||
<svg data-tip="${tipSelect}" class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${s.i}"></use></svg>
|
const tipSelect = `${tip}. Click to see relations to ${state.name}`;
|
||||||
<div data-tip="${tipSelect}" style="width:12em">${s.fullName}</div>
|
const tipChange = `${tip}. Click to change relations to ${selectedName}`;
|
||||||
|
COArenderer.trigger("stateCOA" + state.i, state.coa);
|
||||||
|
|
||||||
|
lines += `<div class="states" data-id=${state.i} data-name="${state.fullName}" data-relations="${relation}">
|
||||||
|
<svg data-tip="${tipSelect}" class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${state.i}"></use></svg>
|
||||||
|
<div data-tip="${tipSelect}" style="width:12em">${state.fullName}</div>
|
||||||
<svg data-tip="${tipChange}" width=".9em" height=".9em" style="margin-bottom:-1px" class="changeRelations">
|
<svg data-tip="${tipChange}" width=".9em" height=".9em" style="margin-bottom:-1px" class="changeRelations">
|
||||||
<rect x="0" y="0" width="100%" height="100%" fill="${color}" class="fillRect pointer" style="pointer-events: none"></rect>
|
<rect x="0" y="0" width="100%" height="100%" fill="${color}" class="fillRect pointer" style="pointer-events: none"></rect>
|
||||||
</svg>
|
</svg>
|
||||||
<input data-tip="${tipChange}" class="changeRelations diplomacyRelations" value="${relation}" readonly/>
|
<div data-tip="${tipChange}" class="changeRelations" style="width: 5em" />${relation}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
body.innerHTML = lines;
|
body.innerHTML = lines;
|
||||||
|
|
@ -84,8 +115,6 @@ function editDiplomacy() {
|
||||||
// add listeners
|
// add listeners
|
||||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseenter", ev => stateHighlightOn(ev)));
|
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseenter", ev => stateHighlightOn(ev)));
|
||||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseleave", ev => stateHighlightOff(ev)));
|
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseleave", ev => stateHighlightOff(ev)));
|
||||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("click", selectStateOnLineClick));
|
|
||||||
body.querySelectorAll(".changeRelations").forEach(el => el.addEventListener("click", toggleDiplomacySelect));
|
|
||||||
|
|
||||||
applySorting(diplomacyHeader);
|
applySorting(diplomacyHeader);
|
||||||
$("#diplomacyEditor").dialog();
|
$("#diplomacyEditor").dialog();
|
||||||
|
|
@ -95,19 +124,31 @@ function editDiplomacy() {
|
||||||
if (!layerIsOn("toggleStates")) return;
|
if (!layerIsOn("toggleStates")) return;
|
||||||
const state = +event.target.dataset.id;
|
const state = +event.target.dataset.id;
|
||||||
if (customization || !state) return;
|
if (customization || !state) return;
|
||||||
const d = regions.select("#state"+state).attr("d");
|
const d = regions.select("#state" + state).attr("d");
|
||||||
|
|
||||||
const path = debug.append("path").attr("class", "highlight").attr("d", d)
|
const path = debug
|
||||||
.attr("fill", "none").attr("stroke", "red").attr("stroke-width", 1).attr("opacity", 1)
|
.append("path")
|
||||||
|
.attr("class", "highlight")
|
||||||
|
.attr("d", d)
|
||||||
|
.attr("fill", "none")
|
||||||
|
.attr("stroke", "red")
|
||||||
|
.attr("stroke-width", 1)
|
||||||
|
.attr("opacity", 1)
|
||||||
.attr("filter", "url(#blur1)");
|
.attr("filter", "url(#blur1)");
|
||||||
|
|
||||||
const l = path.node().getTotalLength(), dur = (l + 5000) / 2;
|
const l = path.node().getTotalLength(),
|
||||||
|
dur = (l + 5000) / 2;
|
||||||
const i = d3.interpolateString("0," + l, l + "," + l);
|
const i = d3.interpolateString("0," + l, l + "," + l);
|
||||||
path.transition().duration(dur).attrTween("stroke-dasharray", function() {return t => i(t)});
|
path
|
||||||
|
.transition()
|
||||||
|
.duration(dur)
|
||||||
|
.attrTween("stroke-dasharray", function () {
|
||||||
|
return t => i(t);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function stateHighlightOff(event) {
|
function stateHighlightOff(event) {
|
||||||
debug.selectAll(".highlight").each(function() {
|
debug.selectAll(".highlight").each(function () {
|
||||||
d3.select(this).transition().duration(1000).attr("opacity", 0).remove();
|
d3.select(this).transition().duration(1000).attr("opacity", 0).remove();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -118,22 +159,17 @@ function editDiplomacy() {
|
||||||
if (!sel) return;
|
if (!sel) return;
|
||||||
if (!layerIsOn("toggleStates")) toggleStates();
|
if (!layerIsOn("toggleStates")) toggleStates();
|
||||||
|
|
||||||
statesBody.selectAll("path").each(function() {
|
statesBody.selectAll("path").each(function () {
|
||||||
if (this.id.slice(0, 9) === "state-gap") return; // exclude state gap element
|
if (this.id.slice(0, 9) === "state-gap") return; // exclude state gap element
|
||||||
const id = +this.id.slice(5); // state id
|
const id = +this.id.slice(5); // state id
|
||||||
const index = statuses.indexOf(pack.states[id].diplomacy[sel]); // status index
|
|
||||||
const clr = index !== -1 ? colors[index] : "#4682b4"; // Self (bluish)
|
|
||||||
this.setAttribute("fill", clr);
|
|
||||||
statesBody.select("#state-gap"+id).attr("stroke", clr);
|
|
||||||
statesHalo.select("#state-border"+id).attr("stroke", d3.color(clr).darker().hex());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectStateOnLineClick() {
|
const relation = pack.states[id].diplomacy[sel];
|
||||||
if (this.classList.contains("Self")) return;
|
const color = relations[relation]?.color || "#4682b4";
|
||||||
body.querySelector("div.Self").classList.remove("Self");
|
|
||||||
this.classList.add("Self");
|
this.setAttribute("fill", color);
|
||||||
refreshDiplomacyEditor();
|
statesBody.select("#state-gap" + id).attr("stroke", color);
|
||||||
|
statesHalo.select("#state-border" + id).attr("stroke", d3.color(color).darker().hex());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectStateOnMapClick() {
|
function selectStateOnMapClick() {
|
||||||
|
|
@ -145,42 +181,63 @@ function editDiplomacy() {
|
||||||
if (+selectedLine.dataset.id === state) return;
|
if (+selectedLine.dataset.id === state) return;
|
||||||
|
|
||||||
selectedLine.classList.remove("Self");
|
selectedLine.classList.remove("Self");
|
||||||
body.querySelector("div[data-id='"+state+"']").classList.add("Self");
|
body.querySelector("div[data-id='" + state + "']").classList.add("Self");
|
||||||
refreshDiplomacyEditor();
|
refreshDiplomacyEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleDiplomacySelect(event) {
|
function selectRelation(subjectId, objectId, currentRelation) {
|
||||||
event.stopPropagation();
|
const states = pack.states;
|
||||||
const select = document.getElementById("diplomacySelect");
|
|
||||||
const show = select.style.display === "none";
|
const subject = states[subjectId];
|
||||||
if (!show) {select.style.display = "none"; return;}
|
const header = `<div style="margin-bottom: 0.3em"><svg class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${subject.i}"></use></svg> <b>${subject.fullName}</b></div>`;
|
||||||
select.style.display = "block";
|
|
||||||
const input = event.target.closest("div").querySelector("input");
|
const options = Object.entries(relations)
|
||||||
select.style.left = input.getBoundingClientRect().left + "px";
|
.map(
|
||||||
select.style.top = input.getBoundingClientRect().bottom + "px";
|
([relation, {color, inText, tip}]) =>
|
||||||
body.dataset.state = event.target.closest("div.states").dataset.id;
|
`<div style="margin-block: 0.2em" data-tip="${tip}"><label class="pointer">
|
||||||
|
<input type="radio" name="relationSelect" value="${relation}" ${currentRelation === relation && "checked"} >
|
||||||
|
<svg width=".9em" height=".9em" style="margin-bottom:-1px">
|
||||||
|
<rect x="0" y="0" width="100%" height="100%" fill="${color}" class="fillRect" />
|
||||||
|
</svg>
|
||||||
|
${inText}
|
||||||
|
</label></div>`
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
const object = states[objectId];
|
||||||
|
const footer = `<div style="margin-top: 0.7em"><svg class="coaIcon" viewBox="0 0 200 200"><use href="#stateCOA${object.i}"></use></svg> <b>${object.fullName}</b></div>`;
|
||||||
|
|
||||||
|
alertMessage.innerHTML = `<div style="overflow: hidden">${header} ${options} ${footer}</div>`;
|
||||||
|
|
||||||
|
$("#alert").dialog({
|
||||||
|
width: fitContent(),
|
||||||
|
title: `Change relations`,
|
||||||
|
buttons: {
|
||||||
|
Apply: function () {
|
||||||
|
const newRelation = document.querySelector('input[name="relationSelect"]:checked')?.value;
|
||||||
|
changeRelation(subjectId, objectId, currentRelation, newRelation);
|
||||||
|
$(this).dialog("close");
|
||||||
|
},
|
||||||
|
Cancel: function () {
|
||||||
|
$(this).dialog("close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function diplomacyChangeRelations(event) {
|
function changeRelation(subjectId, objectId, oldRelation, newRelation) {
|
||||||
event.stopPropagation();
|
if (newRelation === oldRelation) return;
|
||||||
diplomacySelect.style.display = "none";
|
const states = pack.states;
|
||||||
const subject = +body.dataset.state;
|
const chronicle = states[0].diplomacy;
|
||||||
const rel = event.target.innerHTML;
|
|
||||||
|
|
||||||
const states = pack.states, chronicle = states[0].diplomacy;
|
const subjectName = states[subjectId].name;
|
||||||
const selectedLine = body.querySelector("div.Self");
|
const objectName = states[objectId].name;
|
||||||
const object = selectedLine ? +selectedLine.dataset.id : states.find(s => s.i && !s.removed).i;
|
|
||||||
if (!object) return;
|
|
||||||
const objectName = states[object].name; // object of relations change
|
|
||||||
const subjectName = states[subject].name; // subject of relations change - actor
|
|
||||||
|
|
||||||
const oldRel = states[subject].diplomacy[object];
|
states[subjectId].diplomacy[objectId] = newRelation;
|
||||||
if (rel === oldRel) return;
|
states[objectId].diplomacy[subjectId] = newRelation === "Vassal" ? "Suzerain" : newRelation === "Suzerain" ? "Vassal" : newRelation;
|
||||||
states[subject].diplomacy[object] = rel;
|
|
||||||
states[object].diplomacy[subject] = rel === "Vassal" ? "Suzerain" : rel === "Suzerain" ? "Vassal" : rel;
|
|
||||||
|
|
||||||
// update relation history
|
// update relation history
|
||||||
const change = () => [`Relations change`, `${subjectName}-${getAdjective(objectName)} relations changed to ${rel.toLowerCase()}`];
|
const change = () => [`Relations change`, `${subjectName}-${getAdjective(objectName)} relations changed to ${newRelation.toLowerCase()}`];
|
||||||
const ally = () => [`Defence pact`, `${subjectName} entered into defensive pact with ${objectName}`];
|
const ally = () => [`Defence pact`, `${subjectName} entered into defensive pact with ${objectName}`];
|
||||||
const vassal = () => [`Vassalization`, `${subjectName} became a vassal of ${objectName}`];
|
const vassal = () => [`Vassalization`, `${subjectName} became a vassal of ${objectName}`];
|
||||||
const suzerain = () => [`Vassalization`, `${subjectName} vassalized ${objectName}`];
|
const suzerain = () => [`Vassalization`, `${subjectName} vassalized ${objectName}`];
|
||||||
|
|
@ -189,22 +246,27 @@ function editDiplomacy() {
|
||||||
const war = () => [`War declaration`, `${subjectName} declared a war on its enemy ${objectName}`];
|
const war = () => [`War declaration`, `${subjectName} declared a war on its enemy ${objectName}`];
|
||||||
const peace = () => {
|
const peace = () => {
|
||||||
const treaty = `${subjectName} and ${objectName} agreed to cease fire and signed a peace treaty`;
|
const treaty = `${subjectName} and ${objectName} agreed to cease fire and signed a peace treaty`;
|
||||||
const changed = rel === "Ally" ? ally()
|
const changed =
|
||||||
: rel === "Vassal" ? vassal()
|
newRelation === "Ally"
|
||||||
: rel === "Suzerain" ? suzerain()
|
? ally()
|
||||||
: rel === "Unknown" ? unknown()
|
: newRelation === "Vassal"
|
||||||
|
? vassal()
|
||||||
|
: newRelation === "Suzerain"
|
||||||
|
? suzerain()
|
||||||
|
: newRelation === "Unknown"
|
||||||
|
? unknown()
|
||||||
: change();
|
: change();
|
||||||
return [`War termination`, treaty, changed[1]];
|
return [`War termination`, treaty, changed[1]];
|
||||||
}
|
};
|
||||||
|
|
||||||
if (oldRel === "Enemy") chronicle.push(peace()); else
|
if (oldRelation === "Enemy") chronicle.push(peace());
|
||||||
if (rel === "Enemy") chronicle.push(war()); else
|
else if (newRelation === "Enemy") chronicle.push(war());
|
||||||
if (rel === "Vassal") chronicle.push(vassal()); else
|
else if (newRelation === "Vassal") chronicle.push(vassal());
|
||||||
if (rel === "Suzerain") chronicle.push(suzerain()); else
|
else if (newRelation === "Suzerain") chronicle.push(suzerain());
|
||||||
if (rel === "Ally") chronicle.push(ally()); else
|
else if (newRelation === "Ally") chronicle.push(ally());
|
||||||
if (rel === "Unknown") chronicle.push(unknown()); else
|
else if (newRelation === "Unknown") chronicle.push(unknown());
|
||||||
if (rel === "Rival") chronicle.push(rival()); else
|
else if (newRelation === "Rival") chronicle.push(rival());
|
||||||
chronicle.push(change());
|
else chronicle.push(change());
|
||||||
|
|
||||||
refreshDiplomacyEditor();
|
refreshDiplomacyEditor();
|
||||||
}
|
}
|
||||||
|
|
@ -216,26 +278,38 @@ function editDiplomacy() {
|
||||||
|
|
||||||
function showRelationsHistory() {
|
function showRelationsHistory() {
|
||||||
const chronicle = pack.states[0].diplomacy;
|
const chronicle = pack.states[0].diplomacy;
|
||||||
if (!chronicle.length) {tip("Relations history is blank", false, "error"); return;}
|
if (!chronicle.length) {
|
||||||
|
tip("Relations history is blank", false, "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let message = `<div autocorrect="off" spellcheck="false">`;
|
let message = `<div autocorrect="off" spellcheck="false">`;
|
||||||
chronicle.forEach((e, d) => {
|
chronicle.forEach((entry, d) => {
|
||||||
message += `<div>`;
|
message += `<div>`;
|
||||||
e.forEach((l, i) => message += `<div contenteditable="true" data-id="${d}-${i}"${i ? "" : " style='font-weight:bold'"}>${l}</div>`);
|
entry.forEach((l, i) => {
|
||||||
|
message += `<div contenteditable="true" data-id="${d}-${i}"${i ? "" : " style='font-weight:bold'"}>${l}</div>`;
|
||||||
|
});
|
||||||
message += `‍</div>`;
|
message += `‍</div>`;
|
||||||
});
|
});
|
||||||
alertMessage.innerHTML = message + `</div><i id="info-line">Type to edit. Press Enter to add a new line, empty the element to remove it</i>`;
|
alertMessage.innerHTML = message + `</div><i id="info-line">Type to edit. Press Enter to add a new line, empty the element to remove it</i>`;
|
||||||
alertMessage.querySelectorAll("div[contenteditable='true']").forEach(el => el.addEventListener("input", changeReliationsHistory));
|
alertMessage.querySelectorAll("div[contenteditable='true']").forEach(el => el.addEventListener("input", changeReliationsHistory));
|
||||||
|
|
||||||
$("#alert").dialog({title: "Relations history", position: {my: "center", at: "center", of: "svg"},
|
$("#alert").dialog({
|
||||||
|
title: "Relations history",
|
||||||
|
position: {my: "center", at: "center", of: "svg"},
|
||||||
buttons: {
|
buttons: {
|
||||||
Save: function() {
|
Save: function () {
|
||||||
const data = this.querySelector("div").innerText.split("\n").join("\r\n");
|
const data = this.querySelector("div").innerText.split("\n").join("\r\n");
|
||||||
const name = getFileName("Relations history") + ".txt";
|
const name = getFileName("Relations history") + ".txt";
|
||||||
downloadFile(data, name);
|
downloadFile(data, name);
|
||||||
},
|
},
|
||||||
Clear: function() {pack.states[0].diplomacy = []; $(this).dialog("close");},
|
Clear: function () {
|
||||||
Close: function() {$(this).dialog("close");}
|
pack.states[0].diplomacy = [];
|
||||||
|
$(this).dialog("close");
|
||||||
|
},
|
||||||
|
Close: function () {
|
||||||
|
$(this).dialog("close");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -251,22 +325,41 @@ function editDiplomacy() {
|
||||||
|
|
||||||
function showRelationsMatrix() {
|
function showRelationsMatrix() {
|
||||||
const states = pack.states.filter(s => s.i && !s.removed);
|
const states = pack.states.filter(s => s.i && !s.removed);
|
||||||
const valid = states.map(s => s.i);
|
const valid = states.map(state => state.i);
|
||||||
|
const body = document.getElementById("diplomacyMatrixBody");
|
||||||
|
|
||||||
let message = `<table class="matrix-table"><tr><th data-tip='‍'></th>`;
|
let table = `<table><thead><tr><th data-tip='‍'></th>`;
|
||||||
message += states.map(s => `<th data-tip='See relations to ${s.fullName}'>${s.name}</th>`).join("") + `</tr>`; // headers
|
table += states.map(state => `<th data-tip='Relations to ${state.fullName}'>${state.name}</th>`).join("") + `</tr>`;
|
||||||
states.forEach(s => {
|
table += `<tbody>`;
|
||||||
message += `<tr><th data-tip='See relations of ${s.fullName}'>${s.name}</th>` + s.diplomacy
|
|
||||||
.filter((v, i) => valid.includes(i)).map((r, i) => {
|
states.forEach(state => {
|
||||||
const desc = description[statuses.indexOf(r)];
|
table +=
|
||||||
const tip = desc ? s.fullName + desc + pack.states[valid[i]].fullName : '‍';
|
`<tr><th data-tip='Relations of ${state.fullName}'>${state.name}</th>` +
|
||||||
return `<td data-tip='${tip}' class='${r}'>${r}</td>`
|
state.diplomacy
|
||||||
}).join("") + "</tr>";
|
.filter((v, i) => valid.includes(i))
|
||||||
|
.map((relation, index) => {
|
||||||
|
const relationObj = relations[relation];
|
||||||
|
if (!relationObj) return `<td class='${relation}'>${relation}</td>`;
|
||||||
|
|
||||||
|
const stateName = pack.states[valid[index]].fullName;
|
||||||
|
const tip = `${state.fullName} ${relationObj.inText} ${stateName}`;
|
||||||
|
return `<td data-tip='${tip}' class='${relation}'>${relation}</td>`;
|
||||||
|
})
|
||||||
|
.join("") +
|
||||||
|
"</tr>";
|
||||||
});
|
});
|
||||||
message += `</table>`;
|
|
||||||
alertMessage.innerHTML = message;
|
|
||||||
|
|
||||||
$("#alert").dialog({title: "Relations matrix", width: fitContent(), position: {my: "center", at: "center", of: "svg"}, buttons: {}});
|
table += `</tbody></table>`;
|
||||||
|
body.innerHTML = table;
|
||||||
|
|
||||||
|
const tableEl = body.querySelector("table");
|
||||||
|
tableEl.addEventListener("click", showRelationsDropdown);
|
||||||
|
|
||||||
|
$("#diplomacyMatrix").dialog({title: "Relations matrix", position: {my: "center", at: "center", of: "svg"}, buttons: {}});
|
||||||
|
|
||||||
|
function showRelationsDropdown() {
|
||||||
|
if (this.tagName !== "TD") return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadDiplomacyData() {
|
function downloadDiplomacyData() {
|
||||||
|
|
@ -288,7 +381,8 @@ function editDiplomacy() {
|
||||||
clearMainTip();
|
clearMainTip();
|
||||||
const selected = body.querySelector("div.Self");
|
const selected = body.querySelector("div.Self");
|
||||||
if (selected) selected.classList.remove("Self");
|
if (selected) selected.classList.remove("Self");
|
||||||
if (layerIsOn("toggleStates")) drawStates(); else toggleStates();
|
if (layerIsOn("toggleStates")) drawStates();
|
||||||
|
else toggleStates();
|
||||||
debug.selectAll(".highlight").remove();
|
debug.selectAll(".highlight").remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ function editProvinces() {
|
||||||
p.color
|
p.color
|
||||||
}" class="fillRect pointer"></svg>
|
}" class="fillRect pointer"></svg>
|
||||||
<input data-tip="Province name. Click to change" class="name pointer" value="${p.name}" readonly>
|
<input data-tip="Province name. Click to change" class="name pointer" value="${p.name}" readonly>
|
||||||
<svg data-tip="Click to show and edit province emblem" class="coaIcon hide" viewBox="0 0 200 200"><use href="#provinceCOA${p.i}"></use></svg>
|
<svg data-tip="Click to show and edit province emblem" class="coaIcon pointer hide" viewBox="0 0 200 200"><use href="#provinceCOA${p.i}"></use></svg>
|
||||||
<input data-tip="Province form name. Click to change" class="name pointer hide" value="${p.formName}" readonly>
|
<input data-tip="Province form name. Click to change" class="name pointer hide" value="${p.formName}" readonly>
|
||||||
<span data-tip="Province capital. Click to zoom into view" class="icon-star-empty pointer hide ${p.burg ? "" : "placeholder"}"></span>
|
<span data-tip="Province capital. Click to zoom into view" class="icon-star-empty pointer hide ${p.burg ? "" : "placeholder"}"></span>
|
||||||
<select data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital" class="cultureBase hide ${
|
<select data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital" class="cultureBase hide ${
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ function editStates() {
|
||||||
s.color
|
s.color
|
||||||
}" class="fillRect pointer"></svg>
|
}" class="fillRect pointer"></svg>
|
||||||
<input data-tip="State name. Click to change" class="stateName name pointer" value="${s.name}" readonly>
|
<input data-tip="State name. Click to change" class="stateName name pointer" value="${s.name}" readonly>
|
||||||
<svg data-tip="Click to show and edit state emblem" class="coaIcon hide" viewBox="0 0 200 200"><use href="#stateCOA${s.i}"></use></svg>
|
<svg data-tip="Click to show and edit state emblem" class="coaIcon pointer hide" viewBox="0 0 200 200"><use href="#stateCOA${s.i}"></use></svg>
|
||||||
<input data-tip="State form name. Click to change" class="stateForm name pointer" value="${s.formName}" readonly>
|
<input data-tip="State form name. Click to change" class="stateForm name pointer" value="${s.formName}" readonly>
|
||||||
<span data-tip="State capital. Click to zoom into view" class="icon-star-empty pointer hide"></span>
|
<span data-tip="State capital. Click to zoom into view" class="icon-star-empty pointer hide"></span>
|
||||||
<input data-tip="Capital name. Click and type to rename" class="stateCapital hide" value="${capital}" autocorrect="off" spellcheck="false"/>
|
<input data-tip="Capital name. Click and type to rename" class="stateCapital hide" value="${capital}" autocorrect="off" spellcheck="false"/>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue