285 lines
7.8 KiB
JavaScript
285 lines
7.8 KiB
JavaScript
import getTranslations from './i18n/mapCoordsPicker';
|
|
import { getItem, setItem } from './utils/localStorage';
|
|
|
|
// ==UserScript==
|
|
// @name Map coords picker
|
|
// @namespace https://github.com/tribalwarshelp/scripts
|
|
// @updateURL https://raw.githubusercontent.com/tribalwarshelp/scripts/master/dist/mapCoordsPicker.js
|
|
// @downloadURL https://raw.githubusercontent.com/tribalwarshelp/scripts/master/dist/mapCoordsPicker.js
|
|
// @version 0.7.4
|
|
// @description Map coords picker
|
|
// @author Kichiyaki https://dwysokinski.me/
|
|
// @match *://*/game.php*screen=map*
|
|
// @grant none
|
|
// ==/UserScript==
|
|
|
|
const LOCAL_STORAGE_KEY = 'kichiyaki_map_coords_picker';
|
|
const container = document.querySelector('#content_value > h2');
|
|
let button;
|
|
let formsContainer;
|
|
let actionsContainer;
|
|
let config = getItem(LOCAL_STORAGE_KEY, {
|
|
started: false,
|
|
groups: {
|
|
All: {
|
|
villages: [],
|
|
color: '#ffffff',
|
|
},
|
|
},
|
|
selectedGroup: 'All',
|
|
});
|
|
let intervalID;
|
|
const translations = getTranslations();
|
|
|
|
const saveConfig = () => {
|
|
setItem(LOCAL_STORAGE_KEY, config);
|
|
};
|
|
|
|
const villageIDByCoords = (x, y) => {
|
|
const xy = parseInt(`${x}${y}`, 10);
|
|
const village = TWMap.villages[xy];
|
|
if (village) {
|
|
return TWMap.villages[xy].id;
|
|
}
|
|
return NaN;
|
|
};
|
|
|
|
const setVillageBorder = (x, y, color = 'transparent') => {
|
|
const id = villageIDByCoords(x, y);
|
|
if (isNaN(id)) return;
|
|
const village = document.querySelector('#map_village_' + id);
|
|
if (village) {
|
|
village.style.boxSizing = 'border-box';
|
|
village.style.border =
|
|
color !== 'transparent' ? `5px solid ${color}` : 'none';
|
|
}
|
|
};
|
|
|
|
const deleteVillageFromOtherGroups = key => {
|
|
for (let name in config.groups) {
|
|
if (name === config.selectedGroup) return;
|
|
config.groups[name].villages = config.groups[name].villages.filter(
|
|
village => village.key !== key
|
|
);
|
|
}
|
|
};
|
|
|
|
const handleMapClick = (x, y, e) => {
|
|
e.preventDefault();
|
|
|
|
const key = `${x}|${y}`;
|
|
const selected = config.groups[config.selectedGroup].villages.some(
|
|
village => village.key === key
|
|
);
|
|
if (selected) {
|
|
config.groups[config.selectedGroup].villages = config.groups[
|
|
config.selectedGroup
|
|
].villages.filter(village => village.key !== key);
|
|
setVillageBorder(x, y, 'transparent');
|
|
} else {
|
|
config.groups[config.selectedGroup].villages = [
|
|
...config.groups[config.selectedGroup].villages,
|
|
{
|
|
x,
|
|
y,
|
|
key,
|
|
},
|
|
];
|
|
setVillageBorder(x, y, config.groups[config.selectedGroup].color);
|
|
deleteVillageFromOtherGroups(key);
|
|
}
|
|
};
|
|
|
|
const renderForm = (container, group) => {
|
|
const selected = group && group.name !== config.selectedGroup;
|
|
const html = `
|
|
<input type="color" value="${group ? group.color : ''}" required />
|
|
<input type="text" required placeholder="${
|
|
translations.groupName
|
|
}" value="${group ? group.name : ''}" />
|
|
<button type="submit">${
|
|
group ? translations.save : translations.add
|
|
}</button>
|
|
${
|
|
group
|
|
? `<button type="button">${translations.delete}</button>`
|
|
: ''
|
|
}
|
|
${
|
|
selected
|
|
? `<button class="selectButton" type="button">${translations.select}</button>`
|
|
: ''
|
|
}
|
|
`;
|
|
|
|
const form = document.createElement('form');
|
|
form.innerHTML = html;
|
|
form.addEventListener('submit', e => {
|
|
e.preventDefault();
|
|
if (group) {
|
|
if (group.name === config.selectedGroup)
|
|
config.selectedGroup = e.target[1].value;
|
|
colorizeGroupVillages(group.name, e.target[0].value);
|
|
config.groups[e.target[1].value] = {
|
|
...config.groups[group.name],
|
|
|
|
color: e.target[0].value,
|
|
};
|
|
if (group.name !== e.target[1].value) delete config.groups[group.name];
|
|
} else {
|
|
config.groups[e.target[1].value] = {
|
|
color: e.target[0].value,
|
|
villages: [],
|
|
};
|
|
}
|
|
renderGroups();
|
|
});
|
|
if (group) {
|
|
form
|
|
.querySelector('button[type="button"]')
|
|
.addEventListener('click', () => {
|
|
if (config.selectedGroup === group.name) {
|
|
return UI.ErrorMessage(translations.cannotDeleteSelectedGroup);
|
|
}
|
|
colorizeGroupVillages(group.name, 'transparent');
|
|
delete config.groups[group.name];
|
|
form.remove();
|
|
});
|
|
|
|
const selectButton = form.querySelector('.selectButton');
|
|
if (selectButton) {
|
|
selectButton.addEventListener('click', e => {
|
|
config.selectedGroup = group.name;
|
|
renderGroups();
|
|
});
|
|
}
|
|
}
|
|
|
|
container.appendChild(form);
|
|
};
|
|
|
|
const renderGroups = () => {
|
|
formsContainer.innerHTML = '';
|
|
for (let name in config.groups) {
|
|
renderForm(formsContainer, { ...config.groups[name], name });
|
|
}
|
|
renderForm(formsContainer);
|
|
};
|
|
|
|
const handleExportVillages = () => {
|
|
const groups = [];
|
|
|
|
for (let name in config.groups) {
|
|
groups.push(`<div style="margin-bottom: 30px;">
|
|
<h3>${name}</h3>
|
|
<textarea cols=30 rows=8 readonly>${config.groups[name].villages
|
|
.map(village => village.key)
|
|
.join(' ')
|
|
.trim()}</textarea>
|
|
</div>`);
|
|
}
|
|
|
|
const html = `
|
|
${groups.join('')}
|
|
`;
|
|
|
|
Dialog.show(translations.exportedVillages, html);
|
|
};
|
|
|
|
const renderActions = () => {
|
|
const exportVillages = document.createElement('button');
|
|
exportVillages.innerHTML = translations.export;
|
|
exportVillages.addEventListener('click', handleExportVillages);
|
|
actionsContainer.appendChild(exportVillages);
|
|
};
|
|
|
|
const handleSpawnSector = (data, sector) => {
|
|
TWMap.mapHandler.__spawnSector(data, sector);
|
|
colorizeVillages();
|
|
};
|
|
|
|
const handleStart = () => {
|
|
TWMap.map.handler.__onClick = TWMap.map.handler.onClick;
|
|
TWMap.map.handler.onClick = handleMapClick;
|
|
TWMap.mapHandler.__spawnSector = TWMap.map.handler.spawnSector;
|
|
TWMap.mapHandler.spawnSector = handleSpawnSector;
|
|
button.innerHTML = translations.stopCoordsPicker;
|
|
renderActions();
|
|
colorizeVillages();
|
|
renderGroups();
|
|
intervalID = setInterval(saveConfig, 500);
|
|
};
|
|
|
|
const handleStop = () => {
|
|
if (typeof TWMap.map.handler.__onClick === 'function') {
|
|
TWMap.map.handler.onClick = TWMap.map.handler.__onClick;
|
|
}
|
|
if (typeof TWMap.map.handler.__spawnSector === 'function') {
|
|
TWMap.mapHandler.spawnSector = TWMap.map.handler.__spawnSector;
|
|
}
|
|
button.innerHTML = translations.startCoordsPicker;
|
|
formsContainer.innerHTML = '';
|
|
actionsContainer.innerHTML = '';
|
|
colorizeVillages('transparent');
|
|
if (intervalID) {
|
|
clearInterval(intervalID);
|
|
}
|
|
for (let name in config.groups) {
|
|
config.groups[name].villages = [];
|
|
}
|
|
};
|
|
|
|
const handleButtonClick = () => {
|
|
if (config.started) {
|
|
handleStop();
|
|
} else {
|
|
handleStart();
|
|
}
|
|
config.started = !config.started;
|
|
saveConfig();
|
|
};
|
|
|
|
const colorizeGroupVillages = (name, bgColor = '') => {
|
|
config.groups[name].villages.forEach(village => {
|
|
setVillageBorder(
|
|
village.x,
|
|
village.y,
|
|
bgColor ? bgColor : config.groups[name].color
|
|
);
|
|
});
|
|
};
|
|
|
|
const colorizeVillages = (bgColor = '') => {
|
|
for (let name in config.groups) {
|
|
colorizeGroupVillages(name, bgColor);
|
|
}
|
|
};
|
|
|
|
const renderUI = () => {
|
|
button = document.createElement('button');
|
|
button.style.marginLeft = '5px';
|
|
button.innerHTML = config.started
|
|
? translations.stopCoordsPicker
|
|
: translations.startCoordsPicker;
|
|
button.addEventListener('click', handleButtonClick);
|
|
container.appendChild(button);
|
|
|
|
formsContainer = document.createElement('div');
|
|
container.parentElement.insertBefore(formsContainer, container.nextSibling);
|
|
|
|
actionsContainer = document.createElement('div');
|
|
container.parentElement.insertBefore(actionsContainer, container.nextSibling);
|
|
|
|
if (config.started) {
|
|
handleStart();
|
|
}
|
|
};
|
|
|
|
(function () {
|
|
try {
|
|
renderUI();
|
|
} catch (error) {
|
|
console.log('Map Coords Picker', error);
|
|
}
|
|
})();
|