// ==UserScript==
// @name Webgame vylepšení
// @version 2024-07-12
// @description Sbírka vylepšení pro hru Webgame
// @author yS
// @match *://*.webgame.cz/wg/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM_info
// @icon https://www.google.com/s2/favicons?sz=64&domain=webgame.cz
// @namespace https://greasyfork.org/users/1005892
// ==/UserScript==
// TODO:
// nastaveni zobrazeni pomeru ztrat prestize utocnika / obrance
// nastaveni prevodu techu na $
// otestovat obyc listu
// archiv - ztraty nase / nepritele
// archiv - ztraty v $
// rozvedka - dohromady - nejlepsi cile pro operace
(function () {
"use strict";
// options
const VALKY_OBRACENE = "valky_flipped";
const ZOBRAZENE_ZOLDY = "zobrazene_zoldy";
const MODIFY_ARCHIVE = "modify_archive";
const MODIFY_ADVANCEMENTS = "modify_advancements";
// menu options
const ROZVOJ_MENU_LINK = "rozvoj";
const GENERALS_MENU_LINK = "generalove";
const PRODEJ_MENU_LINK = "prodej";
const POKROKY_MENU_LINK = "pokroky";
// budovy settings
const COUNTRY_ALI_DATA = "country_ali_data";
const COUNTRY_ALI_DATA_TIME_OFFSET_MILLIS = 24 * 60 * 60 * 1000;
// rozvedka
const SPY_SHOW_REPEAT_ACTIONS = "spy_show_repeat_actions";
const SPY_SHOW_STATS = "spy_show_stats";
const REPEAT_ROZVEDKA = "rozvedka_repeat";
const MAX_OBTIZNOST_OPERACE = "rozvedka_difficulty";
const INF_MODIFY_INFILTRATION = "inf_modify_infiltration";
const INF_LAND_PERCENTAGE_HIGHLIGHT = "inf_land_prestige_highlight";
const INF_TECH_PERCENTAGE_HIGHLIGHT = "inf_tech_prestige_highlight";
const INF_MRTVA_PRES_PERCENTAGE_HIGHLIGHT = "inf_dead_prestige_highlight";
const INF_STEAL_TECH_COUNT_HIGHLIGHT = "inf_steal_tech_highlight";
// prices
const ENERGY_PRICE = "energy";
const FOOD_PRICE = "food";
const TECHNOLOGY_PRICES = "tech_prices";
// country stats
const COUNTRY_STATS = "country_stats";
// pokroky
const ADV_SHOW_BASE_PRICE = "advancements_show_base_price";
const ADV_SHOW_BASE_PRICE_IN_TOOLTIP = "advancements_show_base_price_tooltip";
const ADV_SHOW_MIN_PRICE = "advancements_show_min_price";
const ADV_SHOW_MIN_PRICE_IN_TOOLTIP = "advancements_show_min_price_tooltip";
const ADV_SHOW_CURRENT_PRICE = "advancements_show_current_price";
// aliance
const ALI_ALLOW_CHANGES = "aliance_modify";
const ALI_SHOW_CARDS = "aliance_show_cards";
const ALI_SHOW_REGIME = "aliance_show_regime";
const ALI_SHOW_ROCKETS = "aliance_show_rockets";
const ALI_SHOW_WARS = "aliance_show_wars";
const ALI_WARS_WITH_ANCHORS = "aliance_show_wars_with_anchors";
const ALI_SHOW_FILTER = "aliance_show_filter";
const ALI_SAVED_INFO = "aliance_saved_info";
// strike
const STRIKE_SHOW_EXP = "strike_show_exp";
const STRIKE_WARNING_DISABLES_BUTTON = "strike_warning_disables_button";
const STRIKE_SHOW_BUILD_BUTTON = "strike_show_build_button";
const STRIKE_SHOW_GRANT_EXP_TO_GENERAL_BUTTON = "strike_show_grant_exp_to_general_button";
const STRIKE_SHOW_BURN_LAND_BUTTON = "strike_show_burn_land_button";
const USED_SETTINGS = [
ROZVOJ_MENU_LINK,
GENERALS_MENU_LINK,
PRODEJ_MENU_LINK,
POKROKY_MENU_LINK,
SPY_SHOW_REPEAT_ACTIONS,
INF_MODIFY_INFILTRATION,
SPY_SHOW_STATS,
REPEAT_ROZVEDKA,
MAX_OBTIZNOST_OPERACE,
INF_LAND_PERCENTAGE_HIGHLIGHT,
INF_TECH_PERCENTAGE_HIGHLIGHT,
INF_MRTVA_PRES_PERCENTAGE_HIGHLIGHT,
INF_STEAL_TECH_COUNT_HIGHLIGHT,
VALKY_OBRACENE,
ZOBRAZENE_ZOLDY,
ENERGY_PRICE,
FOOD_PRICE,
COUNTRY_ALI_DATA,
COUNTRY_STATS,
TECHNOLOGY_PRICES,
MODIFY_ARCHIVE,
MODIFY_ADVANCEMENTS,
ADV_SHOW_BASE_PRICE,
ADV_SHOW_BASE_PRICE_IN_TOOLTIP,
ADV_SHOW_MIN_PRICE,
ADV_SHOW_MIN_PRICE_IN_TOOLTIP,
ADV_SHOW_CURRENT_PRICE,
ALI_ALLOW_CHANGES,
ALI_SHOW_CARDS,
ALI_SHOW_REGIME,
ALI_SHOW_ROCKETS,
ALI_SHOW_WARS,
ALI_WARS_WITH_ANCHORS,
ALI_SHOW_FILTER,
ALI_SAVED_INFO,
STRIKE_SHOW_EXP,
STRIKE_WARNING_DISABLES_BUTTON,
STRIKE_SHOW_BUILD_BUTTON,
STRIKE_SHOW_GRANT_EXP_TO_GENERAL_BUTTON,
STRIKE_SHOW_BURN_LAND_BUTTON,
];
function execute() {
const modified_pages_data = [
{
url: "p=zebricek&s=aliazebr",
script: modifyAliZebricek,
},
{
url: "s=detailyaliance",
script: modifyDetailyAli,
},
{
url: "p=konflikty&s=awarstat&getali=",
script: modifyValky,
},
{
url: "s=ppravidla",
script: modifyPravidlaValky,
},
{
url: "p=dotace&s=ehelp",
script: modifyHospoPage,
},
{
url: "s=detailyprestiz",
script: processPrestigeDetails,
},
{
url: "p=archiv",
script: modifyArchive,
},
{
url: "p=technologie&s=pokroky",
script: modifyAdvancements,
},
{
url: "p=valka",
script: modifyValka,
},
{
url: "p=zebricek&s=stats",
script: modifyStatisticsPage,
},
{
url: "p=detaily",
script: processCountryDetail,
},
{
url: "p=rozvedka",
script: modifyRozvedka,
},
];
deleteUnusedSettings();
createMenuItemSettings();
addMenuLinks();
modifyLista();
modified_pages_data.forEach(({ url, script }) => {
if (window.location.href.includes(url)) {
script();
}
});
}
let log;
setLogger(console.log);
function setLogger(logger) {
// eslint-disable-next-line no-undef
log = logger.bind(console, `[${GM_info.script.name}]`);
}
function setSetting(setting_name, value) {
// eslint-disable-next-line no-undef
GM_setValue(setting_name, value);
}
function getSetting(setting_name, default_value) {
// eslint-disable-next-line no-undef
return GM_getValue(setting_name, default_value);
}
async function deleteUnusedSettings() {
// eslint-disable-next-line no-undef
const keys = await GM_listValues();
keys.forEach((key) => {
if (!USED_SETTINGS.includes(key)) {
// eslint-disable-next-line no-undef
GM_deleteValue(key);
}
});
}
function createMenuItemSettings() {
const menu = document.getElementById("left_menu");
const list = menu.children[0];
let li = createElement("li");
list.appendChild(li);
let ul = createElement("ul");
li.appendChild(ul);
li = createElement("li");
ul.appendChild(li);
const settings_button = createElement("a", { textContent: "Modifikace ⚙️" });
settings_button.addEventListener("click", function () {
let element = document.getElementById("settings_container");
element.classList.toggle("hidden");
});
li.appendChild(settings_button);
createSettingsWindow();
}
function createElement(tag = "div", props = null) {
let element = document.createElement(tag);
for (const key in props) {
if (!Object.hasOwnProperty.call(props, key)) {
continue;
}
const value = props[key];
element[key] = value;
}
return element;
}
function createButton(text, func = null, params = null, props = {}) {
if (props === null) props = {};
props.textContent = text;
props.type = "button";
const class_name = props.className ? props.className + " " : "";
props.className = class_name + "submit btn";
let button = createElement("button", props);
button.addEventListener("click", (e) => {
if (func !== null) {
func(params, e);
}
});
return button;
}
function addDoubleClickProtection(button) {
button.addEventListener("click", () => {
button.disabled = true;
setTimeout(() => {
button.disabled = false;
}, 1000);
});
}
function createSettingsWindow() {
CssHelper.addSavedCss(CssHelper.styles.settings);
const content = document.getElementById("content");
const container = createElement("div", { id: "settings_container", className: "hidden" });
content.appendChild(container);
const overlay = createElement("div", { className: "overlay" });
container.appendChild(overlay);
const div = createElement("div", { id: "settings_window", className: "settings_window" });
container.appendChild(div);
const toggle_container = function () {
container.classList.toggle("hidden");
};
overlay.addEventListener("click", toggle_container);
let button = createButton("x", toggle_container, null, { className: "btn-close" });
div.appendChild(button);
let settings = [
{
menu_link_header: { label: "Zobrazit v menu odkazy na:", header: true },
rozvoj_menu_link: { setting_name: ROZVOJ_MENU_LINK, label: "Rozvoj", default_value: true },
generalove_menu_link: { setting_name: GENERALS_MENU_LINK, label: "Generály", default_value: true },
prodej_menu_link: { setting_name: PRODEJ_MENU_LINK, label: "Prodej", default_value: true },
pokroky_menu_link: { setting_name: POKROKY_MENU_LINK, label: "Pokroky", default_value: true },
},
{
pokroky_header: { label: "Pokroky:", header: true },
pokroky_changes: { setting_name: MODIFY_ADVANCEMENTS, label: "Povolit změny", default_value: true },
min_price: { setting_name: ADV_SHOW_MIN_PRICE, label: "Povolit zobrazení minimální ceny", default_value: true },
min_price_tooltip: { setting_name: ADV_SHOW_MIN_PRICE_IN_TOOLTIP, label: "Zobrazit minimální cenu v tooltipu", default_value: false },
base_price: { setting_name: ADV_SHOW_BASE_PRICE, label: "Povolit zobrazení základní ceny", default_value: true },
base_price_tooltip: { setting_name: ADV_SHOW_BASE_PRICE_IN_TOOLTIP, label: "Zobrazit základní cenu v tooltipu", default_value: true },
current_price: { setting_name: ADV_SHOW_CURRENT_PRICE, label: "Zobrazit aktuální cenu", default_value: true },
},
{
spy_header: { label: "Rozvědka:", header: true },
spy_show_repeat_action: { setting_name: SPY_SHOW_REPEAT_ACTIONS, label: "Zobrazit menu opakování operací", default_value: true },
spy_show_stats: { setting_name: SPY_SHOW_STATS, label: "Zobrazit statistiky rozvědky", default_value: true },
},
{
strike_header: { label: "Útok:", header: true },
strike_exp: { setting_name: STRIKE_SHOW_EXP, label: "Zobrazit zkušenosti za kolo", default_value: true },
strike_button: { setting_name: STRIKE_WARNING_DISABLES_BUTTON, label: "Potvrzení útoku při porušení pravidel", default_value: true },
strike_stavebka_button: { setting_name: STRIKE_SHOW_BUILD_BUTTON, label: "Dopříprava - možnost postavit stavebku", default_value: true },
strike_dotace_button: { setting_name: STRIKE_SHOW_GRANT_EXP_TO_GENERAL_BUTTON, label: "Dopříprava - možnost dotace generála", default_value: true },
strike_burn_land_button: { setting_name: STRIKE_SHOW_BURN_LAND_BUTTON, label: "Dopříprava - možnost spálení hlíny", default_value: false },
},
{
archive_header: { label: "Archiv:", header: true },
archive_changes: { setting_name: MODIFY_ARCHIVE, label: "Povolit změny", default_value: true },
},
{
inf_header: { label: "Infiltrace:", header: true },
inf_modify_infiltrations: { setting_name: INF_MODIFY_INFILTRATION, label: "Povolit úpravy", default_value: true },
inf_land_highlight: {
setting_name: INF_LAND_PERCENTAGE_HIGHLIGHT,
label: "Zvýraznit území, když je přes x %",
default_value: 20,
props: { type: "number", min: 0, max: 100, step: 1 },
},
inf_tech_hightlight: {
setting_name: INF_TECH_PERCENTAGE_HIGHLIGHT,
label: "Zvýraznit technologie, když je jich přes x %",
default_value: 30,
props: { type: "number", min: 0, max: 100, step: 1 },
},
inf_dead_pres_highlight: {
setting_name: INF_MRTVA_PRES_PERCENTAGE_HIGHLIGHT,
label: "Zvýraznit mrtvou prestiž, když jí je přes x %",
default_value: 10,
props: { type: "number", min: 0, max: 100, step: 1 },
},
inf_steal_tech_highlight: {
setting_name: INF_STEAL_TECH_COUNT_HIGHLIGHT,
label: "Zvýraznit krádež technologií, když je přes počet",
default_value: 1000,
props: { type: "number", min: 0, step: 10 },
},
},
{
ali_header: { label: "Žebříček aliancí:", header: true },
ali_changes: { setting_name: ALI_ALLOW_CHANGES, label: "Povolit změny", default_value: true },
ali_show_cards: { setting_name: ALI_SHOW_CARDS, label: "Zobrazit sloupec kartiček", default_value: true },
ali_show_regime: { setting_name: ALI_SHOW_REGIME, label: "Zobrazit sloupec zřízení", default_value: true },
ali_show_rockets: { setting_name: ALI_SHOW_ROCKETS, label: "Zobrazit sloupec rakety", default_value: true },
ali_show_wars: { setting_name: ALI_SHOW_WARS, label: "Zobrazit sloupec válek", default_value: true },
ali_show_wars_with_anchors: { setting_name: ALI_WARS_WITH_ANCHORS, label: "Sloupec válek obsahuje i kotvy", default_value: true },
ali_show_filter: { setting_name: ALI_SHOW_FILTER, label: "Zobrazit filtr", default_value: true },
},
{
others_header: { label: "Jiné:", header: true },
zobrazene_zoldy: { setting_name: ZOBRAZENE_ZOLDY, label: "Zobrazit výdaje armády v detailu země", default_value: true },
valky_obracene: { setting_name: VALKY_OBRACENE, label: "Války - poměr prestiží na začátku: vyhlašující ali / cílová", default_value: true },
},
];
for (let index = 0; index < settings.length; index++) {
const block = settings[index];
const container = createElement("div", { className: "block" });
div.appendChild(container);
for (const key in block) {
const setting = block[key];
if (setting.header) {
const h3 = createElement("h3", { textContent: setting.label });
container.appendChild(h3);
} else {
const config = createConfig(setting.setting_name, setting.label, false, setting.default_value, setting.props ? setting.props : {});
container.appendChild(config);
}
}
}
button = createButton(
"Refresh stránky",
() => {
refreshPage();
},
null,
{ className: "btn-refresh" }
);
div.appendChild(button);
}
function wrapInTooltip(element) {
element.classList.add("tooltiptext");
element.parentElement.classList.add("tooltip");
}
function createConfig(setting_name, label_text, force_reload = false, default_value = true, props) {
let label = createElement("label");
const value = getSetting(setting_name, default_value);
if (props.type === undefined) {
props.type = "checkbox";
props.checked = value;
} else {
props.value = value;
}
let input = createElement("input", props);
label.appendChild(input);
label.appendChild(document.createTextNode(label_text));
input.addEventListener("change", function () {
if (input.type === "checkbox") {
setSetting(setting_name, input.checked);
} else {
input.value = Number(input.value);
if (input.max && input.value > Number(input.max)) input.value = Number(input.max);
if (input.min && input.value < Number(input.min)) input.value = Number(input.min);
setSetting(setting_name, input.value);
}
if (force_reload) {
refreshPage();
}
});
return label;
}
function addMenuLinks() {
let vlada_menu_index = 4;
let play_menu_index = 5;
addButtonIfToggled(ROZVOJ_MENU_LINK, "Rozvoj", "index.php?p=vlada&s=rozvoj", vlada_menu_index, 1);
addButtonIfToggled(GENERALS_MENU_LINK, "Generálové", "index.php?p=valka&s=general", play_menu_index, 6);
addButtonIfToggled(PRODEJ_MENU_LINK, "Prodej", "index.php?p=svetovy_trh&s=trhposlat", play_menu_index, 4);
addButtonIfToggled(POKROKY_MENU_LINK, "Pokroky", "index.php?p=technologie&s=pokroky", play_menu_index, 3);
}
function addButtonIfToggled(value_key, button_text, link, menu_index, submenu_index) {
if (!getSetting(value_key, true)) {
return;
}
let menu = document.getElementById("left_menu");
menu = menu.children[0];
addButton(button_text, link, menu, menu_index, submenu_index);
}
function addButton(button_text, link, menu, menu_index, submenu_index) {
let relevant_menu = menu.children[menu_index].children[0];
let element = createElement("a", { href: link, textContent: button_text });
let li = createElement("li");
li.append(element);
relevant_menu.insertBefore(li, relevant_menu.children[submenu_index]);
}
// DETAILY ALI
function modifyDetailyAli() {
let table = document.getElementsByClassName("vis_tbl");
if (table == null) {
return;
}
table = table[0];
let exp_object = calculateExp(table);
let container_element = document.getElementsByClassName("container");
let content_element = container_element[0].children[0];
let div = createElement("div", {
style: "width: 250px; background: #222222; border: 2px solid; border-bottom-color: #000; border-right-color: #000; border-left-color: #555; border-top-color: #555; padding: 3px; margin-left: calc(50% - 125px); text-align: center;",
});
let p = createElement("p", { textContent: "Aktualní ali hodnost: " + exp_object.current_ali_level });
div.append(p);
p = createElement("p", { textContent: "Celkový počet zkušeností ali: " + exp_object.total_exp + "k" });
div.append(p);
p = createElement("p", { textContent: "Chybějící počet zkušeností ali: " + exp_object.missing_exp + "k" });
div.append(p);
content_element.insertBefore(div, content_element.children[1]);
}
function calculateExp(table) {
const EXPERIENCE_PER_LEVEL = [10000, 20000, 40000, 80000, 150000, 250000, 400000, 600000, 850000, 1150000, 1500000, 1950000, 2450000];
let rows = table.getElementsByTagName("tr");
let exp_total_row = rows[17];
let exp_total_columns = exp_total_row.getElementsByTagName("td");
let total_exp = 0;
let row_count = exp_total_columns.length;
let member_count = row_count - 1;
for (let i = 1; i < row_count; i++) {
total_exp = total_exp + parseInt(exp_total_columns[i].innerHTML) * 1000;
}
for (let i = 0; i < EXPERIENCE_PER_LEVEL.length; i++) {
if (EXPERIENCE_PER_LEVEL[i] * member_count < total_exp) {
continue;
}
let missing_exp = EXPERIENCE_PER_LEVEL[i] * member_count - total_exp;
let exp_object = {
missing_exp: missing_exp / 1000,
total_exp: total_exp / 1000,
current_ali_level: i + 1,
};
return exp_object;
}
}
// DETAILY ALI KONEC
// HOSPO, MAX PRESTIZ PRESTIZ
function modifyHospoPage() {
const table = document.forms[0].children[0];
if (table == null) return false;
const row = table.insertRow(table.rows.length - 1);
row.insertCell().textContent = "Prestiž";
let total_prestige = 0;
let prestige_per_unit = [0, 0, 0, 0.002, 0.02, 0.02, 1, 5, 3.5, 3.5, 2.7];
for (let i = 3; i < table.rows.length - 2; i++) {
const cell = table.rows[i].cells[1];
total_prestige += parseFloat(Number(cell.textContent) * prestige_per_unit[i]);
const input = table.rows[i].cells[2].children[0];
input.dataset.prestige = prestige_per_unit[i];
input.addEventListener("keyup", processHospaPrestige);
}
row.insertCell().textContent = parseInt(total_prestige * 10) / 10;
const cell = row.insertCell();
cell.textContent = 0;
cell.id = "sent_prestige";
}
function processHospaPrestige() {
const result_cell = document.getElementById("sent_prestige");
let total_prestige = 0;
const table = document.forms[0].children[0];
for (let i = 3; i < table.rows.length - 2; i++) {
const max_value = Number(table.rows[i].cells[1].textContent);
const cell = table.rows[i].cells[2];
const input = cell.children[0];
let value = input.value;
if (value <= 0) {
continue;
}
value = value > max_value ? max_value : value;
const prestige_per_unit = parseFloat(input.dataset.prestige);
total_prestige += value * prestige_per_unit;
}
result_cell.textContent = total_prestige.toFixed(1);
}
// HOSPO KONEC
// PRAVIDLA VALEK
function modifyPravidlaValky() {
const table = document.forms[0].elements[1].closest("table");
if (table == null) {
return;
}
let button;
let elements = getElementsInTheWarForm(1);
button = createButton("Reset", resetWar, elements);
table.parentElement.insertBefore(button, table.nextSibling);
button = createButton("Přepnout", toggleUtoky, elements);
addDoubleClickProtection(button);
table.parentElement.insertBefore(button, table.nextSibling);
button = createButton("Farmy (10)", warFarmyUtoky, elements);
table.parentElement.insertBefore(button, table.nextSibling);
button = createButton("Farmy", setWarAgainstFarms, elements);
table.parentElement.insertBefore(button, table.nextSibling);
button = createButton("Klasika", setWarClassic, elements);
table.parentElement.insertBefore(button, table.nextSibling);
}
function toggleUtoky(elements) {
for (let i = 0; i < elements.length; i++) {
elements[i].value = 1 - elements[i].value;
elements[i].checked = !elements[i].checked;
}
}
function setUtoky(elements, values) {
for (let i = 0; i < elements.length; i++) {
elements[i].value = values[i] == true ? 1 : 0;
elements[i].checked = values[i];
}
}
function setTextInputy(elements, values) {
for (let i = 0; i < elements.length; i++) {
elements[i].value = values[i];
}
}
function warFarmyUtoky(elements) {
setWarAgainstFarms(elements);
let text_input_elements = getElementsInTheWarForm(1, "text");
setTextInputy(text_input_elements, [0, 0, 10]);
}
function setWarAgainstFarms(elements) {
let values = [
false,
false,
true, // normaly jen lupy
true,
true,
true,
false,
true,
true, // taktika mimo bombeni
true,
false,
false,
false,
true,
false,
true,
true,
false,
false,
false, // sabotaz jen epky, bourani, demoralizace, sabotaz
true,
true,
true,
true,
true, // kradez rozvedkou = ok
true,
false,
false,
false, // jen konve
];
setUtoky(elements, values);
}
function setWarClassic(elements) {
let values = [
true,
false,
true, // normaly jen lupy
true,
true,
true,
false,
true,
true, // taktika mimo bombeni
true,
false,
false,
false,
true,
false,
true,
true,
false,
false,
false, // sabotaz jen epky, bourani, demoralizace, sabotaz
true,
true,
true,
true,
true, // kradez rozvedkou = ok
true,
false,
false,
false, // jen konve
];
setUtoky(elements, values);
}
function resetWar(elements) {
for (let i = 0; i < elements.length; i++) {
elements[i].value = 1;
elements[i].checked = true;
}
}
function getElementsInTheWarForm(nth, type = "checkbox") {
return document.querySelectorAll("form>div:nth-of-type(" + nth + ") input[type=" + type + "]");
}
// PRAVIDLA VALEK KONEC
// ROZVEDKA
function repeatAction(difficulties) {
const repeat_action = getSetting(REPEAT_ROZVEDKA, 0);
if (repeat_action == 0) {
// log("opky se uz nemaji opakovat => konec");
return;
}
// ziskat obtiznost z opky
let content = document.getElementById("icontent");
if (content == null) return;
let message_start = content.innerHTML.indexOf("<br><br><br>");
if (message_start == -1) return;
let message = content.innerHTML.slice(message_start + 12);
message = message.slice(0, message.indexOf("<"));
if (message.indexOf("infiltrovali") != -1) {
// log("infiltrace úspěšná => konec.");
setSetting(REPEAT_ROZVEDKA, 0);
return;
}
let difficulty_text = content.querySelector("b");
if (difficulty_text == null) {
// log("tucny text nenalezen => konec");
setSetting(REPEAT_ROZVEDKA, 0);
return;
}
difficulty_text = difficulty_text.innerText;
let obtiznost = difficulties.indexOf(difficulty_text);
if (obtiznost == -1) {
// log("Obtížnost [" + difficulty_text + "] nebyla nalezena => konec");
setSetting(REPEAT_ROZVEDKA, 0);
return;
}
const max_operation_difficulty = getSetting(MAX_OBTIZNOST_OPERACE, 0);
if (obtiznost > max_operation_difficulty) {
// log("Obtížnost je moc vysoka => konec");
setSetting(REPEAT_ROZVEDKA, 0);
return;
}
setSetting(REPEAT_ROZVEDKA, repeat_action - 1);
// log("reload page");
location.reload();
}
let technology_prices = (function () {
let prices = null;
function fetchTechnologyPrices() {
return new Promise((resolve) => {
let req = new XMLHttpRequest();
let url = "index.php?p=svetovy_trh&s=techkoupit";
req.open("GET", url);
req.onload = function () {
if (req.readyState == 4 && req.status == 200) {
let parser = new DOMParser();
let doc = parser.parseFromString(req.response, "text/html");
let warning_elements = doc.getElementsByClassName("warn");
if (warning_elements.length > 0 || !doc.forms[0]) {
// reject("Není přístup na světový trh");
return;
}
let technologie_prices = [];
let price_cells = doc.forms[0].children[0].querySelectorAll(".mactprice");
price_cells.forEach((price_cell) => {
const value = Number(price_cell.innerHTML.split("<")[0].replace(/\s/g, ""));
technologie_prices.push(value);
});
resolve(technologie_prices);
} else {
// reject("Soubor nenalezen");
}
};
req.send();
});
}
return {
async get() {
if (prices) return prices;
let technology_prices_data = getSetting(TECHNOLOGY_PRICES, null);
let time_in_millis = getCurrentTimeInMillis();
const hour_in_millis = 60 * 60 * 1000;
if (!technology_prices_data || technology_prices_data.updated_at == undefined || technology_prices_data.updated_at + hour_in_millis < time_in_millis) {
let technology_prices = await fetchTechnologyPrices();
technology_prices_data.prices = technology_prices;
setSetting(TECHNOLOGY_PRICES, {
updated_at: time_in_millis,
prices: technology_prices,
});
}
prices = technology_prices_data.prices;
return prices;
},
};
})();
async function modifyRozvedka() {
const DATA_SEPARATOR = "\n";
handleMainSpyPage();
if (getSetting(INF_MODIFY_INFILTRATION, true)) {
processInfiltrationPage();
}
function handleMainSpyPage() {
if (document.forms.tajsluzba === undefined) return;
const header_elements = document.getElementsByTagName("h1");
if (header_elements.length == 0 || header_elements[0].innerText != "Rozvědka") {
return;
}
const submit_elements = document.getElementsByClassName("submit");
const list_elements = document.getElementsByClassName("tbl_sim");
if (submit_elements.length == 0 || list_elements.length == 0) {
return;
}
const submit_element = submit_elements[0];
const list_element = list_elements[0];
if (getSetting(SPY_SHOW_REPEAT_ACTIONS)) {
addRepeatAction(submit_element, list_element);
}
if (getSetting(SPY_SHOW_STATS, true)) {
addSpyStats(list_element);
}
}
function addRepeatAction(submit_element, list_element) {
const difficulties = ["snadná jak facka", "jednoduchá", "středně náročná", "velice náročná", "extrémně náročná", "téměř neproveditelná"];
repeatAction(difficulties);
const max_operation_element = document.querySelector("#icontent > p > strong"),
inputs = [];
let max_operation_count = parseInt(max_operation_element.innerText);
if (isNaN(max_operation_count) == true) {
max_operation_count = 15;
}
let li_index = 2,
li,
input;
// kolikrat opakovat opku
li = createElement("li", { textContent: "Opakovat operaci: " });
input = createNumberInput("repeat_operation", 5, 1, max_operation_count);
li.append(input);
inputs[0] = input;
list_element.insertBefore(li, list_element.children[li_index++]);
//
// do jake obtiznosti
li = createElement("li", { textContent: "Maximální obtížnost operace: " });
input = createElement("select");
li.append(input);
for (let i = 0; i < difficulties.length; i++) {
input.append(createElement("option", { value: i, textContent: difficulties[i] }));
}
input.options[2].selected = true;
inputs[1] = input;
list_element.insertBefore(li, list_element.children[li_index++]);
//
// brute force button
const button = createButton("Opakuj operaci");
button.params = inputs;
button.addEventListener("click", (e) => {
setSetting(REPEAT_ROZVEDKA, e.currentTarget.params[0].value - 1);
setSetting(MAX_OBTIZNOST_OPERACE, e.currentTarget.params[1].selectedIndex);
const submit_elements = document.getElementsByClassName("submit");
const list_elements = document.getElementsByClassName("tbl_sim");
if (submit_elements.length == 0 || list_elements.length == 0) {
return true;
}
const submit_element = submit_elements[0];
submit_element.click();
});
submit_element.parentElement.append(button);
}
function addSpyStats(list_element) {
const stat_elements = wrapCountrySpyStatsAroundElement(list_element);
list_element.style.height = "fit-content";
list_element.style.marginBottom = "0";
list_element.style.marginTop = "auto";
stat_elements[0].style.marginTop = "14px";
}
function processInfiltrationPage() {
if (location.href.indexOf("s=viewspye") === -1) {
return;
}
const table_summary = document.getElementById("spy-message-summary");
const info_type = getInfiltrationType(table_summary);
if (info_type == null) {
return;
}
CssHelper.addSavedCss(CssHelper.styles.infiltration);
const table_detail = document.getElementById("spy-message-detail");
const country = getCountryData(table_detail.rows[1], table_summary);
addColumnInformation(table_detail, info_type, country);
if (info_type !== 0) {
return;
}
// vlada
const row = table_detail.rows[1];
const labels_column = row.cells[0];
const values_column = row.cells[1];
addValueToTable(labels_column, values_column);
addValueToTable(labels_column, values_column);
let added_values = addValueToTable(labels_column, values_column, "Armáda");
added_values.label.style = "font-weight: bold";
const army_strength = getArmyStrength(country);
addValueToTable(labels_column, values_column, "U základ", formatNumber(army_strength.attack_sum));
addValueToTable(
labels_column,
values_column,
country.people_defense > 0 ? "O základ (včetně lidí)" : "O základ",
formatNumber((army_strength.defense_sum + country.people_defense).toFixed(0))
);
if (country.people_defense > 0) addValueToTable(labels_column, values_column, "Minimum za obyvatele", formatNumber(country.people_defense.toFixed(0)));
}
function formatPercentage(percentage) {
return formatNumber(percentage.toFixed(1)) + "%";
}
function getInfiltrationType(table_summary) {
const text = table_summary.querySelector(".r").textContent;
if (text.indexOf("infiltrovat vládu") !== -1) {
return 0;
}
if (text.indexOf("infiltrovat generální štáb") !== -1) {
return 1;
}
return null;
}
function getPrestige(table_summary) {
const matches = table_summary.rows[0].cells[1].innerText.match(/(?<!#)(\d){5,}/g);
if (matches.length === 0) return null;
return Number(matches[0]);
}
function addColumnInformation(table, info_type, country) {
const header_row = table.rows[0],
data_row = table.rows[1];
header_row.appendChild(createElement("th", { textContent: "Přehled", colSpan: 2 }));
let added_column = {
labels: createElement("td", { className: "rname l" }),
values: createElement("td", { className: "rdata r" }),
};
data_row.appendChild(added_column.labels);
data_row.appendChild(added_column.values);
// ARMADA ZACATEK
let army_prestige = 0;
for (const key in country.units) {
army_prestige += country.units[key].total_prestige;
}
addValueToTable(added_column.labels, added_column.values, "Armáda prestiž", formatNumber(Math.round(army_prestige)));
addValueToTable(added_column.labels, added_column.values, "Podíl prestiže", formatPercentage((army_prestige / country.prestige) * 100), true);
// ARMADA KONEC
// MECHY % ZACATEK
const mech_percent = (country.units.mechy.total_prestige / army_prestige) * 100;
addValueToTable(added_column.labels, added_column.values, "Mechy %", formatPercentage(mech_percent), true);
// MECHY % KONEC
if (info_type == 0) {
let elements;
const land_prestige = getLandPrestige(country);
addValueToTable(added_column.labels, added_column.values, "Území", formatNumber(land_prestige));
let percent = (land_prestige / country.prestige) * 100;
elements = addValueToTable(added_column.labels, added_column.values, "Procent", formatPercentage(percent), true);
if (percent > getSetting(INF_LAND_PERCENTAGE_HIGHLIGHT, 20)) elements.value.style.color = "lime";
const techy_data = processTechy(data_row, country.prestige);
addValueToTable(added_column.labels, added_column.values, "Technologie", formatNumber(techy_data.count));
percent = (techy_data.count / country.prestige) * 100;
elements = addValueToTable(added_column.labels, added_column.values, "Procent", formatPercentage(percent), true);
if (percent > getSetting(INF_TECH_PERCENTAGE_HIGHLIGHT, 30)) elements.value.style.color = "lime";
// MRTVA PRESTIZ ZACATEK
const mrtva_prestiz = country.prestige - army_prestige - land_prestige - techy_data.count;
addValueToTable(added_column.labels, added_column.values, "Mrtvá prestiž", formatNumber(Math.round(mrtva_prestiz)));
percent = (mrtva_prestiz / country.prestige) * 100;
elements = addValueToTable(added_column.labels, added_column.values, "Procent", formatPercentage(percent), true);
if (percent > getSetting(INF_MRTVA_PRES_PERCENTAGE_HIGHLIGHT, 10)) elements.value.style.color = "lime";
const rozvedka_prestiz = ((country.land + 2000) / 4) * 15;
addValueToTable(added_column.labels, added_column.values, "Na R kartičku", formatNumber(Math.round(rozvedka_prestiz)), true);
// MRTVA PRESTIZ KONEC
// KRADEZ TECHU ZACATEK
CssHelper.addTooltipCss(200);
elements = addValueToTable(added_column.labels, added_column.values, "Techy krádež", formatNumber(techy_data.steal_per_op), true);
if (Number(techy_data.steal_per_op) > getSetting(INF_STEAL_TECH_COUNT_HIGHLIGHT, 1000)) elements.value.style.color = "lime";
const tooltip = createElement();
elements.value.appendChild(tooltip);
wrapInTooltip(tooltip);
createStolenTechnologiesInformation(tooltip, techy_data.technologies_stolen_per_type);
// KRADEZ TECHU KONEC
}
}
function createStolenTechnologiesInformation(tooltip, technologies_stolen_per_type) {
const sorted_keys = Object.keys(technologies_stolen_per_type).sort(function (a, b) {
return technologies_stolen_per_type[b] - technologies_stolen_per_type[a];
});
for (let index = 0; index < sorted_keys.length; index++) {
const key = sorted_keys[index];
const p = createElement("p", { className: "row" });
tooltip.appendChild(p);
p.appendChild(createElement("span", { textContent: key }));
p.appendChild(createElement("span", { textContent: technologies_stolen_per_type[key] }));
tooltip.appendChild(p);
}
}
function getLandPrestige(country) {
const land_prestige = country.land * 15;
const buildings_prestige = (country.land - country.buildings.empty - country.buildings.ruins) * 5;
const ruins_prestige = country.buildings.ruins * 2;
return land_prestige + buildings_prestige + ruins_prestige;
}
function processTechy(data_row) {
const technology_name_data = data_row.cells[4].innerText.split(DATA_SEPARATOR);
const technology_count_data = data_row.cells[5].innerText.split(DATA_SEPARATOR);
const secure_technology_count = 2 * parseInt(technology_count_data[10]);
const technology = {
count: 0,
steal_per_op: 0,
technologies_stolen_per_type: {},
};
for (let i = 0; i < technology_count_data.length; i++) {
const count = parseInt(technology_count_data[i]);
technology.count += count;
let per_op;
if (count > secure_technology_count) {
per_op = (count - secure_technology_count) * 0.05 + secure_technology_count * 0.002;
} else {
per_op = count * 0.002;
}
if (per_op !== 0) {
technology.steal_per_op += per_op;
technology.technologies_stolen_per_type[technology_name_data[i]] = per_op.toFixed(0);
}
}
technology.steal_per_op = technology.steal_per_op.toFixed(0);
return technology;
}
function getCountryData(data_row, table_summary) {
const unit_column = data_row.children[1].innerText.split(DATA_SEPARATOR);
const country = { units: {}, buildings: {} };
const unit_names = ["vojaci", "tanky", "stihacky", "bunkry", "mechy"];
for (let i = 0; i < unit_names.length; i++) {
const unit_name = unit_names[i];
const count = parseInt(unit_column[i]);
country.units[unit_name] = UNITS.get(unit_name, count);
}
const buildings_data = data_row.children[3].innerText.split(DATA_SEPARATOR);
country.prestige = getPrestige(table_summary);
country.regime = unit_column[8];
country.land = parseInt(unit_column[9]);
country.buildings.villages = Number(buildings_data[0]);
country.buildings.cities = Number(buildings_data[1]);
country.buildings.empty = Number(buildings_data[buildings_data.length - 2]);
country.buildings.ruins = Number(buildings_data[buildings_data.length - 1]);
country.people_defense = country.regime === "Anarchie" ? (country.buildings.cities * 2 + country.buildings.villages + country.land) * 3.5 : 0;
return country;
}
function getArmyStrength({ units }) {
let attack_sum = 0,
defense_sum = 0;
for (const unit_name in units) {
attack_sum += units[unit_name].count * units[unit_name].attack;
defense_sum += units[unit_name].count * units[unit_name].defense;
}
// ARMADA KONEC
return {
attack_sum,
defense_sum,
};
}
}
function addValueToTable(labels_column, values_column, label = null, value = null, space_after = false) {
const result = { after: {} };
let element = addText(label);
labels_column.appendChild(element);
result.label = element;
element = addText(value);
values_column.appendChild(element);
result.value = element;
if (space_after) {
element = createElement("br");
labels_column.appendChild(element);
result.after.label = element;
element = createElement("br");
values_column.appendChild(element);
result.after.value = element;
}
return result;
function addText(text = null) {
if (text === null) {
return createElement("br");
}
return createElement("p", { textContent: text });
}
}
function wrapCountrySpyStatsAroundElement(element, country_id = getCountryId()) {
const country_stats = getCountryStats(country_id);
if (country_stats === undefined) return;
const country_stats_table = createCountryStatsSpySuccessTable(country_stats);
const operations_stats_table = createCountryStatsSpyOperationsTable(country_stats);
const stolen_stats_table = createCountryStatsStolenStatsTable(country_stats);
const combined_spy_stats_difficulty = getAllSpyStats();
const combined_country_stats_table = createCombinedSpySuccessTable(combined_spy_stats_difficulty);
const tables = [country_stats_table, combined_country_stats_table, operations_stats_table, stolen_stats_table];
for (let index = 0; index < tables.length; index++) {
const table = tables[index];
if (table === undefined) continue;
table.style.margin = "unset";
table.style.height = "fit-content";
}
function toggleCurrentChild(parent) {
const children = Array.from(parent.children);
children[0].style.display = "initial";
for (let i = 1; i < children.length; i++) {
const child = children[i];
child.style.display = "none";
}
let index = 0;
parent.addEventListener("click", () => {
index = index + 1;
if (index >= children.length) index = 0;
for (let i = 0; i < children.length; i++) {
const child = children[i];
child.style.display = index === i ? "initial" : "none";
}
});
}
const container = createElement("div", { style: "position: relative" });
element.parentElement.insertBefore(container, element);
const wrapper = createElement("div", { style: "display: grid; grid-template-columns: 2fr 3fr 2fr; gap: 0.5rem; margin: 5px auto;" });
container.appendChild(wrapper);
const left_wrapper = createElement("div", { style: "margin-left: auto; height: fit-content;" });
wrapper.appendChild(left_wrapper);
const operations_stats_table_wrapper = createElement();
left_wrapper.appendChild(operations_stats_table_wrapper);
operations_stats_table_wrapper.appendChild(createElement("h2", { textContent: "Úspěsnost operací země 🔄", style: "padding-bottom: 0.25rem;" }));
operations_stats_table_wrapper.appendChild(operations_stats_table);
const stolen_stats_table_wrapper = createElement("div", { style: "display: none;" });
left_wrapper.appendChild(stolen_stats_table_wrapper);
stolen_stats_table_wrapper.appendChild(createElement("h2", { textContent: "Statistiky krádeží země 🔄", style: "padding-bottom: 0.25rem;" }));
stolen_stats_table_wrapper.appendChild(stolen_stats_table);
toggleCurrentChild(left_wrapper);
element.style.margin = "unset";
wrapper.appendChild(element);
const right_wrapper = createElement("div", { style: "margin-right: auto; height: fit-content;" });
wrapper.appendChild(right_wrapper);
const country_stats_table_wrapper = createElement();
right_wrapper.appendChild(country_stats_table_wrapper);
country_stats_table_wrapper.appendChild(createElement("h2", { textContent: "Statistiky země 🔄", style: "padding-bottom: 0.25rem" }));
country_stats_table_wrapper.appendChild(country_stats_table);
const combined_country_stats_table_wrapper = createElement("div", { style: "display: none;" });
right_wrapper.appendChild(combined_country_stats_table_wrapper);
combined_country_stats_table_wrapper.appendChild(createElement("h2", { textContent: "Kombinované statistiky všech zemí 🔄", style: "padding-bottom: 0.25rem;" }));
combined_country_stats_table_wrapper.appendChild(combined_country_stats_table);
toggleCurrentChild(right_wrapper);
return [operations_stats_table, country_stats_table_wrapper, combined_country_stats_table_wrapper];
}
function getCountryId() {
let country_id = document.querySelector("#uLista a").href.split("id=")[1];
if (country_id == undefined) {
//obyc lista, mozna nefunguje?
const lista = document.getElementById("#uLista");
country_id = lista.children[0].textContent.split("#")[1];
}
return country_id;
}
function createNumberInput(id, default_value = 5, min = 1, max = 15, class_text = "short") {
if (default_value > max) {
default_value = max;
}
let input = createElement("input", { className: class_text, type: "number", value: default_value, min, max, id });
return input;
}
// ROZVEDKA KONEC
// valky
function modifyValky() {
const flipped = getSetting(VALKY_OBRACENE, 0);
const textContent = flipped == 1 ? "Přehodit počítání prestiže na: cílová / vyhlašující ali" : "Přehodit počítání prestiže na: vyhlašující ali / cílová";
let func = () => {
setSetting(VALKY_OBRACENE, 1 - getSetting(VALKY_OBRACENE, 0));
location.reload();
};
let button = createButton(textContent, func);
let div = createElement("div", { style: "margin: 0 auto; width: fit-content;" });
div.append(button);
let header = document.getElementsByTagName("h1")[0];
header.parentElement.insertBefore(div, header.nextElementSibling);
let tables = document.querySelectorAll(".container .vis_tbl");
// ziskat nazev ali ve valce
let offset = isGameOver() ? 1 : 0;
for (let i = 1 + offset; i < tables.length; i++) {
const table = tables[i];
for (let column_index = 4; column_index < 6; column_index++) {
const vyhlasujici_ali_prestiz = parseInt(table.rows[column_index].children[1].innerText);
const cilova_ali_prestiz = parseInt(table.rows[column_index].children[2].innerText);
let procentualni_sila_ali = flipped == 0 ? cilova_ali_prestiz / vyhlasujici_ali_prestiz : vyhlasujici_ali_prestiz / cilova_ali_prestiz;
procentualni_sila_ali = Math.round(procentualni_sila_ali * 10000) / 100;
let color = "palegreen";
if ((procentualni_sila_ali > 120 && flipped == 0) || (procentualni_sila_ali < 80 && flipped == 1)) {
color = "chartreuse";
} else if ((procentualni_sila_ali < 80 && flipped == 0) || (procentualni_sila_ali > 120 && flipped == 1)) {
color = "coral";
}
table.rows[column_index].children[0].append(createElement("span", { textContent: "(" + procentualni_sila_ali + "%)", style: "margin-left: 5px; color: " + color }));
}
}
}
// valky konec
// lista
function saveResourcePrices() {
if ((location.href.indexOf("svetovy_trh") != -1 && location.href.indexOf("tech") === -1) || location.href.indexOf("domtrh") != -1) {
getPricesFromMarket();
} else if (location.href.indexOf("index.php?p=archiv") === -1) {
let info_messages = document.getElementsByClassName("infomsg");
if (info_messages.length === 0) {
return;
}
let count = info_messages.length - 1,
food_set = false,
energy_set = false,
max_tries = 3;
while (--count >= 0 && max_tries-- > 0) {
let info_message = info_messages[count];
if (info_message.textContent.indexOf("nakoupili") === -1) {
continue;
}
const price = Number(info_message.textContent.split("po ")[1].split("$")[0]);
let variable;
if (info_message.textContent.indexOf("jídla") != -1) {
if (food_set) continue;
variable = FOOD_PRICE;
food_set = true;
} else if (info_message.textContent.indexOf("energie") != -1) {
if (energy_set) continue;
variable = ENERGY_PRICE;
energy_set = true;
}
if (variable !== undefined) {
setSetting(variable, price);
}
if (food_set && energy_set) {
return;
}
}
}
}
function getPricesFromMarket() {
const column_names = ["cena/kus", "tržní cena"];
let tables = document.getElementsByClassName("vis_tbl");
if (tables.length === 0) {
return;
}
let column_price = 0,
table;
main_loop: for (let i = 0; i < tables.length; i++) {
table = tables[i];
for (let j = 0; j < table.rows[0].cells.length; j++) {
const cell = table.rows[0].cells[j];
if (column_names.includes(cell.textContent.toLowerCase())) {
column_price = j;
break main_loop;
}
}
}
if (column_price === 0) {
return;
}
let cell = table.rows[1].cells[column_price];
let price = cell.innerText.split("\n")[0].replace("$", "");
if (price === "") {
price = cell.children[0].value;
}
setSetting(FOOD_PRICE, Number(price));
cell = table.rows[2].cells[column_price];
price = cell.innerText.split("\n")[0].replace("$", "");
if (price === "") {
price = cell.children[0].value;
}
setSetting(ENERGY_PRICE, Number(price));
}
function modifyLista() {
if (isGameOver()) {
return;
}
saveResourcePrices();
let lista = document.getElementById("uLista");
if (lista == null) {
// lista neni z nejakeho duvodu vubec na strance => skip
return;
}
if (lista.rows[0].cells[0].children[0].tagName == "IMG") {
processGoldLista();
addListaObserver();
return;
}
let tables = document.getElementsByTagName("table");
const dividers = ["$", "t", "MWh"];
// chceme vsechny tabulky, protoze na strance se muze 2x vyskytovat #uLista - stara + nova po odehrani kol
for (let i = 0; i < tables.length; i++) {
const table = tables[i];
if (table.id != "uLista") {
// neni uLista => skip
continue;
}
const row = table.rows[0];
for (let j = 1; j < 4; j++) {
const cell = row.cells[j];
processListaCell(cell, dividers[j - 1]);
}
}
}
function addListaObserver() {
let lista_elements = document.querySelectorAll("#uLista");
const lista_element = lista_elements[lista_elements.length - 1];
addObserver(lista_element, processGoldLista);
}
function addObserver(
element,
callback,
options = {
childList: true,
subtree: false,
}
) {
let observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.type == "childList" && mutation.addedNodes.length > 0) {
callback();
}
});
});
observer.observe(element, options);
}
function processGoldLista() {
let lista_elements = document.querySelectorAll("table#uLista");
for (let index = 0; index < lista_elements.length; index++) {
const lista = lista_elements[index];
updateGoldLista(lista);
}
}
function updateGoldLista(lista) {
let tables = lista.querySelectorAll("table");
let table = tables[0];
if (!table) {
return;
}
const turns_element = lista.querySelector("strong");
let playable_turns = 140;
if (turns_element) {
playable_turns = Number(turns_element.textContent.split("+")[0]);
}
const energy_price = getSetting(ENERGY_PRICE, 15);
const food_price = getSetting(FOOD_PRICE, 15);
const prices = [1, food_price, energy_price];
const resource_names = ["money", "food", "energy"];
const resources = new Map();
resource_names.forEach((resource_name, index) => {
let resource = {
value: Number(table.rows[index].cells[1].textContent.replace(/\s/g, "")),
per_turn: Number(table.rows[index].cells[2].textContent.replace(/\s/g, "")),
};
let stockpiled = 140;
if (resource.per_turn < 0) {
stockpiled = Math.floor(resource.value / -resource.per_turn);
}
if (stockpiled > 140 || stockpiled < 0) {
stockpiled = 140;
}
resource.stockpiles_for = stockpiled;
resource.spotreba = -resource.per_turn * prices[index];
resources.set(resource_name, resource);
});
let cell;
let resources_for_turns = getMoneyFor(resources.get("money"), resources.get("food"), resources.get("energy"));
cell = table.rows[0].cells[3];
if (cell === undefined) {
cell = table.rows[0].insertCell();
cell.style.textAlign = "right";
cell.style.paddingLeft = "20px";
} else {
for (let index = cell.children.length - 1; index >= 0; index--) {
const element = cell.children[index];
element.remove();
}
}
let props = { textContent: resources_for_turns[0], className: "plus" };
if (Number(resources_for_turns[0].split(" kol")[0]) < playable_turns) {
props.className = "minus";
}
let money_for_turns = createElement("span", props);
cell.appendChild(money_for_turns);
let separator = createElement("span", { textContent: " | " });
cell.appendChild(separator);
props = { textContent: resources_for_turns[1], className: "minus", style: "padding-right: 0;" };
if (Number(resources_for_turns[1].replaceAll(String.fromCharCode(160), "").slice(0, -1)) > 0) {
props.className = "plus";
}
let money_change_per_turn = createElement("span", props);
cell.appendChild(money_change_per_turn);
resource_names.forEach((resource_name, index) => {
if (index === 0) return;
const resource = resources.get(resource_name);
if (resource.per_turn < 0) {
const stockpiles_for = Math.round(resource.stockpiles_for * 10) / 10;
const stockpiles_text = stockpiles_for == 0 ? "" : stockpiles_for + " kol | ";
cell = table.rows[index].cells[3];
if (cell === undefined) {
cell = table.rows[index].insertCell();
cell.style.textAlign = "right";
cell.style.paddingLeft = "20px";
cell.classList.add("minus");
}
cell.textContent = `${stockpiles_text} ${formatNumber(-resource.spotreba)}$`;
}
});
}
function getMoneyFor(money, food, energy) {
let current_money = money.value,
current_spotreba = money.spotreba,
total_spotreba = current_spotreba + (energy.spotreba < 0 ? 0 : energy.spotreba) + (food.spotreba < 0 ? 0 : food.spotreba),
money_for = 0,
money_for_offset = 0;
if (total_spotreba < 0) {
return ["140+ kol", formatNumber(-total_spotreba) + "$"];
}
if (food.stockpiles_for !== energy.stockpiles_for && food.stockpiles_for !== 0) {
let is_more_of_food = food.stockpiles_for > energy.stockpiles_for;
let more_res = is_more_of_food ? food : energy;
let less_res = is_more_of_food ? energy : food;
if (less_res.stockpiles_for !== 0) {
money_for = current_money / current_spotreba;
if (money_for >= 0 && money_for < less_res.stockpiles_for) {
return [Math.floor(money_for) + " kol", formatNumber(-total_spotreba) + "$"];
}
money_for_offset = Math.min(money_for, less_res.stockpiles_for);
current_money -= current_spotreba * less_res.stockpiles_for;
}
current_spotreba += less_res.spotreba;
money_for = money_for_offset + current_money / current_spotreba;
if (money_for >= 0 && money_for < more_res.stockpiles_for) {
return [Math.floor(money_for) + " kol", formatNumber(-total_spotreba) + "$"];
}
money_for_offset = Math.min(money_for, more_res.stockpiles_for);
current_money -= current_spotreba * (more_res.stockpiles_for - less_res.stockpiles_for);
}
current_spotreba = money.spotreba + food.spotreba + energy.spotreba;
current_spotreba = money.spotreba + Math.max(food.spotreba, 0) + Math.max(energy.spotreba, 0);
money_for = money_for_offset + current_money / current_spotreba;
if (money_for > 140 || money_for < 0) {
money_for = "140+";
} else {
money_for = Math.floor(money_for);
}
return [money_for + " kol", formatNumber(-total_spotreba) + "$"];
}
function formatNumber(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, String.fromCharCode(160));
}
function processListaCell(cell, divider) {
if (cell == null) return;
let text = cell.innerText;
if (text == "") return;
text = text.replaceAll(" ", "");
const values = text.split(divider);
const production = values[1].split(":")[1];
if (production >= 0) {
return;
}
const at_storage = values[0].split(":")[1];
const turns_left = Math.floor((parseInt(at_storage) / parseInt(production)) * -1);
addListaCellInformation(cell, turns_left);
}
function addListaCellInformation(cell, turns_left) {
let color_class = "plus";
if (turns_left < 20) {
color_class = "minus";
}
const paragraph = createElement("p", { textContent: "Vydrží: ", className: color_class });
const bold = createElement("b", { textContent: turns_left, className: color_class });
bold.innerText = turns_left;
if (color_class != null) {
bold.classList.add(color_class);
}
paragraph.append(bold);
paragraph.append(document.createTextNode("kol"));
cell.append(paragraph);
}
//
// detaily zeme
function createArmyUnit(name, count, base_wage, prestige, base_food_consumption = 0.005, base_energy_consumption = 0) {
const unit = new ArmyUnit(name, count, prestige);
unit.base_wage = base_wage;
unit.base_food_consumption = base_food_consumption;
unit.base_energy_consumption = base_energy_consumption;
return unit;
}
function createCountryStatsSpySuccessTable(country_stats) {
const sorted_stats = country_stats.spy_stats.success_stats.sort((a, b) => a.difficulty_id - b.difficulty_id);
return createCountryStatsSpyTable(sorted_stats, "difficulty_id", SpyDifficulty);
}
function createCombinedSpySuccessTable(complete_stats) {
const sorted_stats = complete_stats.sort((a, b) => a.difficulty_id - b.difficulty_id);
return createCountryStatsSpyTable(sorted_stats, "difficulty_id", SpyDifficulty);
}
function createCountryStatsSpyOperationsTable(country_stats) {
const sorted_stats = country_stats.spy_stats.operation_stats.sort((a, b) => a.operation_id - b.operation_id);
return createCountryStatsSpyTable(
sorted_stats,
"operation_id",
Operation,
[
{ label: "Název operace", key: "operation_id" },
{ label: "Operací", key: "count" },
{ label: "Úspěšných", key: "success" },
{ label: "%", key: "success_percentage" },
],
false
);
}
function createCountryStatsStolenStatsTable(country_stats) {
const stats = country_stats.spy_stats.stolen_stats.reduce((result, stat) => {
const values = {};
values.operation_id = stat.operation_id;
let per_operation = stat.values
.map((value) => value.per_operation)
.flat()
.sort((a, b) => b - a);
values.stolen = per_operation.reduce((sum, value) => sum + value, 0);
values.count = per_operation.length;
values.per_operation = Math.round(values.stolen / values.count);
values.max = per_operation[0];
result.push(values);
return result;
}, []);
const sorted_stats = stats.sort((a, b) => a.operation_id - b.operation_id);
return createCountryStatsSpyTable(
sorted_stats,
"operation_id",
Operation,
[
{ label: "Název operace", key: "operation_id" },
{ label: "Počet operací", key: "count" },
{ label: "Za operaci", key: "per_operation" },
{ label: "Max", key: "max" },
{ label: "Celkem", key: "stolen" },
],
false
);
}
function getAllSpyStats() {
const all_country_stats = getSetting(COUNTRY_STATS, []);
const stats = Object.values(all_country_stats);
const success_stats = stats.map((stat) => stat.spy_stats.success_stats).flat();
const length = getEnumLength(SpyDifficulty);
let total_stats = new Array(length);
for (let index = 0; index < length; index++) {
total_stats[index] = {
difficulty_id: index + 1,
count: 0,
success: 0,
};
}
total_stats = success_stats.reduce(function (result, stats) {
result[stats.difficulty_id - 1].count += stats.count;
result[stats.difficulty_id - 1].success += stats.success;
return result;
}, total_stats);
return total_stats;
}
function createCountryStatsSpyTable(
stats,
key,
myEnum,
values = [
{ label: "Obtížnost", key: "difficulty_id" },
{ label: "Operací", key: "count" },
{ label: "Úspěšných", key: "success" },
{ label: "%", key: "success_percentage" },
],
add_total_row = true
) {
let table = createElement("table", { className: "vis_tbl" });
const header = table.insertRow();
values.forEach((value) => {
const header_cell = createElement("th", { textContent: value.label });
header.appendChild(header_cell);
});
let total_count = 0;
let total_succeeded = 0;
let colors = [
// red to green
"#900", // 0
"#B20", // 1
"#F50", // 2
"#FA0", // 3
"#FD0", // 4
"#DF0", // 5
"#AF0", // 6
"#5F0", // 7
"#2B0", // 8
"#090", // 9
"#090", // 10
];
const length = stats.length;
for (let index = 0; index < length; index++) {
const current_stat = stats[index];
if (current_stat === undefined) return;
total_count += current_stat.count;
total_succeeded += current_stat.success;
const row = table.insertRow();
let cell = row.insertCell();
cell.classList.add("l");
const name = getEnumKeyByEnumValue(myEnum, current_stat[key]);
cell.innerText = name.charAt(0).toUpperCase() + name.slice(1);
for (let i = 1; i < values.length; i++) {
const value = values[i].key;
cell = row.insertCell();
if (value === "success_percentage") {
cell.textContent = ((current_stat.success / current_stat.count) * 100).toFixed(1) + "%";
const color_id = current_stat.count === 0 ? 0 : Math.floor((current_stat.success / current_stat.count) * 10);
cell.style.color = colors[color_id];
continue;
}
const text = Number.isInteger(current_stat[value]) ? formatNumber(current_stat[value]) : current_stat[value];
cell.textContent = text;
}
}
if (add_total_row) {
const row = table.insertRow();
let cell = row.insertCell();
cell.classList.add("l");
cell.innerText = "Celkem";
cell = row.insertCell();
cell.innerText = total_count;
cell = row.insertCell();
cell.innerText = total_succeeded;
let color_id = 0;
if (total_count !== 0) {
color_id = Math.floor((total_succeeded / total_count) * 10);
}
cell = row.insertCell();
cell.style.color = colors[color_id];
cell.innerText = (total_count !== 0 ? Math.round((total_succeeded / total_count) * 10000) / 100 : 0) + "%";
}
return table;
}
async function createWagesTable(eco_detail_table, war_detail_table, prestige, total_wage_reduction, resources_reduction, vlada) {
let is_robokrat = vlada == "Robokracie";
let values = getValuesFromTheCell(eco_detail_table.rows[1].cells[1]);
let people = parseInt(values[2]);
const base_consumption = 0.005 * ((1 * (100 - resources_reduction)) / 100);
let consumption_food = base_consumption,
consumption_energy = 0;
if (is_robokrat) {
consumption_food = 0;
consumption_energy = base_consumption;
}
values = getValuesFromTheCell(war_detail_table.rows[1].cells[5]);
let units = [];
units.push(createArmyUnit("Vojáci", parseInt(values[0]), 0.06, 1, consumption_food, consumption_energy));
units.push(createArmyUnit("Tanky", parseInt(values[1]), 0.42, 5, consumption_food, consumption_energy));
units.push(createArmyUnit("Stíhačky", parseInt(values[2]), 0.32, 3.5, consumption_food, consumption_energy));
units.push(createArmyUnit("Bunkry", parseInt(values[3]), 0.35, 3.5, consumption_food, consumption_energy));
units.push(createArmyUnit("Mechové", parseInt(values[4]), 0.2, 2.7, 0, base_consumption));
units.push(createArmyUnit("Agenti", parseInt(values[5]), 5.0, 15, consumption_food, consumption_energy));
addUnitsBeingSold(units);
let food_price = 10;
let energy_price = 10;
let prices = await fetchMarketPrices();
food_price = prices[0];
energy_price = prices[1];
let wages_total = calculateTotalWages(units, prestige, -total_wage_reduction);
let expenses_total = calculateTotalExpenses(units, food_price, energy_price);
let expenses_container = createExpensesTable(units, expenses_total, wages_total, food_price, energy_price, total_wage_reduction, resources_reduction);
war_detail_table.parentElement.insertBefore(expenses_container, war_detail_table.nextElementSibling);
let result = {
prestige: prestige,
units: units,
people: people,
is_robokrat: is_robokrat,
wages_total: wages_total,
expenses_total: expenses_total,
food_price: food_price,
energy_price: energy_price,
};
return result;
}
function addUnitsBeingSold(units) {
let package_elements = document.querySelectorAll(".gtrans, .gsale");
for (let index = 0; index < package_elements.length; index++) {
let cell = package_elements[index];
let row = cell.parentElement;
const name_to_find = row.cells[2].textContent.slice(0, -1);
const unit = units.find(({ name }) => name === name_to_find);
if (unit !== undefined) {
unit.count += Number(row.cells[3].textContent.replace(/\s/g, ""));
}
}
}
function addSpyRobberyColumn(eco_detail_table, war_detail_table, prestige) {
let values = getValuesFromTheCell(eco_detail_table.rows[1].cells[3]);
const money = parseInt(values[0].slice(0, -1));
const food = parseInt(values[1].slice(0, -1));
const energy = parseInt(values[2].slice(0, -1));
values = getValuesFromTheCell(war_detail_table.rows[1].cells[3]);
const spy_tech_points = parseInt(values[10]);
const safe_technology_points = spy_tech_points * 2;
let technology_to_steal = 0;
values.forEach((value) => {
const technology_points = parseInt(value);
if (technology_points > safe_technology_points) {
technology_to_steal += (technology_points - safe_technology_points) * 0.05 + safe_technology_points * 0.002;
} else {
technology_to_steal += technology_points * 0.002;
}
});
const safe_money = Math.min(spy_tech_points * 1000, money);
const unsafe_money = money - safe_money;
const money_to_steal = Math.round(Math.min(unsafe_money * 0.25 + safe_money * 0.01, prestige));
const safe_food = Math.min(spy_tech_points * 50, food);
const unsafe_food = food - safe_food;
const food_to_steal = Math.round(Math.min(unsafe_food * 0.25 + safe_food * 0.01, prestige / 5));
const safe_energy = Math.min(spy_tech_points * 50, energy);
const unsafe_energy = energy - safe_energy;
const energy_to_steal = Math.round(Math.min(unsafe_energy * 0.25 + safe_energy * 0.01, prestige / 5));
war_detail_table.rows[0].appendChild(createElement("th", { textContent: "Další informace", colSpan: 2 }));
// krádez rozvedkou:
const columns = {
labels: war_detail_table.rows[1].insertCell(),
values: war_detail_table.rows[1].insertCell(),
};
columns.labels.classList.add("rname", "l");
columns.values.classList.add("rdata", "r");
let elements = addValueToTable(columns.labels, columns.values, "Krádež rozvědkou");
elements.label.style.fontWeight = "bold";
addValueToTable(columns.labels, columns.values, "Peníze", formatNumber(money_to_steal));
addValueToTable(columns.labels, columns.values, "Jídlo", formatNumber(food_to_steal));
addValueToTable(columns.labels, columns.values, "Energie", formatNumber(energy_to_steal));
addValueToTable(columns.labels, columns.values, "Technologie", formatNumber(Math.floor(technology_to_steal)), true);
addValueToTable(columns.labels, columns.values, "Mechy %", getMechyPercentageInArmy(war_detail_table));
}
function getMechyPercentageInArmy(war_detail_table) {
const values = getValuesFromTheCell(war_detail_table.rows[1].cells[5]);
let units = [];
units.push(new ArmyUnit("Mechové", parseInt(values[4]), 2.7));
units.push(new ArmyUnit("Vojáci", parseInt(values[0]), 1));
units.push(new ArmyUnit("Tanky", parseInt(values[1]), 5));
units.push(new ArmyUnit("Stíhačky", parseInt(values[2]), 3.5));
units.push(new ArmyUnit("Bunkry", parseInt(values[3]), 3.5));
let prestige_sum = units.reduce((acc, obj) => acc + obj.total_prestige, 0);
if (prestige_sum === 0) {
return "0%";
}
return ((units[0].total_prestige / prestige_sum) * 100).toFixed(1) + "%";
}
function addCountryDetailButtons(show_wages) {
let infotext = document.getElementsByClassName("infotext");
if (infotext.length === 0) {
return;
}
infotext = infotext[0];
const padding = "0.5rem";
const div = createElement("div", { style: "margin-top: 0.6rem;" });
infotext.append(div);
let text = show_wages ? "Vypnout zobrazení výdajů" : "Zapnout zobrazení výdajů";
let func = () => {
setSetting(ZOBRAZENE_ZOLDY, !show_wages);
refreshPage();
};
const show_wages_button = createButton(text, func, null, { style: `padding: ${padding}` });
div.appendChild(show_wages_button);
const is_ally = location.href.endsWith("p=detaily");
const refresh_stats_button = createButton("Aktualizovat statistiky země", null, null, { style: `padding: ${padding}` });
addDoubleClickProtection(refresh_stats_button);
refresh_stats_button.addEventListener("click", async function () {
await archive_spy.processSpyArchive(countryDetailGetCountryId(), !is_ally, false, true, refresh_stats_button);
});
div.appendChild(refresh_stats_button);
const fetch_all_stats_button = createButton("Získat kompletní statistiky země", null, null, { style: `padding: ${padding}` });
addDoubleClickProtection(fetch_all_stats_button);
fetch_all_stats_button.addEventListener("click", async function () {
await archive_spy.processSpyArchive(countryDetailGetCountryId(), !is_ally, true, true, fetch_all_stats_button);
});
div.appendChild(fetch_all_stats_button);
const fetch_all_stats_for_ali_button = createButton("Získat statistiky všech zemí v alianci", null, null, { style: `padding: ${padding}` });
addDoubleClickProtection(fetch_all_stats_for_ali_button);
fetch_all_stats_for_ali_button.addEventListener("click", async function () {
await processSpyArchiveForAlliance(fetch_all_stats_for_ali_button);
});
div.appendChild(fetch_all_stats_for_ali_button);
const reset_button = createButton("Vynulovat statistiky všech zemí", null, null, { style: `padding: ${padding}` });
addDoubleClickProtection(fetch_all_stats_for_ali_button);
reset_button.addEventListener("click", async function () {
resetStats();
});
div.appendChild(reset_button);
}
async function processCountryDetail() {
if (document.querySelector("h1").textContent !== "Detaily členů aliance") {
return;
}
const show_wages = getSetting(ZOBRAZENE_ZOLDY, true);
const country_id = countryDetailGetCountryId();
const country_stats = getCountryStats(country_id);
addCountryDetailButtons(show_wages);
let eco_detail_table = document.getElementById("tdetail");
let war_detail_table = document.getElementById("detaily");
if (!war_detail_table || !eco_detail_table) {
return;
}
let values = getValuesFromTheCell(eco_detail_table.rows[1].cells[1]);
let prestige = parseInt(values[0]);
addSpyRobberyColumn(eco_detail_table, war_detail_table, prestige);
if (country_stats !== undefined) {
wrapCountrySpyStatsAroundElement(eco_detail_table, country_id);
}
if (!show_wages) {
return;
}
let vlada = null,
hodnost = null,
ekonom = 0,
ali_bonus = 0,
ali_tag = null;
// ziskat hodnost
let hodnost_elements = document.getElementsByClassName("hodnost");
if (hodnost_elements.length === 0) {
return;
}
hodnost = Number(hodnost_elements[0].textContent.split("(")[1].split(")")[0]);
let table = hodnost_elements[0].closest("table");
// ziskat zrizeni
vlada = table.rows[0].cells[3].textContent;
// ziskat ali tag
let country_full_name = table.rows[0].cells[1].textContent;
if (country_full_name.includes("[")) {
ali_tag = country_full_name.split("[")[1].split("]")[0];
}
let generals_table = document.getElementById("dgen");
if (generals_table) {
for (let index = 1; index < generals_table.rows.length; index++) {
const row = generals_table.rows[index];
let cell = row.cells[1];
if (cell.textContent.includes("Ekonom")) {
ekonom = Number(row.cells[2].textContent);
break;
}
}
}
if (ali_tag !== null && ali_tag !== "Bezalianční") {
let saved_ali_data = getSetting(COUNTRY_ALI_DATA, null);
let time_in_millis = getCurrentTimeInMillis();
if (saved_ali_data == null || saved_ali_data.ali_tag != ali_tag || saved_ali_data.updated_at + COUNTRY_ALI_DATA_TIME_OFFSET_MILLIS < time_in_millis) {
// pouze provadet request, jestli informace ze settingu jsou ulozene informace z jine aliance a nebo jsou data moc stara
ali_bonus = await fetchAliFundaBonus(ali_tag);
setSetting(COUNTRY_ALI_DATA, {
ali_tag: ali_tag,
ali_bonus: ali_bonus,
updated_at: time_in_millis,
});
} else {
ali_bonus = saved_ali_data.ali_bonus;
}
}
let resources_reduction = 0;
let total_wage_reduction = ali_bonus;
let econom_effective_level = ekonom;
if (ekonom > 5) {
econom_effective_level = 4 + ((ekonom - 4) * (ekonom - 3)) / 2;
}
total_wage_reduction += econom_effective_level * 5;
if (hodnost >= 11) resources_reduction += 15;
if (hodnost >= 12) total_wage_reduction += 25;
if (vlada === "Fundamentalismus") total_wage_reduction += 25;
createWagesTable(eco_detail_table, war_detail_table, prestige, total_wage_reduction, resources_reduction, vlada);
}
async function fetchAliFundaBonus(ali_tag) {
return new Promise((resolve) => {
const url = "index.php?p=najit&s=najittag&tag=" + ali_tag;
let req = new XMLHttpRequest();
req.open("GET", url);
req.onload = function () {
if (req.readyState == 4 && req.status == 200) {
let parser = new DOMParser();
let doc = parser.parseFromString(req.response, "text/html");
let funda_bonus = 0;
let table = doc.getElementById("alliance-members");
let member_count = table.rows.length - 3;
const fund_text = "Fund";
for (let index = 1; index < member_count + 1; index++) {
const row = table.rows[index];
let cell = row.cells[6];
if (cell.textContent === fund_text) {
funda_bonus = Math.floor(member_count / 2) * 3;
break;
}
}
resolve(funda_bonus);
} else {
resolve(0);
}
};
req.send();
});
}
function getValuesFromTheCell(cell) {
return cell.innerHTML.replaceAll("\n\t", "").replaceAll(" ", "").split("<br>");
}
function calculateTotalWages(units, prestige, wage_increase = 0) {
const wage_modification = Math.max((1 + wage_increase / 100) * (1 + prestige / 5000000), 0.1);
let wages_total = 0;
for (const unit of units) {
unit.expenses_per_unit = unit.base_wage * wage_modification;
unit.wages_total = Math.round(unit.count * unit.expenses_per_unit * 100) / 100;
wages_total += unit.wages_total;
}
return Math.round(wages_total * 100) / 100;
}
function calculateTotalExpenses(units, food_price, energy_price) {
let expenses_total = 0;
for (const unit of units) {
unit.expenses_per_unit += unit.base_food_consumption * food_price + unit.base_energy_consumption * energy_price;
unit.expenses_per_prestige_point = unit.expenses_per_unit / unit.prestige;
unit.expenses_total = Math.round(unit.expenses_per_unit * unit.count * 100) / 100;
expenses_total += unit.expenses_total;
}
return Math.round(expenses_total * 100) / 100;
}
function fetchMarketPrices() {
return new Promise((resolve) => {
let req = new XMLHttpRequest();
let url = "index.php?p=domtrh";
req.open("GET", url);
req.onload = function () {
if (req.readyState == 4 && req.status == 200) {
let parser = new DOMParser();
let doc = parser.parseFromString(req.response, "text/html");
let prices = [];
let price_cells = doc.querySelectorAll("#icontent form .vis_tbl .mactprice");
for (let i = 0; i < 2; i++) {
const price_cell = price_cells[i];
prices.push(Number(price_cell.innerText.replaceAll(" ", "").replace("$", "")));
}
resolve(prices);
} else {
log("File not found");
}
};
req.send();
});
}
function createExpensesTable(units, expenses_total, wages_total, food_price, energy_price, total_wage_reduction, resources_reduction) {
const div = createElement();
div.append(createElement("h2", { textContent: "Výdaje za armádu" }));
const table = createElement("table", { id: "spotreba_jednotek", className: "vis_tbl", style: "table-layout: fixed; min-width: 600px; max-width: 1200px; width: 70%;" });
div.append(table);
const th_values = [
"Jednotka",
"Počet",
"Celkem",
`Žold (${(total_wage_reduction <= 0 ? "+" : "") + -total_wage_reduction}%)`,
`Suroviny (${(resources_reduction <= 0 ? "+" : "") + -resources_reduction}%)`,
"Na 1 jednotku",
"Na bod prestiže",
"Procento výdajů",
];
let row = table.insertRow();
th_values.forEach((th_value) => {
row.appendChild(createElement("th", { textContent: th_value }));
});
let total_food_cost = 0,
total_energy_cost = 0;
units.forEach((unit) => {
const food_consumed = unit.base_food_consumption * unit.count;
const food_cost = food_consumed * food_price;
total_food_cost += food_cost;
const energy_consumed = unit.base_energy_consumption * unit.count;
const energy_cost = energy_consumed * energy_price;
total_energy_cost += energy_cost;
const base_wage_per_unit = unit.wages_total / unit.count;
const base_resources_consumption = unit.base_food_consumption * food_price + unit.base_energy_consumption * energy_price;
const wage_percentage = (base_wage_per_unit / (base_wage_per_unit + base_resources_consumption)) * 100;
const others_percentage = (base_resources_consumption / (base_wage_per_unit + base_resources_consumption)) * 100;
const row = table.insertRow();
let cell = row.insertCell();
cell.textContent = unit.name;
cell.classList.add("rname", "l");
addCellWithNumericalValue(row, unit.count, 0, "");
cell = addCellWithNumericalValue(row, unit.expenses_total);
cell.title = `Žold: ${Math.round(wage_percentage * 10) / 10}% \nSuroviny: ${Math.round(others_percentage * 10) / 10}%`;
cell = addCellWithNumericalValue(row, unit.wages_total);
cell.title = `Žold: ${Math.round(wage_percentage * 10) / 10}% \nSuroviny: ${Math.round(others_percentage * 10) / 10}%`;
if (food_cost > energy_cost) {
cell = addCellWithNumericalValue(row, food_cost);
cell.title = `Celková spotřeba jídla jednotkou: ${Math.round(food_consumed * 10) / 10}\nCena jídla: ${food_price}`;
} else {
cell = addCellWithNumericalValue(row, energy_cost);
if (energy_cost > 0) {
cell.title = `Celková spotřeba energie jednotkou: ${Math.round(energy_consumed * 10) / 10}\nCena energie: ${energy_price}`;
}
}
cell = addCellWithNumericalValue(row, unit.expenses_per_unit, 3);
cell.title = `Žold: ${Math.round(base_wage_per_unit * 1000) / 1000}$ \nSuroviny: ${Math.round(base_resources_consumption * 1000) / 1000}$`;
cell = addCellWithNumericalValue(row, unit.expenses_per_prestige_point, 3);
cell.title = `Žold: ${Math.round((base_wage_per_unit / unit.prestige) * 1000) / 1000}$ \nSuroviny: ${Math.round((base_resources_consumption / unit.prestige) * 1000) / 1000}$`;
let percent = expenses_total > 0 ? unit.expenses_total / expenses_total : 0;
cell = addCellWithNumericalValue(row, percent * 100, 1, "%");
cell.title = `Žold: ${Math.round(wage_percentage * 10) / 10}% \nSuroviny: ${Math.round(others_percentage * 10) / 10}%`;
});
row = table.insertRow();
let cell = row.insertCell();
cell.textContent = "Celkem";
cell.classList.add("rname", "l");
cell.colSpan = 2;
addCellWithNumericalValue(row, expenses_total);
addCellWithNumericalValue(row, wages_total);
cell = addCellWithNumericalValue(row, total_food_cost + total_energy_cost);
cell.title = `Celkem jídlo: \t${formatNumber(total_food_cost.toFixed(1))}$\nCelkem energie: \t${formatNumber(total_energy_cost.toFixed(1))}$`;
row.insertCell().colSpan = 3;
return div;
}
function processPrestigeDetails() {
let tables = document.getElementsByClassName("vis_tbl");
let table = null;
for (let i = 0; i < tables.length; i++) {
if (tables[i].rows.length > 10) {
table = tables[i];
break;
}
}
if (table === null) return;
let percent = 0,
prestige = 0;
for (let index = 3; index < table.rows.length; index++) {
const row = table.rows[index];
if (row.cells[0].tagName === "TH") {
insertPrestigeDetailsRow(table, index, prestige, percent);
prestige = 0;
percent = 0;
index++;
continue;
}
const percent_cell = row.cells[1];
const prestige_cell = row.cells[4];
percent += Number(percent_cell.textContent.split("%")[0]);
prestige += Number(prestige_cell.textContent.replace(/\s/g, ""));
}
insertPrestigeDetailsRow(table, table.rows.length, prestige, percent);
}
function insertPrestigeDetailsRow(table, index, prestige, percent) {
const row = table.insertRow(index);
let cell = row.insertCell();
cell.classList.add("rname", "l");
cell.textContent = "Celkem";
cell = row.insertCell();
cell.classList.add("perf");
cell.textContent = percent.toFixed(1) + "%";
cell = row.insertCell();
cell.classList.add("rdata");
cell.colSpan = 2;
cell = row.insertCell();
cell.classList.add("rdata");
cell.textContent = formatNumber(prestige);
}
function modifyStatisticsPage() {
let table = document.getElementById("statszrizeni");
if (!table) {
return;
}
let rows = Array.from(table.rows);
let row = rows.shift();
row.insertBefore(createElement("th", { innerHTML: "%<br>zemí" }), row.children[2]);
let countries_count = rows.reduce((acc, row) => acc + Number(row.cells[1].textContent), 0);
rows.forEach((row) => {
const count = Number(row.cells[1].textContent);
const cell = row.insertCell(2);
const percent = (100 * count) / countries_count;
cell.textContent = formatNumber(percent.toFixed(1)) + "%";
});
let sum_row = table.insertRow();
let cell = sum_row.insertCell();
cell.classList.add("l");
cell.textContent = "Celkem";
cell = sum_row.insertCell();
cell.textContent = countries_count;
cell = sum_row.insertCell();
cell.textContent = "100.0%";
const stats = getStatsData();
if (!stats) {
return;
}
cell = sum_row.insertCell();
cell.textContent = stats.average_land;
cell = sum_row.insertCell();
cell.textContent = stats.average_prestige;
cell = sum_row.insertCell();
cell.textContent = stats.max_prestige;
cell = sum_row.insertCell();
cell.textContent = stats.average_turns_played;
}
function getStatsData() {
const table = document.getElementById("statvalues");
if (!table) {
return null;
}
let stats_data = {};
let rows = Array.from(table.rows);
const labels = ["average_prestige", "average_land", "max_prestige", "average_turns_played"];
const row_index = [1, 2, 1, 6];
const column_index = [1, 1, 3, 1];
for (let index = 0; index < row_index.length; index++) {
const row = rows[row_index[index]];
const value = Number(row.children[column_index[index]].textContent);
stats_data[labels[index]] = value;
}
return stats_data;
}
function addCellWithNumericalValue(row, value, fraction_digits = 1, after_value = "$") {
const cell = row.insertCell();
cell.textContent = formatNumber(value.toFixed(fraction_digits)) + after_value;
cell.classList.add("rdata", "r");
return cell;
}
function modifyArchive() {
const modify_archive = getSetting(MODIFY_ARCHIVE, true);
if (!modify_archive) {
return;
}
let tables = document.getElementsByClassName("vis_tbl");
let table = null;
for (let i = 0; i < tables.length; i++) {
if (tables[i].rows.length > 2 && tables[i].rows[0].cells.length == 2) {
table = tables[i];
break;
}
}
if (table === null) {
return;
}
const TOOLTIP_ROW_VALUES = ["name", "count", "prestige"];
CssHelper.addSavedCss(CssHelper.styles.archive);
CssHelper.addTooltipCss(250, true, 100);
let header_row = table.rows[0];
header_row.style.position = "sticky";
header_row.style.top = "0";
header_row.style.zIndex = "1";
header_row.appendChild(createElement("th", { textContent: "Prestiž na expy" }));
const colors = ["red", "lime", "mediumorchid"];
for (let index = 1; index < table.rows.length; index++) {
const row = table.rows[index];
let message = row.cells[1].textContent;
message = message.replace("Nová - Útoky", "").replace("Nová - Spojenci", "").replace("Nová - Rozvědka", "").trim();
let result = null;
if (message.indexOf("Nepřátelským mechům") !== -1) {
result = processExpTazeni(message);
} else if (message.indexOf("na nás podnikla partyzánský útok") !== -1) {
result = processExpPartyzan(message);
} else if (message.indexOf("Naši vojáci odvrátili partyzánský útok") !== -1) {
result = processExpPartyzanSuccessful(message);
} else if (message.startsWith("Pěchotě země ")) {
result = processExpVniknutiDoBunkru(message);
} else if (message.startsWith("Naši vojáci odvrátili vniknutí do bunkrů")) {
result = processExpVniknutiDoBunkruSuccessful(message);
} else if (message.startsWith("Naší pěchotě se")) {
result = processExpVniknutiDoBunkruUtok(message);
} else if (message.startsWith("Tankové brigádě ")) {
result = processExpTyl(message);
} else if (message.startsWith("Bleskový úder tankové brigády ")) {
result = processExpTyl(message, true);
} else if (message.startsWith("Letectvo nepřátelské země")) {
result = processExpNaletSuccessful(message);
} else if (message.indexOf("na naše strategická vojenská zařízení") !== -1) {
result = processExpNalet(message);
} else if (message.startsWith("Stali jsme se obětí loupežného útoku") || message.startsWith("Stali jsme se obětí částečného loupežného útoku")) {
result = processExpLoupezak(message);
} else if (message.indexOf("prolomila naši obranu a zabrala ") !== -1) {
result = processExpDobyvak(message);
} else if (message.startsWith("Naší tankové brigádě se")) {
result = processExpTylUtok(message);
} else if (message.startsWith("Bleskový úder naší tankové brigády")) {
result = processExpTylUtok(message, false);
} else if (message.indexOf("Naši elitní piloti podnikli taktický nálet") !== -1 || message.indexOf("Naši elitní piloti podnikli částečný taktický nálet") !== -1) {
result = processExpNaletUtok(message);
} else if (message.startsWith("Našim mechům se podařilo během nočního tažení")) {
result = processExpTazeniUtok(message);
} else if (message.indexOf("Při loupeživém útoku na ") !== -1) {
result = processExpNormalUtok(message);
} else if (message.indexOf("Obsadili jsme") !== -1) {
result = processExpNormalUtok(message);
} else if (message.startsWith("Partyzánský útok")) {
result = processExpPartyzanUtok(message);
} else if (message.startsWith("Naši vojáci neuspěli díky silnému odporu")) {
result = processExpPartyzanUtok(message, false);
} else if (message.startsWith("Barbarská armáda")) {
result = processExpVyhlaz(message);
} else if (message.indexOf("Při vyhlazovacím útoku") !== -1) {
result = processExpDobyvakSuccessful(message);
} else if (message.startsWith("Sebevědomá země")) {
result = processExpDobyvakSuccessful(message);
} else if (message.indexOf("bombardovaly naše budovy") !== -1) {
result = processExpBombeni(message);
} else if (message.startsWith("Naše mocné protiletecké síly")) {
result = processExpBombeniSuccessful(message);
} else if (message.indexOf("úspěšně bombardovaly civilní cíle") !== -1) {
result = processExpBombeniUtok(message);
} else if (message.startsWith("Našim jednotkám se nepodařilo obejít přesilu nepřátelských mechů")) {
result = processExpTazeniUtok(message);
} else if (message.startsWith("Země") && message.indexOf("nebyla poražena. Naše ztráty byly ")) {
result = processExpNormalUtok(message);
} else if (message.startsWith("Byli jsme povoláni zemí")) {
result = processExpSpojka(message);
} else if (message.startsWith("Rozvědka")) {
// process opku
if (message.indexOf("Naši agenti ukradli celkem") !== -1) {
processTechnologyToMoney(message, row);
}
}
const cell = row.insertCell();
if (result === null) continue;
cell.style.textAlign = "center";
cell.style.userSelect = "none";
if (result.exp_ratio !== null) {
cell.textContent = result.exp_ratio;
cell.style.color = colors[result.type];
const tooltip = createElement();
cell.appendChild(tooltip);
wrapInTooltip(tooltip);
const header = addRowToTooltip(tooltip, { name: "Jednotka", count: "Počet", prestige: "Prestiž" });
header.classList.add("header");
for (let index = 0; index < result.units_lost.length; index++) {
const unit = result.units_lost[index];
addRowToTooltip(tooltip, unit);
}
tooltip.appendChild(createElement("p", { className: "divider" }));
const additional_info = [
{
name: "Celkem:",
count: "",
prestige: result.total_prestige,
},
{
name: "Zkušeností:",
count: "",
prestige: result.experience,
},
];
for (let index = 0; index < additional_info.length; index++) {
const info = additional_info[index];
addRowToTooltip(tooltip, info);
}
}
}
function addRowToTooltip(tooltip, information) {
const p = createElement("p", { className: "row" });
tooltip.appendChild(p);
for (let i = 0; i < TOOLTIP_ROW_VALUES.length; i++) {
const unit_value = TOOLTIP_ROW_VALUES[i];
const span = createElement("span", { textContent: information[unit_value] });
p.appendChild(span);
}
return p;
}
}
async function processTechnologyToMoney(message, row) {
message = message.split("Rozpis: ")[1];
let numbers = message.match(/(\d)+/g);
let words = message.replace(/[0-9]/g, "").split(".")[0].split(", ");
let tech_prices = await technology_prices.get();
let total_money = 0,
title = "";
for (let i = 0; i < words.length; i++) {
let count = Number(numbers[i]);
if (count === 0) {
continue;
}
let word = words[i];
let price = tech_prices[i];
total_money += price * count;
title += `${word}: ${formatNumber(count)}x ${formatNumber(price)}$ = ${formatNumber(Math.floor(price * count))}$\n`;
}
let p = createElement("p", { textContent: "Hodnota celkem: ", title });
row.cells[1].appendChild(p);
p.appendChild(createElement("span", { textContent: formatNumber(Math.floor(total_money)) + "$", style: "font-weight: bold; color: lime;" }));
}
function processExpTazeni(message) {
if (message.indexOf("nepodařilo obejít přesilu našich mechů") !== -1) {
message = message.split("nepodařilo obejít přesilu našich mechů")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("mechy", Number(numbers[1]))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
message = message.split("se podařilo během nočního tažení naší zemí zlikvidovat")[1];
let numbers = message.match(/(\d)+/g);
let units = [
UNITS.get("vojaci", Number(numbers.shift())),
UNITS.get("tanky", Number(numbers.shift())),
UNITS.get("stihacky", Number(numbers.shift())),
UNITS.get("budovy", Number(numbers.shift())),
UNITS.get("mechy", Number(numbers[1])),
];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpTazeniUtok(message) {
message = message.split("Zničeno bylo")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("mechy", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience, 1);
}
function processExpPartyzan(message) {
message = message.split("%, zabito bylo ")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("agenti", Number(numbers.shift())), UNITS.get("energie", Number(numbers.shift())), UNITS.get("vojaci", Number(numbers[1]))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpPartyzanSuccessful(message) {
message = message.split("Zahynulo při tom ")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("vojaci", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpPartyzanUtok(message, success = true) {
let separator = "Při bojích zahynulo";
if (!success) separator = "Zahynulo při tom";
message = message.split(separator)[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("vojaci", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience, 1);
}
function processExpVniknutiDoBunkru(message) {
message = message.split("se podařilo vniknout do ")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("bunkry", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpVniknutiDoBunkruSuccessful(message) {
message = message.split("Zahynulo při tom ")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("vojaci", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpVniknutiDoBunkruUtok(message) {
message = message.split("Při tom zahynulo")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("vojaci", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience, 1);
}
function processExpTyl(message, success = false) {
let separator = "My jsme při tom přišli o";
if (success) separator = "Ztratili jsme při tom";
message = message.split(separator)[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("tanky", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpTylUtok(message, success = true) {
let separator = "My jsme při tom přišli o ";
if (!success) {
separator = "Ztratili jsme při tom ";
}
message = message.split(separator)[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("tanky", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience, 1);
}
function processExpNalet(message) {
message = message.split("Nálety nám zničily ")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("budovy_na_ruiny", Number(numbers.shift())), UNITS.get("stihacky", Number(numbers.shift())), UNITS.get("bunkry", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpNaletSuccessful(message) {
message = message.split("Při obraně jsme ztratili ")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("stihacky", Number(numbers.shift())), UNITS.get("bunkry", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpBombeni(message) {
message = message.split("Pod troskami")[1];
let numbers = message.match(/(\d)+/g);
let units = [
UNITS.get("budovy", Number(numbers.shift())),
UNITS.get("ruiny", Number(numbers.shift())),
UNITS.get("stihacky", Number(numbers.shift())),
UNITS.get("bunkry", Number(numbers.shift())),
];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpBombeniSuccessful(message) {
message = message.split(". Bylo zničeno ")[1];
let numbers = message.match(/(\d)+/g);
numbers.shift(); // nepratelske stihacky
let units = [UNITS.get("stihacky", Number(numbers.shift())), UNITS.get("bunkry", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience);
}
function processExpBombeniUtok(message) {
message = message.split("Bylo zničeno")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("stihacky", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience, 1);
}
function processExpNaletUtok(message) {
message = message.split("vojenských základen nepřítele")[1];
let numbers = message.match(/(\d)+/g);
let units = [UNITS.get("stihacky", Number(numbers.shift()))];
let experience = Number(numbers.pop());
return processExp(units, experience, 1);
}
function processExpLoupezak(message) {
message = message.split("Bylo nám násilně zabráno ")[1];
return processNormal(message);
}
function processExpNormalUtok(message) {
message = message.split("Naše ztráty byly ")[1];
return processNormalUtok(message);
}
function processExpSpojka(message) {
message = message.split("V bojích bylo ztraceno ")[1];
return processNormalUtok(message, true);
}
function processExpDobyvak(message) {
message = message.split("prolomila naši obranu a zabrala ")[1];
return processNormal(message);
}
function processExpDobyvakSuccessful(message) {
message = message.split("Naše ztráty byly")[1];
let numbers = message.match(/(\d)+/g);
const experience = Number(numbers.pop());
let units = [
UNITS.get("vojaci", Number(numbers.shift())),
UNITS.get("tanky", Number(numbers.shift())),
UNITS.get("bunkry", Number(numbers.shift())),
UNITS.get("mechy", Number(numbers.shift())),
];
return processExp(units, experience);
}
function processExpVyhlaz(message) {
message = message.split(" zničila ")[1];
let numbers = message.match(/(\d)+/g);
const experience = Number(numbers.pop());
let units = [
UNITS.get("budovy", Number(numbers[0])),
UNITS.get("ruiny", Number(numbers[1])),
UNITS.get("penize", Number(numbers[3])),
UNITS.get("jidlo", Number(numbers[4])),
UNITS.get("energie", Number(numbers[5])),
UNITS.get("technologie", Number(numbers[6])),
UNITS.get("vojaci", Number(numbers[7])),
UNITS.get("tanky", Number(numbers[8])),
UNITS.get("bunkry", Number(numbers[9])),
UNITS.get("mechy", Number(numbers[10])),
];
return processExp(units, experience);
}
function processNormal(message) {
let numbers = message.match(/(\d)+/g);
const experience = Number(numbers.pop());
let units = [
UNITS.get("uzemi", Number(numbers[0])),
UNITS.get("budovy", Number(numbers[2]) * 2),
UNITS.get("penize", Number(numbers[3])),
UNITS.get("jidlo", Number(numbers[4])),
UNITS.get("energie", Number(numbers[5])),
UNITS.get("technologie", Number(numbers[6])),
UNITS.get("vojaci", Number(numbers[7])),
UNITS.get("tanky", Number(numbers[8])),
UNITS.get("bunkry", Number(numbers[9])),
UNITS.get("mechy", Number(numbers[10])),
];
return processExp(units, experience);
}
function processNormalUtok(message, is_spojka = false) {
let numbers = message.match(/(\d)+/g);
const experience = Number(numbers.pop());
let units = [
UNITS.get("vojaci", Number(numbers.shift())),
UNITS.get("tanky", Number(numbers.shift())),
UNITS.get("bunkry", Number(numbers.shift())),
UNITS.get("mechy", Number(numbers.shift())),
];
let type = is_spojka ? 2 : 1;
return processExp(units, experience, type);
}
/**
*
* @param {array} units
* @param {int} experience
* @param {int} type 0 = defense, 1 = attack, 2 = ally
* @returns {object}
*/
function processExp(units, experience, type = 0) {
let total_prestige = 0,
units_lost = [];
for (let index = 0; index < units.length; index++) {
const unit = units[index];
const prestige = unit.count * unit.prestige;
total_prestige += prestige;
units_lost.push({ name: unit.name + ":", count: formatNumber(unit.count), prestige: formatNumber(prestige.toFixed(1)) });
}
let percentage = total_prestige == 0 ? 999 : (experience / total_prestige) * 100;
experience = formatNumber(experience.toFixed(1));
total_prestige = formatNumber(total_prestige.toFixed(1));
return { exp_ratio: formatNumber(percentage.toFixed(2)) + "%", units_lost, total_prestige, type, experience };
}
class Operation {
constructor(type) {
this.type = type;
}
}
Operation["Infiltrovat vládu"] = 10;
Operation["Infiltrovat rozvědku"] = 11;
Operation["Infiltrovat generální štáb"] = 12;
Operation["Infiltrovat vědecká centra"] = 13;
Operation["Nabourat ovládání mechů"] = 20;
Operation["Počítačový virus"] = 21;
Operation["Sabotovat letiště"] = 22;
Operation["Rozšířit epidemii"] = 23;
Operation["Demoralizovat obyvatele"] = 24;
Operation["Zničit rakety"] = 25;
Operation["Vykrást sklady"] = 30;
Operation["Vykrást centrální banku"] = 31;
Operation["Napíchnout ropovod"] = 32;
Operation["Ukrást technologie"] = 33;
Operation["Prodat drogy"] = 34;
Operation["Jiné"] = 40;
class SpyDifficulty {
constructor(type) {
this.type = type;
}
}
SpyDifficulty["snadná jak facka"] = 1;
SpyDifficulty["jednoduchá"] = 2;
SpyDifficulty["středně náročná"] = 3;
SpyDifficulty["velice náročná"] = 4;
SpyDifficulty["extrémně náročná"] = 5;
SpyDifficulty["téměř neproveditelná"] = 6;
const archive_spy = (function () {
const URL = "index.php?p=archiv&typ=3&limit=";
const ALLY_URL = "index.php?p=archiv&typ=3&tag=1&id=$country_id$&limit=";
const MESSAGES_PER_PAGE = 30;
const OPERATION_SEARCH_TERMS = [
// infiltrace
{
term: /infiltrova(li|t) vládu/,
operation: "Infiltrovat vládu",
},
{
term: /infiltrova(li|t) rozvědku/,
operation: "Infiltrovat rozvědku",
},
{
term: /infiltrova(li|t) generální štáb/,
operation: "Infiltrovat generální štáb",
},
{
term: /infiltrova(li|t) vědecká centra/,
operation: "Infiltrovat vědecká centra",
},
// sabotazni
{
term: /naboura(li|t) ovládání mechů/,
operation: "Nabourat ovládání mechů",
},
{
term: /zavirova(li|t) počítače/,
operation: "Počítačový virus",
},
{
term: /sabotova(li|t) letiště/,
operation: "Sabotovat letiště",
},
{
term: /rozšíři(li|t) epidemii/,
operation: "Rozšířit epidemii",
},
{
term: /demoralizova(li|t) obyvatele/,
operation: "Demoralizovat obyvatele",
},
{
term: /zniči.*raket/,
operation: "Zničit rakety",
},
// loupezive
{
term: /vykr(a|á)(dli|st) sklady/,
operation: "Vykrást sklady",
},
{
term: /vykr(a|á)(dli|st) centrální banku/,
operation: "Vykrást centrální banku",
},
{
term: /napích(li|nout) ropovod/,
operation: "Napíchnout ropovod",
},
{
term: /ukr(a|á)(st|dli) (celkem )?(\d)*( )?technologi(í|e)/,
operation: "Ukrást technologie",
},
{
term: /prod(a|á)(vá|t) drogy/,
operation: "Prodat drogy",
},
// TODO zbytek sabotaznich:
{
term: " ",
operation: "Jiné",
},
];
const steal_operation_types = [Operation["Vykrást sklady"], Operation["Vykrást centrální banku"], Operation["Napíchnout ropovod"], Operation["Ukrást technologie"], Operation["Prodat drogy"]];
let country_id;
let current_page;
let last_message_time = null;
let fetch_until_time = null;
let spy_success_stats;
let spy_operation_stats;
let spy_stolen_stats;
let button = null;
function initValues(_country_id) {
country_id = _country_id;
current_page = 0;
last_message_time = null;
fetch_until_time = null;
current_page = 0;
spy_stolen_stats = [];
spy_operation_stats = [];
spy_success_stats = [];
}
function save() {
const stats = getSetting(COUNTRY_STATS, []);
let relevant_stats = stats.find((country_stats) => country_stats.country_id === country_id);
if (relevant_stats === undefined) {
relevant_stats = {
country_id,
};
stats.push(relevant_stats);
}
relevant_stats.spy_stats = {
success_stats: spy_success_stats,
operation_stats: spy_operation_stats,
stolen_stats: spy_stolen_stats,
last_message: last_message_time,
// spy_messages: archive_spy.messages,
};
setSetting(COUNTRY_STATS, stats);
}
async function processSpyArchive(is_ally, force_all = false) {
const country_stats = getCountryStats(country_id);
if (country_stats !== undefined && !force_all) {
let spy_stats = country_stats.spy_stats;
spy_success_stats = spy_stats.success_stats;
spy_operation_stats = spy_stats.operation_stats;
spy_stolen_stats = spy_stats.stolen_stats;
let time = spy_stats.last_message;
fetch_until_time = time ? archiveGetTimeInMillis(time) : null;
}
let message_count = 0;
let url = URL;
if (is_ally) {
url = ALLY_URL.replace("$country_id$", country_id);
}
do {
message_count = await fetchPage(url + current_page++ * MESSAGES_PER_PAGE, processArchivePage);
if (button !== null) {
button.textContent = `Probíhá... ${current_page}`;
}
} while (message_count === MESSAGES_PER_PAGE);
}
function isNewerMessage(row) {
const time = row.cells[0].textContent;
const time_in_millis = archiveGetTimeInMillis(time);
if (fetch_until_time && fetch_until_time === time_in_millis) {
return false;
}
return true;
}
function getOperationId(original_message) {
for (let index = 0; index < OPERATION_SEARCH_TERMS.length; index++) {
const search_term = OPERATION_SEARCH_TERMS[index];
if (original_message.match(search_term.term) !== null) {
return Operation[search_term.operation];
}
}
return null;
}
async function addStolenData(clean_message, operation_id, targetted_country_id) {
const stolen_amount = await getStolenData(clean_message, operation_id);
if (stolen_amount === null) return;
const operation_stats = getStolenStats(operation_id);
const target_country_stats = getStolenStatsForTargetCountry(operation_stats, targetted_country_id);
target_country_stats.per_operation.push(stolen_amount);
}
function getOperationStats(operation_id) {
return findStats(spy_operation_stats, "operation_id", operation_id, { operation_id, count: 0, success: 0 });
}
function getStolenStats(operation_id) {
return findStats(spy_stolen_stats, "operation_id", operation_id, { operation_id, values: [] });
}
function getStolenStatsForTargetCountry(operation_stats, targetted_country_id) {
return findStats(operation_stats.values, "country_id", targetted_country_id, { country_id: targetted_country_id, per_operation: [] });
}
function getSuccessStats(difficulty) {
return findStats(spy_success_stats, "difficulty_id", difficulty, { difficulty_id: difficulty, count: 0, success: 0 });
}
function findStats(stats, key, id, blank_object) {
let result = stats.find((stat) => stat[key] === id);
if (result === undefined) {
result = blank_object;
stats.push(result);
}
return result;
}
function getCleanMessage(cell) {
let text = "";
for (let i = 0; i < cell.childNodes.length; i++) {
if (cell.childNodes[i].nodeType === Node.TEXT_NODE) {
text += cell.childNodes[i].textContent;
}
}
return text;
}
async function processRow(row) {
const original_message = row.cells[1].textContent;
const clean_message = getCleanMessage(row.cells[1]);
if (original_message.indexOf("Operace byla ") == -1) {
return null;
}
const targetted_country_id = original_message.match(/(?<=\(#)\d+(?=\))/g)[0];
const difficulty_text = original_message.split("Operace byla ")[1].split(".")[0];
const difficulty = SpyDifficulty[difficulty_text] || 1;
const failed_operation = original_message.indexOf("nepodařilo") !== -1;
let difficulty_results = getSuccessStats(difficulty);
difficulty_results.count++;
if (!failed_operation) difficulty_results.success++;
const operation_id = getOperationId(original_message);
const operation_stats = getOperationStats(operation_id);
operation_stats.count++;
if (failed_operation) return;
operation_stats.success++;
if (steal_operation_types.includes(operation_id)) {
await addStolenData(clean_message, operation_id, targetted_country_id);
}
}
async function processArchivePage(doc) {
let tables = doc.getElementsByClassName("vis_tbl");
let table = null;
for (let i = 0; i < tables.length; i++) {
if (tables[i].rows.length > 2 && tables[i].rows[0].cells.length >= 2) {
table = tables[i];
break;
}
}
if (table === null) {
return;
}
let rows = table.rows;
if (last_message_time === null) {
last_message_time = rows[1].cells[0].textContent;
}
for (let i = 1; i < rows.length; i++) {
if (!isNewerMessage(rows[i])) return;
await processRow(rows[i]);
}
return table.rows.length - 1;
}
async function transformNumbersTechy(numbers) {
const tech_prices = await technology_prices.get();
for (let i = 0; i < numbers.length; i++) {
numbers[i] = tech_prices[i] * Number(numbers[i]);
}
return numbers;
}
function transformNumbersEnergy(numbers) {
const energy_price = getSetting(ENERGY_PRICE, 15);
return transformNumbers(numbers, energy_price);
}
function transformNumbersFood(numbers) {
const food_price = getSetting(FOOD_PRICE, 15);
return transformNumbers(numbers, food_price);
}
function transformNumbers(numbers, price) {
for (let i = 0; i < numbers.length; i++) {
numbers[i] = price * Number(numbers[i]);
}
return numbers;
}
async function getStolenData(clean_message, operation_id) {
let numbers = clean_message.match(/(?<!\(#)\d+(?!\))/g);
switch (operation_id) {
case Operation["Napíchnout ropovod"]:
numbers = transformNumbersEnergy(numbers);
break;
case Operation["Vykrást sklady"]:
numbers = transformNumbersFood(numbers);
break;
case Operation["Ukrást technologie"]:
numbers = await transformNumbersTechy(numbers);
break;
default:
numbers = clean_message.match(/(?<!\(#)\d{3,}(?!\))/g);
}
if (numbers === null) {
return null;
}
const sum = numbers.reduce((acc, n) => acc + Number(n), 0);
return sum;
}
return {
OPERATION_SEARCH_TERMS,
spy_success_stats() {
return spy_success_stats;
},
last_message_time() {
return last_message_time;
},
async processSpyArchive(country_id, is_ally = false, force_all = false, reload_page = false, _button = null) {
initValues(country_id);
button = _button;
if (button !== null) {
button.textContent = "Probíhá...";
}
await processSpyArchive(is_ally, force_all);
save();
if (reload_page) {
refreshPage();
}
},
// spy_operation_stats: spy_operation_stats
};
})();
function modifyAdvancements() {
if (!getSetting(MODIFY_ADVANCEMENTS, true)) {
return;
}
execute();
function execute() {
const table = getAdvancementTable();
if (table === null) {
return;
}
const show_base_price = getSetting(ADV_SHOW_BASE_PRICE, true);
const show_min_price = getSetting(ADV_SHOW_MIN_PRICE, true);
const show_current_price = getSetting(ADV_SHOW_CURRENT_PRICE, true);
const difficulty = getCurrentTechnologicalDifficulty();
if (show_base_price) {
CssHelper.addTooltipCss(300);
}
for (let index = 1; index < table.rows.length; index++) {
const row = table.rows[index];
const type = getAdvancementType(row);
const advancement_name = getAdvancementName(row);
const current_price_element = getCurrentPriceElement(row);
const current_price = getCurrentPrice(current_price_element);
const times_researched = getTimesResearched(row);
formatValueOnElement(current_price_element);
const price_reduction = getPriceReduction(row, type);
let elements = [];
if (show_base_price) {
elements.push(addBasePrice(current_price_element, current_price, price_reduction, difficulty, advancement_name));
}
if (type == AdvancementHelper.types.S) {
continue;
}
if (show_min_price) {
elements.push(addMinPrice(current_price_element, current_price, price_reduction, difficulty, type, advancement_name, times_researched));
}
if (show_current_price) {
addPriceReduction(current_price_element, price_reduction);
}
mergeTooltips(elements);
}
}
function mergeTooltips(elements) {
if (elements.length < 2) {
return;
}
for (let index = 0; index < elements.length; index++) {
const element = elements[index];
if (!element.classList.contains("tooltiptext")) return;
}
let content = "";
for (let index = 1; index < elements.length; index++) {
const element = elements[index];
content += "<p>" + element.innerHTML + "</p>";
element.remove();
}
const tooltip = elements[0];
tooltip.innerHTML += content;
}
function getPriceReduction(row, type) {
if (type == AdvancementHelper.types.S || type == AdvancementHelper.types["K-"]) {
return 100;
}
const country_count = Number(row.cells[3].textContent);
return getPrice(type, country_count);
}
function getPrice(type, countries) {
if (type == AdvancementHelper.types.S || type == AdvancementHelper.types["K-"]) {
return 100;
}
const reduction = AdvancementHelper.maxReduction[type].reduction;
const countries_max = AdvancementHelper.maxReduction[type].countries;
const base = 100 - reduction;
const discounted = reduction * (1 - Math.min(countries / countries_max, 1));
return base + discounted;
}
function getMinPrice(type) {
if (type == AdvancementHelper.types.S || type == AdvancementHelper.types["K-"]) {
return 100;
}
return getPrice(type, AdvancementHelper.maxReduction[type].countries);
}
function getAdvancementType(row) {
let value = row.cells[0].textContent.match(/\([TSK-]*\)/g)[0];
return value.slice(1).slice(0, -1);
}
function getAdvancementName(row) {
const cell = row.cells[0];
const child_nodes = cell.childNodes;
return child_nodes[child_nodes.length - 1].textContent.split(" (")[0].trim();
}
function addPriceReduction(element, price_reduction) {
const wrapper = createElement("i", { textContent: "Aktuální cena pokroku je: " + Math.round(price_reduction * 10) / 10 + "%" });
const parent = element.parentElement.parentElement;
const sibling = element.parentElement.nextSibling;
if (sibling) {
parent.insertBefore(wrapper, sibling);
} else {
parent.appendChild(wrapper);
}
return wrapper;
}
function addMinPrice(current_price_element, current_price, price_reduction, difficulty, type, advancement_name, times_researched) {
let min_price = 0;
if (AdvancementHelper.advancementExceptions[advancement_name] !== undefined) {
let exception = AdvancementHelper.advancementExceptions[advancement_name];
min_price = exception.minimum_price;
if (exception.per_country_price) {
let extra_price = exception.per_country_price * times_researched;
if (exception.cap_price && exception.cap_price <= min_price + extra_price) {
min_price = exception.cap_price;
} else {
min_price += extra_price;
}
}
if (!exception.not_affected_by_difficulty) {
min_price = min_price * difficulty;
}
} else {
min_price = (current_price / price_reduction) * getMinPrice(type);
}
const element = addPriceValue(current_price_element, min_price, "Minimální cena");
if (getSetting(ADV_SHOW_MIN_PRICE_IN_TOOLTIP, false)) {
element.classList.add("center");
wrapInTooltip(element);
}
return element;
}
function addBasePrice(current_price_element, current_price, current_reduction, difficulty, advancement_name) {
let base_price = 0;
if (AdvancementHelper.advancementExceptions[advancement_name] !== undefined) {
base_price = AdvancementHelper.advancementExceptions[advancement_name].base_price;
} else {
base_price = getBasePrice(current_price, current_reduction, difficulty);
}
const element = addPriceValue(current_price_element, base_price, "Základní cena");
if (getSetting(ADV_SHOW_BASE_PRICE_IN_TOOLTIP, true)) {
element.classList.add("center");
wrapInTooltip(element);
}
return element;
}
function getCurrentPrice(current_price_element) {
return Number(current_price_element.textContent);
}
function getCurrentPriceElement(row) {
return row.getElementsByTagName("em")[0];
}
function getTimesResearched(row) {
return Number(row.cells[3].textContent);
}
function formatValueOnElement(current_price_element) {
const current_price = Number(current_price_element.textContent);
current_price_element.textContent = formatNumber(current_price);
}
function addPriceValue(element, value, label = "") {
const wrapper = createElement("p", { className: "imprp" });
const i = createElement("i");
wrapper.appendChild(i);
const em = createElement("em", { textContent: formatNumber(value.toFixed(0)) });
i.appendChild(em);
i.innerHTML = label + ": " + i.innerHTML + " " + element.nextSibling.textContent;
const parent = element.parentElement.parentElement;
const sibling = element.parentElement.nextSibling;
if (sibling) {
parent.insertBefore(wrapper, sibling);
} else {
parent.appendChild(wrapper);
}
return wrapper;
}
function getBasePrice(current_price, current_reduction, difficulty) {
return ((current_price / current_reduction) * 100) / difficulty;
}
function getAdvancementTable() {
let tables = document.getElementsByClassName("vis_tbl");
let table = null;
for (let i = 0; i < tables.length; i++) {
if (tables[i].rows[0].cells[0].textContent == "Pokrok") {
table = tables[i];
break;
}
}
return table;
}
function getCurrentTechnologicalDifficulty() {
let elements = document.querySelectorAll(".infotext strong");
let difficulty = null;
for (let i = 0; i < elements.length; i++) {
if (elements[i].textContent.indexOf("Náročnost pokroků je") !== -1) {
const parts = elements[i].textContent.split(" ");
difficulty = Number(parts[parts.length - 1]);
break;
}
}
return difficulty;
}
}
class ValkaHelper {
static get rychlost_dopripravovani_za_kolo() {
return 3;
}
static get vyssi_dopriprava_nad_pripravenosti() {
return 10;
}
}
function modifyValka() {
let last_production_table = null;
let warning_message_element = null;
const WARNING_MESSAGE = "!!! Útokem se dopouštíte porušení pravidel VEDENÍ ALIANCE !!!";
const BUILDINGS_LINK = "index.php?p=budovy";
const DOTACE_LINK = "index.php?p=dotace";
const DEMOLITION_LINK = "index.php?p=budovy&s=budobour";
const is_show_exp_on = getSetting(STRIKE_SHOW_EXP, true);
const is_build_stavebka_on = getSetting(STRIKE_SHOW_BUILD_BUTTON, true);
const is_exp_general_button_on = getSetting(STRIKE_SHOW_GRANT_EXP_TO_GENERAL_BUTTON, true);
const is_burn_land_button_on = getSetting(STRIKE_SHOW_BURN_LAND_BUTTON, false);
const is_extra_protection_from_accidental_attacks_on = getSetting(STRIKE_WARNING_DISABLES_BUTTON, true);
execute();
function execute() {
CssHelper.addSavedCss(CssHelper.styles.strike);
if (is_show_exp_on) {
showExp();
}
if (is_build_stavebka_on || is_exp_general_button_on || is_burn_land_button_on) {
addAlternativeReadyingButtons(is_build_stavebka_on, is_exp_general_button_on, is_burn_land_button_on);
}
if (is_extra_protection_from_accidental_attacks_on) {
if (hasWarningMessage()) {
disableButton();
addForceAttackButton();
}
}
}
function disableButton() {
const button = getStrikeSubmitButton();
button.disabled = true;
button.classList.add("disabled");
}
function addForceAttackButton() {
const warning_message = getWarningMessage();
if (warning_message === null) {
return;
}
const parent = warning_message.parentElement;
parent.style.textAlign = "center";
const button = createButton("Rozumím a chci pokračovat", () => {
const btn = getStrikeSubmitButton();
btn.disabled = false;
btn.classList.remove("disabled");
});
parent.appendChild(button);
}
function getStrikeSubmitButton() {
return document.forms[0].querySelector("input[type=submit]");
}
function getWarningMessage() {
if (warning_message_element !== null) return warning_message_element;
let warning_messages = document.getElementsByClassName("warn");
if (warning_messages.length == 0) return null;
for (let index = 0; index < warning_messages.length; index++) {
const element = warning_messages[index];
if (element.textContent == WARNING_MESSAGE) {
warning_message_element = element;
break;
}
}
return warning_message_element;
}
function hasWarningMessage() {
return getWarningMessage() !== null;
}
function showExp() {
const strong_elements = document.getElementsByTagName("strong");
let experience_element = null;
for (let i = 0; i < strong_elements.length; i++) {
if (strong_elements[i].nextSibling && strong_elements[i].nextSibling.textContent == " zkušeností.") {
experience_element = strong_elements[i];
break;
}
}
if (experience_element === null) {
return;
}
const experience = Number(experience_element.textContent);
const turns_played = getPlayedTurns();
const pripravenost = getCombatReadiness();
const turns_to_full = getTurnsToBeCombatReady(pripravenost, true);
const turns_to_less_than_3 = getTurnsToBeCombatReady(pripravenost, false);
const experience_to_full = getExperiencePerTurn(experience, turns_played + turns_to_full);
let break_element = createElement("br");
experience_element.parentElement.insertBefore(break_element, experience_element.nextSibling.nextSibling);
const element = addResults("Zkušeností / kolo: ", experience_to_full, break_element);
if (turns_to_full != turns_to_less_than_3) {
const experience_to_less_than_3 = getExperiencePerTurn(experience, turns_played + turns_to_less_than_3);
addResults("Zkušeností za kolo (<3%): ", experience_to_less_than_3, element);
}
}
function getPlayedTurns() {
let tables = document.getElementsByClassName("vis_tbl");
let turns = 0;
for (let index = 0; index < tables.length; index++) {
const table = tables[index];
if (table.rows[0].cells[0].textContent == "Peníze") {
last_production_table = table;
turns++;
}
}
return turns;
}
function getCombatReadiness() {
if (!last_production_table) {
log("Není uložená poslední tabulka.");
return 100;
}
return 100 - Number(last_production_table.rows[2].cells[5].textContent.slice(0, -1));
}
function getTurnsToBeCombatReady(pripravenost, doFull = true) {
let turns = 0;
if (pripravenost > 10) {
const per_turn = ValkaHelper.rychlost_dopripravovani_za_kolo + 1;
turns = Math.ceil((pripravenost - ValkaHelper.vyssi_dopriprava_nad_pripravenosti) / per_turn);
pripravenost -= turns * per_turn;
}
if (doFull) {
turns += Math.ceil(pripravenost / ValkaHelper.rychlost_dopripravovani_za_kolo);
} else {
turns += Math.floor(pripravenost / ValkaHelper.rychlost_dopripravovani_za_kolo);
}
return turns;
}
function getExperiencePerTurn(experience, turns) {
return (experience / turns).toFixed(0);
}
function addResults(label, experience, insertBeforeElement) {
const p = createElement("p", { textContent: label, style: "margin-left: 1ch;" });
p.appendChild(createElement("strong", { textContent: experience }));
const parent = insertBeforeElement.parentElement;
parent.insertBefore(p, insertBeforeElement.nextSibling);
return p;
}
function addAdvisedToBuildSymbol(button, advised) {
const text = ["✔", "✖"];
const colors = ["lime", "red"];
const index = advised ? 0 : 1;
button.appendChild(createElement("span", { textContent: text[index], style: `margin-left: 1ch; color: ${colors[index]};` }));
}
function createButtonPostavitStavebku(advised = false) {
const button = createButton("Postavit stavebku");
button.addEventListener("click", () => {
sendPost(BUILDINGS_LINK, buildStavebkuCallback, "doAction=build&vlgsc=&rsdsc=&comsc=&farmsc=&labsc=&fctrsc=&brcksc=&plntsc=&entzsc=&mlbsc=&cssc=1*&expKola=1");
});
addAdvisedToBuildSymbol(button, advised);
addDoubleClickProtection(button);
return button;
}
function createButtonGrantExpToGeneral(advised = false) {
const button = createButton("Dotovat generála");
button.addEventListener("click", () => {
sendPost(DOTACE_LINK, dotaceGeneralaCallback, "action=Dotovat&kol=1&typdotaci=11");
});
addAdvisedToBuildSymbol(button, advised);
addDoubleClickProtection(button);
return button;
}
function createButtonBurnLand() {
const button = createButton("Spálit území");
button.addEventListener("click", () => {
sendPost(
DEMOLITION_LINK,
burnLandCallback,
`action=${encodeURIComponent("Zničit budovy")}&vlgsc=&rsdsc=&comsc=&farmsc=&labsc=&fctrsc=&brcksc=&plntsc=&entzsc=&mlbsc=&cssc=&freec=99999`
);
});
addDoubleClickProtection(button);
return button;
}
function addAlternativeReadyingButtons(is_build_stavebka_on, is_exp_general_button_on, is_burn_land_button_on) {
const table = document.getElementById("war-summary");
if (table === null) {
return;
}
const cell = table.rows[0].cells[0];
const dopripravit = cell.children[0];
if (dopripravit == null) {
return;
}
if (dopripravit.value != "Dopřipravit armádu") {
return;
}
const advised_to_build = getAdvisedToBuild();
if (is_build_stavebka_on) cell.appendChild(createButtonPostavitStavebku(advised_to_build));
if (is_exp_general_button_on) cell.appendChild(createButtonGrantExpToGeneral(advised_to_build));
if (is_burn_land_button_on) cell.appendChild(createButtonBurnLand());
}
function getAdvisedToBuild() {
const bonuses_table = document.getElementById("war-bonuses");
if (bonuses_table === null) {
return false;
}
const combat_readiness = -Number(bonuses_table.rows[1].cells[1].innerText.slice(0, -1));
if (combat_readiness < 10) return false;
if (combat_readiness == 10) {
return true;
}
const left_over_readiness = (combat_readiness - 10) % 4;
return left_over_readiness == 1 || left_over_readiness == 0;
}
function dotaceGeneralaCallback(dom) {
const warn_element = dom.getElementsByClassName("warn");
const goodevent_elements = dom.getElementsByClassName("goodevent");
const elements = [];
for (let index = 0; index < goodevent_elements.length; index++) {
if (goodevent_elements[index].textContent.startsWith("Generál")) {
elements.push(goodevent_elements[index]);
}
}
for (let index = 0; index < warn_element.length; index++) {
elements.push(warn_element[index]);
}
addResponse(elements);
}
function buildStavebkuCallback(dom) {
const warn_element = dom.getElementsByClassName("warn")[0];
const goodmsg_element = dom.getElementsByClassName("goodmsg")[0];
addResponse([goodmsg_element, warn_element]);
}
function burnLandCallback(dom) {
let element = dom.getElementsByClassName("infomsg")[0];
addResponse([element]);
}
function addResponse(elements) {
const header = document.getElementsByTagName("h1")[0];
const sibling = header.nextElementSibling;
const icontent = header.parentElement;
for (let index = 0; index < elements.length; index++) {
const element = elements[index];
icontent.insertBefore(element, sibling);
}
}
}
function fetchPage(url, callback) {
return new Promise((resolve) => {
let req = new XMLHttpRequest();
req.open("GET", url);
req.onload = function () {
if (req.readyState == 4 && req.status == 200) {
let parser = new DOMParser();
let doc = parser.parseFromString(req.response, "text/html");
resolve(callback(doc));
}
};
req.send();
});
}
function sendPost(theUrl, callback, params) {
let xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
const dom = new DOMParser().parseFromString(xmlHttp.responseText, "text/html");
callback(dom);
}
};
xmlHttp.open("POST", theUrl, true); // true for asynchronous
xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlHttp.send(params);
}
async function processSpyArchiveForAlliance(button) {
button.textContent = "Probíhá...";
let country_ids = await fetchCountryIds();
button.textContent = `Probíhá... 0 / ${country_ids.length}`;
for (let index = 0; index < country_ids.length; index++) {
const country_id = country_ids[index];
await archive_spy.processSpyArchive(country_id, true, false, false);
updateProgressBackground(button, index, country_ids.length);
}
refreshPage();
}
function updateProgressBackground(button, completed, total) {
button.textContent = "Probíhá ... " + (completed + 1) + " / " + total;
const progress = Math.floor(((completed + 1) / total) * 100);
let background = "chocolate";
if (progress < 100) {
background = `linear-gradient(to right, chocolate ${progress}%, #363636 ${progress}%)`;
}
button.style.background = background;
}
function fetchCountryIds() {
const URL = "index.php?p=detaily&s=detaily&adetaily=true";
return fetchPage(URL, getCountryIdsCallback);
}
function getCountryIdsCallback(doc) {
let country_ids = [];
let table = doc.forms[0].children[0];
for (let i = 1; i < table.rows.length; i++) {
const row = table.rows[i];
const img = row.querySelector("img");
if (img === null) {
continue;
}
const country_id = Number(img.parentElement.href.split("to_id=")[1]);
country_ids.push(country_id);
}
return country_ids;
}
function getCountryStats(country_id) {
const all_country_stats = getSetting(COUNTRY_STATS, []);
if (typeof all_country_stats == "object" && all_country_stats != null && !Array.isArray(all_country_stats)) {
resetStats();
return undefined;
}
return all_country_stats.find((stats) => stats.country_id === country_id);
}
function archiveGetTimeInMillis(time) {
let date = archiveProcessTime(time);
return date.getTime();
}
function archiveProcessTime(time) {
let parts = time.split(" ");
let date_parts = parts[0].split(".");
let date = new Date(date_parts[2], date_parts[1] - 1, date_parts[0]);
let hour_parts = parts[1].split(":");
date.setHours(hour_parts[0], hour_parts[1], hour_parts[2]);
return date;
}
function countryDetailGetCountryId() {
let mail_to = document.querySelector(".vis_tbl td:nth-child(2) a");
return Number(mail_to.href.split("id=")[1]);
}
// TODO - presunout povolene karty, rakety do helperu
function getAliInformation(doc) {
const separator = ",";
const allowed_cards = ["G", "F", "S", "Q", "P", "Z", "R"];
const rocket_cards = ["L", "B", "N"];
const cards_to_replace = {
"?": "Q",
};
const REGIMES = {
Feud: "e",
Demo: "d",
Rep: "r",
Tech: "t",
Fund: "f",
Anar: "a",
Kom: "k",
Dikt: "i",
Utop: "u",
Robo: "b",
};
let cards = new Map(),
regimes = new Map(),
rockets = new Map();
return execute(doc);
function execute(doc) {
const table = getMembersTable(doc);
processTable(table);
const wars = getWarsData(doc);
const cards_result = transformMapToString(cards);
const regimes_result = transformMapToString(regimes);
const rockets_result = transformMapToString(rockets);
return { cards: cards_result, regimes: regimes_result, rockets: rockets_result, wars };
}
function transformMapToString(map) {
let result = Array.from(map, ([key, value]) => ({ key, value }));
result = result.sort((a, b) => b.value - a.value);
return result.reduce((value, current_value) => value + current_value.key + current_value.value + separator, "").slice(0, -1);
}
function processTable(table) {
if (table === null) throw new Error("Není tabulka v detailu aliance");
for (let i = 1; i < table.rows.length - 2; i++) {
processRow(table.rows[i]);
}
}
function processRow(row) {
addRegimeFromRow(row);
processCards(row);
}
function cardName(card) {
return card in cards_to_replace ? cards_to_replace[card] : card;
}
function getWarsData(doc) {
const table = doc.getElementById("find-treaties-wars");
if (!table) return "";
const ali_tag = getAliTag(doc);
const wars = new Map();
for (let i = 1; i < table.rows.length; i++) {
const row = table.rows[i];
const cells = row.cells;
if (cells[0].colSpan > 1) continue; // is war description = skip
const declarant = cells[0].children[0].textContent.trim();
const declaree = cells[0].children[1].textContent.trim();
const ali = ali_tag == declarant ? declaree : declarant;
const age = getDeclarationAge(cells[2].textContent);
if (!wars.has(ali)) {
wars.set(ali, { age });
} else {
const war = wars.get(ali);
war.kotva = true;
war.age = Math.max(war.age, age);
}
}
const war_data = function () {
return { count: 0, kotev: 0 };
};
let wars_simplified = [war_data(), war_data(), war_data(), war_data()];
for (let [, war] of wars) {
const age = Math.min(war.age, 3);
wars_simplified[age].count++;
if (war.kotva) {
wars_simplified[age].kotev++;
}
}
let result = "";
for (let i = 0; i < wars_simplified.length; i++) {
if (wars_simplified[i].count === 0) continue;
result += wars_simplified[i].count + "x" + i + "x" + wars_simplified[i].kotev + ",";
}
result = result.slice(0, -1);
return result;
}
function getDeclarationAge(text) {
const numbers = text.match(/\d+/g);
const day = numbers[0];
const month = numbers[1];
const hours = numbers[2];
const minutes = numbers[3];
const date = new Date();
date.setDate(day);
date.setMonth(month - 1);
date.setHours(hours);
date.setMinutes(minutes);
const current_time = new Date();
if (current_time - date < 0) date.setFullYear(date.getFullYear() - 1);
return Math.floor((current_time - date) / 1000 / 60 / 60 / 24);
}
function getAliTag(doc) {
const table = doc.getElementById("find-alliance-summary");
return table.rows[0].cells[1].textContent.match(/(?<=\[).*(?=\])/g)[0];
}
function processCards(row) {
const cell = row.cells[9];
if (!cell.children) return;
let allowed_types = allowed_cards.concat(rocket_cards);
for (let index = 0; index < cell.children.length; index++) {
const element = cell.children[index];
let card_type = cardName(element.alt.slice(1, -1));
if (allowed_types.indexOf(card_type) == -1) {
continue;
}
let map = cards;
if (rocket_cards.indexOf(card_type) != -1) map = rockets;
let count = map.get(card_type);
if (count === undefined) {
count = 0;
}
map.set(card_type, count + 1);
}
}
function addRegimeFromRow(row) {
const cell = row.cells[6];
const regime = cell.textContent;
let regime_value = REGIMES[regime];
if (regime_value === undefined) {
throw new Error("Neznámá vláda - " + regime);
}
let count = regimes.get(regime_value);
if (count === undefined) {
count = 0;
}
regimes.set(regime_value, count + 1);
}
function getMembersTable(doc) {
return doc.getElementById("alliance-members");
}
}
function modifyAliZebricek() {
if (!getSetting(ALI_ALLOW_CHANGES, true)) return;
const FULL_SEPARATOR = "*||*";
const SEPARATOR = "*|*";
const URL = "index.php?p=najit&s=najittag&tag=";
const EXCEPTION_ALI_TAG = "ADMINS";
const REGIMES = {
e: "Feud",
d: "Demo",
r: "Rep",
t: "Tech",
f: "Fund",
a: "Anar",
k: "Kom",
i: "Dikt",
u: "Utop",
b: "Robo",
};
const show_wars_with_anchors = getSetting(ALI_WARS_WITH_ANCHORS, true);
const filter_buttons = [];
const table_data = [];
execute();
async function execute() {
const table = getTable();
if (table === null) {
return;
}
const saved_information = getAllSavedInformations();
addControls(table, saved_information);
saveDataRows(table, saved_information);
if (getSetting(ALI_SHOW_CARDS, true)) {
addCards(table, saved_information);
}
if (getSetting(ALI_SHOW_REGIME, true)) {
addRegimes(table, saved_information);
}
if (getSetting(ALI_SHOW_ROCKETS, true)) {
addRockets(table, saved_information);
}
if (getSetting(ALI_SHOW_WARS, true)) {
addWars(table, saved_information);
}
if (getSetting(ALI_SHOW_FILTER, true)) {
addFilter();
}
}
function addCards(table, saved_information) {
addColumn(table, saved_information, { header_text: "Kartičky", type: "cards", callback: cardContentCallback });
}
function addRockets(table, saved_information) {
addColumn(table, saved_information, { header_text: "Rakety", type: "rockets", callback: cardContentCallback });
}
function addRegimes(table, saved_information) {
CssHelper.addTooltipCss(60);
addColumn(table, saved_information, { header_text: "Vlády", type: "regimes", callback: regimeContentCallback });
}
function addWars(table, saved_information) {
addColumn(table, saved_information, { header_text: "Války", type: "wars", callback: warsContentCallback });
}
function saveDataRows(table, saved_information) {
if (saved_information.length == 0) return;
for (let index = 1; index < table.rows.length; index++) {
const row = table.rows[index];
const ali_tag = getAliTag(row);
const ali_information = saved_information.filter((ali_information) => ali_information.tag === ali_tag)[0];
if (ali_information === undefined) {
continue;
}
const cards_data = (ali_information.cards + "," + ali_information.rockets).split(",");
const data = [];
cards_data.forEach((card_data) => {
if (card_data.length == 0) return;
const card_type = card_data.slice(0, -1);
const card_count = card_data.slice(-1);
data[card_type] = Number(card_count);
});
table_data.push({
data,
row,
});
}
}
function addFilter() {
let form = getSearchForm();
if (form === null) {
return;
}
CssHelper.addSavedCss(CssHelper.styles.ali_zebricek);
const container = createElement("div", { className: "grid", style: "grid-template-columns: 1fr 1fr 1fr;" });
form.parentElement.insertBefore(container, form);
container.appendChild(createElement());
container.appendChild(form);
const filter_container = createElement("div", { className: "filter_container" });
container.appendChild(filter_container);
filter_container.appendChild(createElement("h2", { textContent: "Filtr kartiček" }));
const header = createElement("div", { className: "row header" });
filter_container.appendChild(header);
header.appendChild(createElement("span", { textContent: "Min" }));
header.appendChild(createElement("span", { textContent: "Max" }));
const keys = Object.keys(ImageHelper.ICONS);
keys.forEach((key) => {
filter_container.appendChild(createFilterRow(key));
});
}
function createFilterRow(key) {
const wrapper = createElement("div", { className: "row" });
const input_min = createNumberInput(key + "_min", 0, 0, 10);
input_min.addEventListener("change", () => filterRows());
wrapper.appendChild(input_min);
const icon = createElement("img", { src: ImageHelper.ICONS[key], alt: key });
wrapper.appendChild(icon);
const input_max = createNumberInput(key + "_max", 10, 0, 10);
input_max.addEventListener("change", () => filterRows());
wrapper.appendChild(input_max);
filter_buttons.push({
min: input_min,
max: input_max,
});
return wrapper;
}
function getSearchForm() {
if (document.forms.length == 0) return null;
return document.forms[0];
}
function filterRows() {
const filter = {};
filter_buttons.forEach((buttons) => {
const type = buttons.min.id.slice(0, 1);
const min = Number(buttons.min.value);
const max = Number(buttons.max.value);
if (min > 0 || max < buttons.max.max) {
filter[type] = { min, max };
}
});
for (let index = 0; index < table_data.length; index++) {
const data = table_data[index];
const row = data.row;
const cards_data = data.data;
if (fitsCriteria(cards_data, filter)) {
row.classList.remove("fits_not");
} else {
row.classList.add("fits_not");
}
}
}
function fitsCriteria(cards_data, filter) {
const keys = Object.keys(filter);
for (let index = 0; index < keys.length; index++) {
const key = keys[index];
const min = filter[key].min;
const max = filter[key].max;
const count = cards_data[key] === undefined ? 0 : cards_data[key];
if (count < min || count > max) {
return false;
}
}
return true;
}
function addColumn(table, saved_information, { header_text, type, callback }) {
const th = createElement("th", { textContent: header_text });
table.rows[0].appendChild(th);
for (let index = 1; index < table.rows.length; index++) {
const row = table.rows[index];
const ali_tag = getAliTag(row);
const ali_information = saved_information.filter((ali_information) => ali_information.tag === ali_tag)[0];
const cell = row.insertCell();
if (ali_information === undefined) {
cell.textContent = "chybí";
row.classList.add("not_fetched");
continue;
}
if (ali_information[type] === "") {
continue;
}
let data = ali_information[type].split(",");
callback(cell, data);
}
}
function cardContentCallback(cell, data) {
for (let index = 0; index < data.length; index++) {
const value = data[index];
const count = Number(value.slice(1));
cell.appendChild(createElement("span", { textContent: count + "x " }));
const icon_type = value.slice(0, 1);
const icon = createElement("img", { src: ImageHelper.ICONS[icon_type], style: "margin-right: 5px; " });
cell.appendChild(icon);
}
}
function regimeContentCallback(cell, data) {
const icon = createElement("span", { textContent: "?", className: "tooltip icon" });
cell.appendChild(icon);
cell.classList.add("c");
const wrapper = createElement("div", { className: "tooltiptext" });
icon.appendChild(wrapper);
for (let index = 0; index < data.length; index++) {
const value = data[index];
const count = Number(value.slice(1));
const regime = REGIMES[value.slice(0, 1)];
wrapper.appendChild(createElement("p", { textContent: count + "x " + regime }));
}
}
function warsContentCallback(cell, data) {
const background_colors = ["rgb(0, 255, 0)", "rgb(255, 255, 0)", "rgb(255, 128, 0)", "rgb(0, 0, 0)"];
let war_count = 0;
const age_values = ["<24", "24-48", "48-72", ">72"];
for (let index = 0; index < data.length; index++) {
const parts = data[index].split("x");
const count = Number(parts[0]);
war_count += count;
const days = Number(parts[1]);
const kotev = Number(parts[2]);
const age = age_values[days];
const background_color = background_colors[days];
const color = days == 3 ? "color: white;" : "";
const props = {
className: "icon",
style: `background:${background_color}; ${color}`,
};
let anchor_element = null;
if (show_wars_with_anchors) {
if (count > kotev) {
props.textContent = count - kotev;
props.title = count - kotev + "x " + age;
}
if (kotev > 0) {
anchor_element = createElement("span", {
textContent: kotev,
className: "icon",
title: "Zakotveno: " + kotev + "x " + age,
style: `background: linear-gradient(135deg, ${background_color} 50%, #99F 50%); ${color})`,
});
}
} else {
props.textContent = count;
props.title = count + "x " + age + ", z toho zakotveno: " + kotev;
}
if (props.textContent !== undefined) {
cell.appendChild(createElement("span", props));
}
if (anchor_element) {
cell.appendChild(anchor_element);
}
}
cell.prepend(createElement("span", { textContent: war_count, className: "icon war_count", title: `Celkem: ${war_count} ${war_count == 1 ? "válka" : "války"}` }));
}
async function resetAllInformations() {
setSetting(ALI_SAVED_INFO, "");
refreshPage();
}
function getAliTagsFromRows(rows) {
let ali_tags = [];
for (let index = 0; index < rows.length; index++) {
const row = rows[index];
const ali_tag = getAliTag(row);
ali_tags.push(ali_tag);
}
return ali_tags;
}
async function fetchInformationForAliances(ali_tags, button) {
let data = [];
const length = ali_tags.length;
for (let index = 0; index < length; index++) {
if (ali_tags[index] === EXCEPTION_ALI_TAG) {
updateProgressBackground(button, index, length);
continue;
}
const result = await fetchInformationForAnAliance(ali_tags[index]);
data.push(result);
updateProgressBackground(button, index, length);
}
return data;
}
function removeDuplicates(saved_information, ali_tags) {
for (let index = 0; index < ali_tags.length; index++) {
const tag = ali_tags[index];
const found_index = saved_information.findIndex((card) => card.tag === tag, tag);
if (found_index !== -1) {
saved_information.splice(found_index, 1);
}
}
return saved_information;
}
function saveInformation(saved_information, new_ali_information, ali_tags = null, remove_duplicates = false) {
if (remove_duplicates) {
saved_information = removeDuplicates(saved_information, ali_tags);
}
let result = "";
if (saved_information.length > 0) {
result = saved_information.reduce(
(acc, information) =>
acc + information.tag + SEPARATOR + information.cards + SEPARATOR + information.regimes + SEPARATOR + information.rockets + SEPARATOR + information.wars + FULL_SEPARATOR,
""
);
}
result += new_ali_information.join(FULL_SEPARATOR);
result.slice(0, -FULL_SEPARATOR.length);
setSetting(ALI_SAVED_INFO, result);
refreshPage();
}
async function fetchMissingInformations({ table, saved_information }, e) {
const rows = table.querySelectorAll(".not_fetched");
const ali_tags = getAliTagsFromRows(rows);
let ali_Information = await fetchInformationForAliances(ali_tags, e.target);
saveInformation(saved_information, ali_Information);
}
async function refreshAllInformations({ table, saved_information }, e) {
let rows = Array.from(table.rows);
rows.shift();
const ali_tags = getAliTagsFromRows(rows);
let ali_Information = await fetchInformationForAliances(ali_tags, e.target);
saveInformation(saved_information, ali_Information, ali_tags, true);
}
function getAllSavedInformations() {
let saved_information = getSetting(ALI_SAVED_INFO, "");
if (saved_information.length === 0) {
return [];
}
saved_information = saved_information.split(FULL_SEPARATOR);
const ali_informations = [];
for (let index = 0; index < saved_information.length; index++) {
const cards = saved_information[index];
const parts = cards.split(SEPARATOR);
const formatted_cards = {
tag: parts[0],
cards: parts[1],
regimes: parts[2],
rockets: parts[3],
wars: parts[4],
};
ali_informations.push(formatted_cards);
}
return ali_informations;
}
function addControls(table, saved_information) {
const h1 = document.getElementsByTagName("h1")[0];
const container = createElement("div", { style: "text-align: end" });
h1.parentElement.insertBefore(container, h1.nextSibling);
container.appendChild(createButton("Získat informace pro chybějící aliance", fetchMissingInformations, { table, saved_information }));
container.appendChild(createButton("Získat informace o aliancích pro tuto stránku", refreshAllInformations, { table, saved_information }));
container.appendChild(createButton("Smazat všechna data o aliancích", () => resetAllInformations()));
}
function getTable() {
const tables = document.getElementsByClassName("vis_tbl");
if (tables.length == 0) {
return null;
}
for (let index = 0; index < tables.length; index++) {
if (tables[index].rows[0].cells[1].textContent === "Aliance") {
return tables[index];
}
}
return null;
}
function getAliTag(row) {
return row.cells[1].textContent.match(/(?<=\[).+(?=\])/)[0];
}
async function fetchInformationForAnAliance(ali_tag) {
const results = await fetchPage(URL + ali_tag, getAliInformation);
return ali_tag + SEPARATOR + results.cards + SEPARATOR + results.regimes + SEPARATOR + results.rockets + SEPARATOR + results.wars;
}
}
//
function resetStats() {
setSetting(COUNTRY_STATS, []);
refreshPage();
}
function refreshPage() {
window.location.replace(location.href);
}
function getCurrentTimeInMillis() {
return new Date().getTime();
}
function isGameOver() {
let table = document.querySelector(".container .vis_tbl");
if (!table) {
return false;
}
return table.rows[0].children[0].innerText == "Věk skončil";
}
function getEnumLength(myEnum) {
return Object.keys(myEnum).length;
}
function getEnumKeyByEnumValue(myEnum, enumValue) {
const keys = Object.keys(myEnum).filter((x) => myEnum[x] == enumValue);
return keys.length > 0 ? keys[0] : null;
}
class ArmyUnit {
count;
name;
base_wage;
base_food_consumption;
base_energy_consumption;
prestige;
total_prestige;
wages_total;
expenses_total;
expenses_per_unit;
expenses_per_prestige_point;
attack;
defense;
constructor(name, count, prestige, attack = 0, defense = 0) {
this.name = name;
this.count = count;
this.prestige = prestige;
this.total_prestige = prestige * count;
this.attack = attack;
this.defense = defense;
}
setCount(count) {
this.count = count;
this.total_prestige = this.prestige * count;
}
}
const UNITS = {
vojaci: new ArmyUnit("Vojáci", 0, 1, 1, 1),
tanky: new ArmyUnit("Tanky", 0, 5, 6, 4),
stihacky: new ArmyUnit("Stíhačky", 0, 3.5, 6, 0),
bunkry: new ArmyUnit("Bunkry", 0, 3.5, 0, 6),
mechy: new ArmyUnit("Mechy", 0, 2.7, 2, 3),
agenti: new ArmyUnit("Agenti", 0, 15),
penize: new ArmyUnit("Peníze", 0, 0.002),
jidlo: new ArmyUnit("Jídlo", 0, 0.02),
energie: new ArmyUnit("Energie", 0, 0.02),
uzemi: new ArmyUnit("Uzemi", 0, 15),
budovy: new ArmyUnit("Budovy", 0, 5),
budovy_na_ruiny: new ArmyUnit("Budovy Na Ruiny", 0, 3),
ruiny: new ArmyUnit("Ruiny", 0, 2),
technologie: new ArmyUnit("Technologie", 0, 1),
get(unit_name, count = 0) {
const unit = this[unit_name];
unit.setCount(count);
return unit;
},
};
class AdvancementHelper {
static get types() {
return Object.freeze({
T: "T",
K: "K",
"K-": "K-",
S: "S",
});
}
static get maxReduction() {
return {
T: {
reduction: 80,
countries: 80,
},
K: {
reduction: 60,
countries: 300,
},
};
}
static get advancementExceptions() {
return {
"Fúzní elektrárny": {
base_price: 400000,
minimum_price: 160000,
not_affected_by_difficulty: true,
},
"Nejvyšší budova světa": {
base_price: 4000000,
minimum_price: 4000000,
per_country_price: 50000,
},
"Vojenská akademie": {
base_price: 1000,
minimum_price: 1000,
per_country_price: 2,
cap_price: 4000,
},
};
}
}
class ImageHelper {
static get ICONS() {
return {
F: "img/f.gif",
S: "img/x.gif",
P: "img/p.gif",
G: "img/gv.gif",
R: "img/r.gif",
Q: "img/q.gif",
Z: "img/z.gif",
L: "img/l.gif",
B: "img/b.gif",
N: "img/n.gif",
};
}
}
class CssHelper {
static get styles() {
return {
ali_zebricek: `
.vis_tbl tr:first-child {
position: sticky;
top: 0;
z-index: 1;
}
.grid {
display: grid;
gap: 1rem;
}
.filter_container h2 {
border-bottom: 1px solid white;
margin-bottom: 0.5rem;
font-size: 1.5rem;
text-transform: inherit;
letter-spacing: 1.5px;
}
.filter_container input {
padding: 1px 0 1px 4px;
margin: 0 0.5rem;
}
.row {
width: fit-content;
margin: auto;
padding: 0.1rem;
}
.header {
width: 160px;
display: flex;
justify-content: space-around;
font-weight: bold;
}
.row img {
vertical-align: sub;
}
tr.fits_not td {
background: rgb(160, 20, 20);
}
.icon.war_count {
border-radius: unset;
margin-right: 0.25rem;
}
`,
archive: `
.row {
display: grid;
gap: 1rem;
grid-template-columns: 5fr 4fr 4fr;
}
.row span:first-child {
font-weight: bold;
}
.row span:not(:first-child) {
text-align: right;
}
`,
infiltration: `
.row {
display: grid;
gap: 1rem;
grid-template-columns: 4fr 1fr;
}
.row span:first-child {
font-weight: bold;
}
.row span:not(:first-child) {
text-align: right;
}
`,
settings: `
.icon {
display: inline-block;
width: 16px;
height: 16px;
border: 1px solid black;
border-radius: 10px;
background: #aff;
color: black;
font-weight: bold;
text-align: center;
}
button.btn {
width: fit-content;
border-radius: 2px;
cursor: pointer;
font-weight: bold;
text-shadow: 0 0 5px black;
-webkit-transition: background-color 200ms ease-in-out;
-ms-transition: background-color 200ms ease-in-out;
transition: background-color 200ms ease-in-out, box-shadow 200ms ease-in-out;
}
.btn:hover {
background-color: #777;
box-shadow: 0 0 5px white;
}
.btn.btn-close {
position: absolute;
top: 10px;
right: 5px;
}
.btn.btn-refresh {
position: absolute;
bottom: 5px;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
width: fit-content;
}
.overlay {
position: fixed;
height: 100%;
width: 100%;
background: black;
opacity: 0.3;
top: 0;
left: 0;
z-index: 2;
}
.settings_window {
-webkit-columns: 2 auto;
-moz-columns: 2 auto;
columns: 2 auto;
-webkit-column-gap: 1em;
-moz-column-gap: 1em;
column-gap: 1em;
z-index: 1000;
position: fixed;
padding: 10px 10px 35px 10px;
top: 130px;
left: 150px;
background: #666;
border: 1px solid #aaa;
border-radius: 5px;
}
.block {
display: flex;
flex-direction: column;
gap: 1px;
margin-bottom: 10px;
border: 1px solid;
border-top-color: #fff;
border-right-color: #aaa;
border-bottom-color: #999;
border-left-color: #aaa;
padding: 0.5rem;
background: #555;
break-inside: avoid-column;
}
.settings_window label {
width: fit-content;
text-shadow: 1px 1px 4px black;
}
.settings_window h3 {
margin: 0 0 6px 0;
font-weight: bold;
text-shadow: 0 0 5px black;
}
.settings_window input {
margin-right: 10px;
box-shadow: 3px 3px #555;
}
.settings_window input[type=checkbox] {
cursor: pointer;
}
.settings_window input[type=number] {
width: 8ch;
}
.hidden {
display: none;
}
`,
tooltip: `
.tooltip { position: relative; }
.tooltip .tooltiptext {
visibility: hidden;
width: $tooltip_width$px;
top: 100%;
left: $left$%;
margin-left: -$margin_left$px;
background-color: #363636;
color: #fff;
text-align: left;
padding: 5px 5px;
margin-top: 10px;
border-radius: 6px;
border: 1px solid white;
position: absolute;
z-index: 1;
}
.tooltip .tooltiptext.center { text-align: center; }
.tooltip:hover .tooltiptext { visibility: visible; }
.tooltip .tooltiptext::after {
content: ' ';
position: absolute;
bottom: 100%;
left: $arrow_left$%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent white transparent;
}
.tooltiptext .header { font-weight: bold; border-bottom: 1px solid white; }
.tooltiptext .divider { height: 1px; width: 100%; border-bottom: 1px solid white; }
`,
strike: `
input[type=submit].disabled { background: red; border-color: black; }
button.submit:disabled {
filter: blur(0.75px);
}
`,
};
}
static addTooltipCss(tooltip_width = 100, to_left = false, move_to_left_percentage = 75) {
const margin_left = to_left ? (tooltip_width * move_to_left_percentage) / 100 : tooltip_width / 2;
const left = to_left ? move_to_left_percentage : 50;
const arrow_left = to_left ? (50 + left) / 2 : 50;
this.addSavedCss(CssHelper.styles.tooltip, { tooltip_width, margin_left, left, arrow_left });
}
static addSavedCss(css, values_to_replace = {}) {
css = Object.keys(values_to_replace).reduce((acc, key) => {
return acc.replaceAll(`$${key}$`, values_to_replace[key]);
}, css);
CssHelper.addCss(css);
}
static addCss(css) {
let style = document.createElement("style");
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
document.getElementsByTagName("head")[0].appendChild(style);
}
}
execute();
//
})();