22 Commits

Author SHA1 Message Date
53c2c2e7e3 Fix bug on attack calculator
Some checks failed
Continuous Deployment / lint (push) Successful in 32s
Continuous Deployment / deploy-chrome (push) Failing after 19s
Continuous Deployment / deploy-firefox (push) Successful in 4m2s
2025-12-03 23:05:38 +01:00
0d369c4c1e Add calculator form to new tab
Some checks failed
Continuous Deployment / lint (push) Successful in 29s
Continuous Deployment / deploy-chrome (push) Failing after 17s
Continuous Deployment / deploy-firefox (push) Successful in 3m22s
2025-11-29 12:31:00 +01:00
ede3ce1f0b Fix several bugs and refacto
Some checks failed
Continuous Deployment / lint (push) Successful in 30s
Continuous Deployment / deploy-chrome (push) Failing after 20s
Continuous Deployment / deploy-firefox (push) Successful in 3m9s
2025-11-28 19:11:21 +01:00
5b075f057e Fix market target bug 2025-11-28 10:30:53 +01:00
8d8ccd8e9d Add player id in ranking and ally members
Some checks failed
Continuous Deployment / lint (push) Successful in 30s
Continuous Deployment / deploy-chrome (push) Failing after 21s
Continuous Deployment / deploy-firefox (push) Successful in 4m38s
2025-11-24 19:04:59 +01:00
9a3c9c1401 Send resources by thousands
Some checks failed
Continuous Deployment / lint (push) Successful in 27s
Continuous Deployment / deploy-chrome (push) Failing after 17s
Continuous Deployment / deploy-firefox (push) Successful in 1m42s
2025-11-20 02:07:53 +01:00
067b1ef385 Code simplification
All checks were successful
Continuous Deployment / lint (push) Successful in 26s
Continuous Deployment / deploy-chrome (push) Successful in 33s
Continuous Deployment / deploy-firefox (push) Successful in 2m51s
2025-11-18 20:36:46 +01:00
fe33b9a334 Add button to select all units
All checks were successful
Continuous Deployment / lint (push) Successful in 27s
Continuous Deployment / deploy-chrome (push) Successful in 33s
Continuous Deployment / deploy-firefox (push) Successful in 3m42s
2025-11-18 10:50:35 +01:00
255ca528a5 Add tenth of seconds in attack sending page
All checks were successful
Continuous Deployment / lint (push) Successful in 26s
Continuous Deployment / deploy-chrome (push) Successful in 30s
Continuous Deployment / deploy-firefox (push) Successful in 5m27s
2025-11-17 19:22:39 +01:00
b843fa1b26 fix bug with search regex
All checks were successful
Continuous Deployment / lint (push) Successful in 27s
Continuous Deployment / deploy-chrome (push) Successful in 34s
Continuous Deployment / deploy-firefox (push) Successful in 5m42s
2025-11-16 12:53:44 +01:00
aa07f2827b Use server time for computing seconds
Some checks failed
Continuous Deployment / lint (push) Successful in 28s
Continuous Deployment / deploy-chrome (push) Failing after 19s
Continuous Deployment / deploy-firefox (push) Successful in 1m34s
2025-11-16 03:43:13 +01:00
c21ddb517c Fix bug on attack seconds
All checks were successful
Continuous Deployment / deploy-chrome (push) Successful in 34s
Continuous Deployment / deploy-firefox (push) Successful in 1m52s
Continuous Deployment / lint (push) Successful in 27s
2025-11-16 03:27:46 +01:00
ef16412a99 Update changelog
All checks were successful
Continuous Deployment / lint (push) Successful in 27s
Continuous Deployment / deploy-chrome (push) Successful in 33s
Continuous Deployment / deploy-firefox (push) Successful in 1m8s
2025-11-16 02:38:32 +01:00
622cbd817d Add calculator button in ally attacks 2025-11-16 02:27:08 +01:00
6e1bcf85f9 Add seconds in ally attacks page 2025-11-16 01:58:02 +01:00
f841780ed9 Fix bug select in market
All checks were successful
Continuous Deployment / lint (push) Successful in 28s
Continuous Deployment / deploy-chrome (push) Successful in 32s
Continuous Deployment / deploy-firefox (push) Successful in 1m50s
2025-11-15 13:17:40 +01:00
c22c2fb254 Feature multi-attack in same second
All checks were successful
Continuous Deployment / lint (push) Successful in 26s
Continuous Deployment / deploy-chrome (push) Successful in 32s
Continuous Deployment / deploy-firefox (push) Successful in 5m36s
2025-11-13 20:13:50 +01:00
4fe2922e5a Fix display navbar with reports
All checks were successful
Continuous Deployment / lint (push) Successful in 26s
Continuous Deployment / deploy-chrome (push) Successful in 31s
Continuous Deployment / deploy-firefox (push) Successful in 2m43s
2025-11-13 10:31:12 +01:00
4f1d5442be Continuous deployment on Chrome
Some checks failed
Continuous Deployment / lint (push) Successful in 28s
Continuous Deployment / deploy-chrome (push) Successful in 31s
Continuous Deployment / deploy-firefox (push) Failing after 26s
2025-11-13 01:17:56 +01:00
45d5200e61 Fix bug menu
All checks were successful
Continuous Deployment / lint (push) Successful in 29s
Continuous Deployment / deploy (push) Successful in 5m8s
2025-11-11 23:39:57 +01:00
10de4507af Add data collection permissions
All checks were successful
Continuous Deployment / lint (push) Successful in 30s
Continuous Deployment / deploy (push) Successful in 56s
2025-11-11 17:34:00 +01:00
a37d54cd2e Fix metadata.json format
All checks were successful
Continuous Deployment / lint (push) Successful in 30s
Continuous Deployment / deploy (push) Successful in 3m20s
2025-11-11 16:36:50 +01:00
8 changed files with 698 additions and 95 deletions

View File

@@ -14,13 +14,28 @@ jobs:
- name: Run linter - name: Run linter
run: make lint run: make lint
deploy: deploy-chrome:
needs: lint
runs-on: linux runs-on: linux
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@v5 uses: actions/checkout@v5
- name: Deploy project - name: Deploy project to Chrome Webstore
env: env:
WEB_EXT_API_KEY: ${{ vars.WEB_EXT_API_KEY }} CLIENT_ID: ${{ vars.CHROME_CLIENT_ID }}
WEB_EXT_API_SECRET: ${{ secrets.WEB_EXT_API_SECRET }} CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }}
run: make deploy EXTENSION_ID: ${{ vars.CHROME_EXTENSION_ID }}
REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }}
run: make deploy_chrome
deploy-firefox:
needs: lint
runs-on: linux
steps:
- name: Checkout repo
uses: actions/checkout@v5
- name: Deploy project to Firefox Addons
env:
WEB_EXT_API_KEY: ${{ vars.FIREFOX_API_KEY }}
WEB_EXT_API_SECRET: ${{ secrets.FIREFOX_API_SECRET }}
run: make deploy_firefox

View File

@@ -1,5 +1,92 @@
# Changelog # Changelog
## 1.11.4 (2026-12-03)
- correction du bug sur le calculateur
## 1.11.3 (2026-11-21)
- ajout du calculateur de trajet vers un nouvel onglet
## 1.11.2 (2026-11-28)
- correction du bug sur les multiples attaques avec comte
- correction du bug sur le bouton pour sélectionner toutes les troupes
- correction du bug sur l'envoi de ressources vers un village cible
- ajout des ids dans la liste des joueurs d'une alliance
- ajout de l'id sur le profil d'un joueur
## 1.11.1 (2026-11-24)
- ajout de l'id des joueurs dans le classement général et la liste des membres de l'alliance
## 1.10.1 (2026-11-20)
- envoi des ressources par milliers sur le marché
## 1.9.2 (2025-11-18)
- simplification du code
## 1.9.1 (2025-11-18)
- ajout d'un bouton pour sélectionner toutes les troupes
## 1.8.1 (2025-11-17)
- remplacement de 'attaques' par 'occurrences'
- correction du calcul d'arrivée des unités
- ajout des dizièmes de seconde pour envoyer des unités
## 1.7.4 (2025-11-16)
- correction bug de calcul des secondes en utilisant search regex
## 1.7.3 (2025-11-16)
- correction bug de calcul des secondes en utilisant le temps du serveur
## 1.7.2 (2025-11-16)
- correction bug de calcul des secondes sur la page des attaques
## 1.7.1 (2025-11-16)
- ajout des secondes dans la page des attaques
- ajout d'un lien vers le calculateur de trajet dans la page des attaques
## 1.6.1 (2025-11-15)
- correction du bug de sélection de village dans le marché
## 1.5.1 (2025-11-13)
- fonctionnalité de multi-attaques dans la même seconde
## 1.4.14 (2025-11-13)
- correction affichage menu avec rapports
## 1.4.13 (2025-11-13)
- déploiement automatique sur chrome
## 1.4.12 (2025-11-11)
- correction bug menu
## 1.4.11 (2025-11-11)
- ajout des data collection permissions
## 1.4.10 (2025-11-11)
- correction du fichier metadata.json
## 1.4.9 (2025-11-11)
- test déploiement manuel
## 1.4.8 (2025-11-11) ## 1.4.8 (2025-11-11)
- suppression de data_collection_permissions car non supporté pour Android - suppression de data_collection_permissions car non supporté pour Android

View File

@@ -3,8 +3,11 @@ build:
lint: lint:
web-ext lint web-ext lint
deploy_chrome:
chrome-webstore-upload
deploy: deploy_firefox:
web-ext sign --channel listed --amo-metadata metadata.json web-ext sign --channel listed --amo-metadata metadata.json
help: help:

1
images/blank.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path fill="#000000" d="M416.5 88L416.5 160L352.5 160C273 160 208.5 224.5 208.5 304C208.5 397.4 291.3 438.8 309.1 446.6C311.3 447.6 313.7 448 316.2 448L318.7 448C328.5 448 336.5 440 336.5 430.2C336.5 421.9 330.6 414.7 323.7 409.9C314.8 403.7 304.5 391.7 304.5 369.4C304.5 324.4 341 287.9 386 287.9L416.5 287.9L416.5 359.9C416.5 369.6 422.3 378.4 431.3 382.1C440.3 385.8 450.6 383.8 457.5 376.9L593.5 240.9C602.9 231.5 602.9 216.3 593.5 207L457.5 71C450.6 64.1 440.3 62.1 431.3 65.8C422.3 69.5 416.5 78.3 416.5 88zM144.5 160C100.3 160 64.5 195.8 64.5 240L64.5 496C64.5 540.2 100.3 576 144.5 576L400.5 576C444.7 576 480.5 540.2 480.5 496L480.5 464C480.5 446.3 466.2 432 448.5 432C430.8 432 416.5 446.3 416.5 464L416.5 496C416.5 504.8 409.3 512 400.5 512L144.5 512C135.7 512 128.5 504.8 128.5 496L128.5 240C128.5 231.2 135.7 224 144.5 224L160.5 224C178.2 224 192.5 209.7 192.5 192C192.5 174.3 178.2 160 160.5 160L144.5 160z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

1
images/calculator.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path fill="#000000" d="M192 64C156.7 64 128 92.7 128 128L128 512C128 547.3 156.7 576 192 576L448 576C483.3 576 512 547.3 512 512L512 128C512 92.7 483.3 64 448 64L192 64zM224 128L416 128C433.7 128 448 142.3 448 160L448 192C448 209.7 433.7 224 416 224L224 224C206.3 224 192 209.7 192 192L192 160C192 142.3 206.3 128 224 128zM240 296C240 309.3 229.3 320 216 320C202.7 320 192 309.3 192 296C192 282.7 202.7 272 216 272C229.3 272 240 282.7 240 296zM320 320C306.7 320 296 309.3 296 296C296 282.7 306.7 272 320 272C333.3 272 344 282.7 344 296C344 309.3 333.3 320 320 320zM448 296C448 309.3 437.3 320 424 320C410.7 320 400 309.3 400 296C400 282.7 410.7 272 424 272C437.3 272 448 282.7 448 296zM216 416C202.7 416 192 405.3 192 392C192 378.7 202.7 368 216 368C229.3 368 240 378.7 240 392C240 405.3 229.3 416 216 416zM344 392C344 405.3 333.3 416 320 416C306.7 416 296 405.3 296 392C296 378.7 306.7 368 320 368C333.3 368 344 378.7 344 392zM424 416C410.7 416 400 405.3 400 392C400 378.7 410.7 368 424 368C437.3 368 448 378.7 448 392C448 405.3 437.3 416 424 416zM192 488C192 474.7 202.7 464 216 464L328 464C341.3 464 352 474.7 352 488C352 501.3 341.3 512 328 512L216 512C202.7 512 192 501.3 192 488zM424 464C437.3 464 448 474.7 448 488C448 501.3 437.3 512 424 512C410.7 512 400 501.3 400 488C400 474.7 410.7 464 424 464z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,14 +1,23 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "KAplus", "name": "KAplus",
"version": "1.4.8", "version": "1.11.4",
"author": "Samuel Campos - netoik.io", "developer": {
"name": "Samuel Campos",
"url": "https://git.netoik.io/samuel/kaplus"
},
"description": "Extension développée pour améliorer l'expérience de jeu KingsAge (fonctionne avec ou sans premium)", "description": "Extension développée pour améliorer l'expérience de jeu KingsAge (fonctionne avec ou sans premium)",
"browser_specific_settings": { "browser_specific_settings": {
"gecko": { "gecko": {
"id": "{e750d6a9-86ff-4129-aed6-542de03deb79}" "id": "{e750d6a9-86ff-4129-aed6-542de03deb79}",
"data_collection_permissions": {
"required": [
"websiteContent",
"websiteActivity"
]
}
} }
}, },

View File

@@ -1,9 +1,12 @@
{ {
"compatibility": [ "version": {
"android", "compatibility": [
"firefox" "android",
], "firefox"
"release_notes": { ],
"fr": "- suppression de data_collection_permissions car non supporté pour Android" "release_notes": {
"fr": "- correction du bug sur le calculateur",
"en-US": "- fix bug on attack calculator"
}
} }
} }

View File

@@ -1,3 +1,8 @@
let tomorrow = new Date(new Date().getTime() + 24*60*60*1000);
tomorrow.setHours(0, 0, 0, 0);
let afterTomorrow = new Date(tomorrow.getTime() + 24*60*60*1000);
let movingDuration = 0;
function num(s) { function num(s) {
return parseInt(s.replace(".", "")); return parseInt(s.replace(".", ""));
} }
@@ -18,117 +23,596 @@ function str(n) {
return s.replace(/^0+/, ""); return s.replace(/^0+/, "");
} }
function createRow(key, value) { function createCustomElement(tag, attrs, text, style) {
let keyCell = document.createElement("td"); let elt = document.createElement(tag);
keyCell.textContent = key; if (attrs) {
for (let [key, value] of Object.entries(attrs)) {
if (value !== null) {
elt.setAttribute(key, value.toString());
}
}
}
if (text) {
elt.textContent = text.toString();
}
if (style) {
for (let [key, value] of Object.entries(style)) {
elt.style[key] = value.toString();
}
}
return elt;
}
let valueCell = document.createElement("td"); function createCustomInput(type, name, value, attrs, style) {
valueCell.textContent = value; let mergedAttrs = {};
if (attrs) {
mergedAttrs = attrs;
}
mergedAttrs["type"] = type;
if (name) {
mergedAttrs["name"] = name;
}
if (value) {
mergedAttrs["value"] = value;
}
return createCustomElement("input", mergedAttrs, null, style);
}
let row = document.createElement("tr"); function createKeyValueRow(key, value) {
let row = createCustomElement("tr");
let keyCell = createCustomElement("td", null, key);
let valueCell = createCustomElement("td", null, value);
row.appendChild(keyCell); row.appendChild(keyCell);
row.appendChild(valueCell); row.appendChild(valueCell);
return row; return row;
} }
function searchPoint(text) {
let index = text.search(/\d{3}\|\d{3}/);
let point = text.slice(index, index + 7).split("|");
return {x: point[0], y: point[1]}
}
function shortcutElementReplace(elt, img, text) { function shortcutElementReplace(elt, img, text) {
let imgElements = elt.getElementsByTagName("img"); // If more than one hyperlink element found,
for (let i=0; i<imgElements.length; i++) { // then keep the last one but with href of the first one.
if (i === 0) { let aElements = elt.getElementsByTagName("a");
elt.getElementsByTagName("a")[0].classList.add("has_notif"); let imgElements = elt.getElementsByTagName("img");
} if (aElements.length > 1 || imgElements.length > 0) {
imgElements[i].remove(); aElements[aElements.length - 1].classList.add("has_notif");
i --; aElements[aElements.length - 1].setAttribute("href", aElements[0].getAttribute("href"));
} for (let i = imgElements.length - 1; i >= 0; i--) {
imgElements[i].remove();
}
for (let i = aElements.length - 2; i >= 0; i--) {
aElements[i].remove();
}
}
let aElements = elt.getElementsByTagName("a"); let spanImageElement = createCustomElement("span", {"class": "shortcut_element_image"});
for (i=0; i<aElements.length; i++) { let imgElement = createCustomElement("img", {"src": chrome.runtime.getURL("images/" + img + ".svg")});
if (i > 0) { spanImageElement.appendChild(imgElement);
aElements[i].remove();
i --;
}
}
let spanImageElement = document.createElement("span");
spanImageElement.classList.add("shortcut_element_image");
let imgElement = document.createElement("img"); aElements[0].textContent = "";
imgElement.setAttribute("src", chrome.runtime.getURL("images/"+img+".svg")); aElements[0].appendChild(spanImageElement);
spanImageElement.appendChild(imgElement);
aElements[0].textContent = ""; if (text) {
aElements[0].appendChild(spanImageElement); let spanDescElement = createCustomElement("span", {"class": "shortcut_element_desc"}, text);
aElements[0].appendChild(spanDescElement);
if (text) { }
let spanDescElement = document.createElement("span");
spanDescElement.classList.add("shortcut_element_desc");
spanDescElement.textContent = text;
aElements[0].appendChild(spanDescElement);
}
} }
/* Improve main menu display */ function customizeNavbar(layCastleElement) {
let layCastleTopElements = document.getElementsByClassName("lay_castle_top"); /* Improve navbar icons */
if (layCastleTopElements.length === 1) { let shortcutElements = layCastleElement.getElementsByClassName("shortcut_element");
document.getElementById("banner_skyscraper").remove(); shortcutElementReplace(shortcutElements[0], "ranking", shortcutElements[0].textContent.replace(/[^0-9]/g, ""));
shortcutElementReplace(shortcutElements[1], "ally", "");
shortcutElementReplace(shortcutElements[2], "profile", "");
shortcutElementReplace(shortcutElements[3], "premium", "");
shortcutElementReplace(shortcutElements[4], "messages", "");
shortcutElementReplace(shortcutElements[5], "tools", "");
shortcutElementReplace(shortcutElements[6], "favorites", "");
let shortcutElements = layCastleTopElements[0].getElementsByClassName("shortcut_element"); /* Center navbar */
shortcutElementReplace(shortcutElements[0], "ranking", shortcutElements[0].textContent.replace(/[^0-9]/g, "")); let shortcutContainers = layCastleElement.getElementsByClassName("shortcut_container");
shortcutElementReplace(shortcutElements[1], "ally", ""); shortcutContainers[0].classList.add("shortcut_container_left");
shortcutElementReplace(shortcutElements[2], "profile", ""); shortcutContainers[2].classList.add("shortcut_container_right");
shortcutElementReplace(shortcutElements[3], "premium", "");
shortcutElementReplace(shortcutElements[4], "messages", "");
shortcutElementReplace(shortcutElements[5], "tools", "");
shortcutElementReplace(shortcutElements[6], "favorites", "");
let shortcutContainers = layCastleTopElements[0].getElementsByClassName("shortcut_container");
shortcutContainers[0].classList.add("shortcut_container_left");
shortcutContainers[2].classList.add("shortcut_container_right");
} }
/* Display unit-points on user profile */ function countUpMs() {
if (document.body.id === "info_player") { let arrivalDate = new Date(new Date().getTime() + movingDuration * 1000);
let mainContentPane = document.getElementsByClassName("contentpane")[1]; let prefix = "";
let borderLists = mainContentPane.getElementsByClassName("borderlist"); if (arrivalDate >= afterTomorrow) {
prefix = "le " + arrivalDate.getDate() + "." + arrivalDate.getMonth() + " ";
let playerPropertiesTable = borderLists[0]; } else if (arrivalDate > tomorrow) {
let playerPropertiesRows = playerPropertiesTable.getElementsByTagName("tr"); prefix = "demain ";
let totalPoints = num(playerPropertiesRows[2].getElementsByTagName("td")[1].textContent); }
let villagesCount = num(playerPropertiesRows[4].getElementsByTagName("td")[1].textContent); document.getElementById("countup-time-ms").textContent = prefix
+ "à "
+ arrivalDate.getHours().toString().padStart(2, "0")
+ ":"
+ arrivalDate.getMinutes().toString().padStart(2, "0")
+ ":"
+ arrivalDate.getSeconds().toString().padStart(2, "0")
+ ":"
+ Math.floor(arrivalDate.getMilliseconds() / 100);
}
function removeAdsBanner() {
/* Remove iframe banner */
document.getElementById("banner_skyscraper").remove();
}
function showPlayersId() {
/* Add a column with player id */
let mainContentPane = document.getElementsByClassName("contentpane")[1];
let borderListTable = mainContentPane.getElementsByClassName("borderlist")[0];
let playerRows = borderListTable.getElementsByTagName("tr");
let headerCells = playerRows[0].getElementsByTagName("th");
let nameCellIndex = -1;
for (let i = 0; i < headerCells.length; i ++) {
if (headerCells[i].textContent === "Nom") {
nameCellIndex = i;
break;
}
}
if (nameCellIndex === -1) {
/* Name column not found, so return */
console.log("Column 'Nom' not found, cannot show player ids :(");
return;
}
let idHeaderCell = createCustomElement("th", {"class": headerCells[0].getAttribute("class")}, "Id");
for (let i = 1; i < playerRows.length; i ++) {
let playerCells = playerRows[i].getElementsByTagName("td");
let playerProfileLink = playerCells[nameCellIndex].getElementsByTagName("a")[0].getAttribute("href");
let idValue = playerProfileLink.replace(/^.*id=(\d+)$/, "$1");
let idCell = createCustomElement("td", {"class": playerCells[0].getAttribute("class")}, idValue);
playerRows[i].insertBefore(idCell, playerCells[nameCellIndex]);
}
playerRows[0].insertBefore(idHeaderCell, headerCells[nameCellIndex]);
}
function showPlayerUnitPointsAndId() {
let mainContentPane = document.getElementsByClassName("contentpane")[1];
let borderLists = mainContentPane.getElementsByClassName("borderlist");
let playerPropertiesTable = borderLists[0];
let playerPropertiesTbody = playerPropertiesTable.getElementsByTagName("tbody")[0];
let playerPropertiesRows = playerPropertiesTable.getElementsByTagName("tr");
let totalPoints = num(playerPropertiesRows[2].getElementsByTagName("td")[1].textContent);
let villagesCount = num(playerPropertiesRows[4].getElementsByTagName("td")[1].textContent);
let villagesTable = borderLists[1]; let villagesTable = borderLists[1];
let villagesRows = villagesTable.getElementsByTagName("tr"); let villagesRows = villagesTable.getElementsByTagName("tr");
let villagesPoints = 0; let villagesPoints = 0;
for (let i=1; i<villagesRows.length; i+=1) { for (let i = 1; i < villagesRows.length; i += 1) {
villagesPoints += num(villagesRows[i].getElementsByTagName("td")[2].textContent); villagesPoints += num(villagesRows[i].getElementsByTagName("td")[2].textContent);
} }
let villagesBonus = 2250 * Math.max(0, villagesCount - 1); let villagesBonus = 2250 * Math.max(0, villagesCount - 1);
let armyPoints = totalPoints - villagesPoints - villagesBonus; let armyPoints = totalPoints - villagesPoints - villagesBonus;
let armyPercent = "-"; let armyPercent = "-";
if (villagesCount > 0) { if (villagesCount > 0) {
armyPercent = (Math.round(armyPoints / villagesCount) / 100).toString() + " %"; armyPercent = (Math.round(armyPoints / villagesCount) / 100).toString() + " %";
} }
playerPropertiesTable.appendChild(createRow("Points troupes:", str(armyPoints))); let moduleMenu = mainContentPane.getElementsByTagName("table")[0];
playerPropertiesTable.appendChild(createRow("% points troupes:", armyPercent)); let moduleHyperlink = moduleMenu.getElementsByTagName("a")[0];
let playerId = moduleHyperlink.getAttribute("href").replace(/^.*[?&]id=(\d+).*$/, "$1");
playerPropertiesTbody.appendChild(createKeyValueRow("Points troupes:", str(armyPoints)));
playerPropertiesTbody.appendChild(createKeyValueRow("% points troupes:", armyPercent));
playerPropertiesTbody.insertBefore(createKeyValueRow("Id:", playerId), playerPropertiesRows[2]);
} }
/* Display unit-points on village overview */ function showVillageUnitPoints() {
if (document.body.id === "overview") { let settlementElt = document.getElementById("settlement");
let settlements = document.getElementById("settlement").textContent.split("|"); if (settlementElt === null) {
console.log("Settlement element not found => cannot show village points :(");
return;
}
let settlements = settlementElt.textContent.split("|");
let noBorderRows = document.getElementsByClassName("noborder"); let noBorderRows = document.getElementsByClassName("noborder");
let villagePointsRow = noBorderRows[0]; let villagePointsRow = noBorderRows[0];
for (let i=0; i<noBorderRows.length; i++) { for (let i = 0; i < noBorderRows.length; i++) {
if (noBorderRows[i].textContent.startsWith("Points:")) { if (noBorderRows[i].textContent.startsWith("Points:")) {
villagePointsRow = noBorderRows[i]; villagePointsRow = noBorderRows[i];
break; break;
} }
} }
let unitPointsRow = villagePointsRow.cloneNode(true); let unitPointsRow = villagePointsRow.cloneNode(true);
villagePointsRow.getElementsByTagName("td")[1].textContent = "Points village: " + settlements[3]; villagePointsRow.getElementsByTagName("td")[1].textContent = "Points village: " + settlements[3];
unitPointsRow.getElementsByTagName("td")[1].textContent = "Points troupes: " + settlements[4]; unitPointsRow.getElementsByTagName("td")[1].textContent = "Points troupes: " + settlements[4];
villagePointsRow.after(unitPointsRow); villagePointsRow.after(unitPointsRow);
} }
function showBarrackSelectAllUnits() {
let sendCommandForm = document.getElementById("sendCommandForm");
let barracksCommands = sendCommandForm.getElementsByClassName("barracksCommand");
let borderListTables = sendCommandForm.getElementsByClassName("borderlist");
let unitCountBoxes = [];
if (barracksCommands.length === 1) {
unitCountBoxes = barracksCommands[0].getElementsByClassName("box");
} else if (borderListTables.length === 1) {
unitCountBoxes = borderListTables[0].getElementsByTagName("td");
}
for (let i = 0; i < unitCountBoxes.length; i ++) {
let unitCountInputs = unitCountBoxes[i].getElementsByTagName("input");
if (unitCountInputs.length === 0) {
continue;
}
let unitCountInput = unitCountInputs[0];
if (unitCountInput.getAttribute("type") === null) {
unitCountInput.setAttribute("type", "number");
unitCountInput.style.width = "65px";
}
}
let sendXInput = document.getElementById("send_x");
sendXInput.setAttribute("type", "number");
if (sendXInput.value === "0") {
sendXInput.value = "";
}
let sendYInput = document.getElementById("send_y");
sendYInput.setAttribute("type", "number");
if (sendYInput.value === "0") {
sendYInput.value = "";
}
let selectAllLabel = createCustomElement("label");
let selectAllInput = createCustomElement("input", {"type": "checkbox"});
selectAllInput.addEventListener("change", function () {
for (let i = 0; i < unitCountBoxes.length; i ++) {
let unitCountBox = unitCountBoxes[i];
let unitCountClicks = unitCountBox.getElementsByClassName("click");
if (unitCountClicks.length === 0) {
continue;
}
let unitCountClick = unitCountClicks[0];
if (unitCountClick.classList.contains("all")) {
continue;
}
let unitCountInput = unitCountBox.getElementsByTagName("input")[0];
if (this.checked && unitCountClick.textContent !== "(0)") {
unitCountInput.value = unitCountClick.textContent.replace(/^\(([^.]*)(\.([^.]*))?\)$/, "$1$3");
} else {
unitCountInput.value = "";
}
}
})
selectAllLabel.appendChild(selectAllInput);
let selectAllSpan = createCustomElement("span", {"class": "click all"}, "(Tout sélectionner)");
selectAllLabel.appendChild(selectAllSpan);
/* Modern style */
if (barracksCommands.length === 1) {
let boxCell = createCustomElement("div", {"class": "box"});
let backgroundCell = createCustomElement("div", {"class": "background"});
let backgroundImg = createCustomElement(
"img", {"src": "//s58-fr.kingsage.gameforge.com/img/modern/card_sendunit.png"}
);
backgroundCell.appendChild(backgroundImg);
boxCell.appendChild(backgroundCell);
let imageCell = createCustomElement("div", {"class": "image"});
let imageImg = createCustomElement(
"img", {"src": "//s58-fr.kingsage.gameforge.com/img/shortcut/barracks.png"}, null, {"width": "28px"}
);
imageCell.appendChild(imageImg);
boxCell.appendChild(imageCell);
let nameCell = createCustomElement("div", {"class": "name"});
let nameA = createCustomElement("a", {"href": "help.php?m=units", "target": "_help"});
let nameB = createCustomElement("b", null, "Tout");
nameA.appendChild(nameB);
nameCell.appendChild(nameA);
boxCell.appendChild(nameCell);
let selectAllCell = createCustomElement("div", {"class": "quantity"});
selectAllCell.appendChild(selectAllLabel);
boxCell.appendChild(selectAllCell);
let brTag = barracksCommands[0].getElementsByTagName("br")[1];
barracksCommands[0].insertBefore(boxCell, brTag);
/* Classic style */
} else if (borderListTables.length === 1) {
let borderListRows = borderListTables[0].getElementsByTagName("tr");
let selectAllCell = borderListRows[4].getElementsByTagName("td")[3];
let imageA = createCustomElement("a", {"href": "help.php?m=units", "target": "_help"});
let imageImg = createCustomElement(
"img", {"src": "//s58-fr.kingsage.gameforge.com/img/shortcut/barracks.png", "title": "Tout"}
);
imageA.appendChild(imageImg);
selectAllCell.appendChild(imageA);
selectAllCell.appendChild(selectAllLabel);
}
}
function showCountupTimeDecimals() {
let oldCell = document.getElementById("countup-time");
let hms = oldCell.parentElement.previousElementSibling.getElementsByTagName("td")[1].textContent.split(":");
movingDuration = parseInt(hms[0]) * 3600 + parseInt(hms[1]) * 60 + parseInt(hms[2]) ;
let newRow = createCustomElement("tr");
let newLeftCell = createCustomElement("td", null, "Arrivée:");
newRow.appendChild(newLeftCell);
let newRightCell = createCustomElement("td", {"id": "countup-time-ms"});
newRow.appendChild(newRightCell);
oldCell.parentElement.parentElement.insertBefore(newRow, oldCell.parentElement);
oldCell.parentElement.style.display = "none";
setInterval(countUpMs, 100);
}
function showOccurrencesInput() {
let table = createCustomElement("table", {"class": "borderlist"});
let tbody = createCustomElement("tbody");
let tr = createCustomElement("tr");
let th = createCustomElement("th", null, "Nombre d'occurrences:");
tr.appendChild(th)
let td = createCustomElement("td");
let input = createCustomElement("input", {"type": "number", "name": "occurrences", "value": "1"});
td.appendChild(input);
tr.appendChild(td);
tbody.appendChild(tr);
table.appendChild(tbody);
let form = document.getElementsByTagName("form")[0];
let firstInput = form.getElementsByTagName("input")[0];
form.insertBefore(table, firstInput);
form.addEventListener("submit", function (event) {
event.preventDefault();
let formData = new FormData(this);
let attackCount = parseInt(formData.get("occurrences").toString());
formData.delete("occurrences");
let sent = 0;
for (let i = 0; i < attackCount; i ++) {
let xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
sent ++;
}
if (sent === attackCount) {
window.location.replace(xhr.responseURL);
}
})
xhr.open(this.method, this.action, true);
xhr.send(formData);
}
});
}
function fixSelectVillageBug() {
let select = document.getElementsByName("village_name")[0];
select.removeAttribute("onchange");
select.addEventListener("change", function () {
let sendX = document.getElementById("send_x");
let sendY = document.getElementById("send_y");
if (this.selectedIndex === 0) {
sendX.value = "";
sendY.value = "";
} else {
let xy = this.value.split("|");
sendX.value = xy[0];
sendY.value = xy[1];
}
});
}
function showThousandInputs() {
let sendForm = document.getElementsByTagName("form")[0]
sendForm.addEventListener("submit", function () {
let inputs = this.getElementsByTagName("input");
for (let i = 0; i < inputs.length; i ++) {
if (inputs[i].getAttribute("name").endsWith("_k")) {
inputs[i].setAttribute("name", "");
}
}
});
let sendFormTables = sendForm.getElementsByTagName("table");
let newTable = sendFormTables[0].cloneNode(true);
newTable.getElementsByTagName("th")[0].textContent = "Ressources par milliers";
let resCells = newTable.getElementsByTagName("td");
for (let i = 0; i < resCells.length; i ++) {
let resInput = resCells[i].getElementsByTagName("input")[0];
let resName = resInput.getAttribute("name");
let resNameK = resInput.getAttribute("name") + "_k";
resInput.setAttribute("name", resNameK);
resInput.addEventListener("change", function () {
document.getElementsByName(resName)[0].value = 1000 * parseInt(this.value);
});
let spanInput = resCells[i].getElementsByTagName("span")[0];
let resMax = spanInput.textContent.replace(/\(/, "").replace("\)", "").replace(/\./, "");
let rMax = Math.floor(parseInt(resMax) / 1000);
spanInput.setAttribute(
"onclick",
"insertNum('kingsage', '" + resNameK + "', '" + rMax.toString() + "'); " +
"insertNum('kingsage', '" + resName + "', '" + (1000 * rMax).toString() + "');"
)
spanInput.textContent = "(" + rMax.toString() + "K)";
}
sendForm.insertBefore(newTable, sendFormTables[0]);
sendForm.insertBefore(createCustomElement("br"), sendFormTables[1]);
}
function fixSendResourcesInputsTypes() {
let contentPane = document.getElementsByClassName("contentpane")[1]
let sendCommandForm = contentPane.getElementsByTagName("form")[0];
let sendInputs = sendCommandForm.getElementsByTagName("input");
for (let i = 0; i < sendInputs.length; i ++) {
if (sendInputs[i].name.startsWith("send_")) {
sendInputs[i].setAttribute("type", "number");
if (sendInputs[i].value === "0") {
sendInputs[i].value = "";
}
sendInputs[i].style.width = "65px";
}
}
}
function showSecondsAndCalculator() {
let serverTime = parseInt(document.getElementById("servertime").getAttribute("time"));
let contentPane = document.getElementsByClassName("contentpane")[1]
let table = contentPane.getElementsByClassName("borderlist")[0];
let rows = table.getElementsByTagName("tr");
let titleRowIndex = 0;
if (rows[titleRowIndex].getElementsByTagName("th").length === 0) {
titleRowIndex = 1;
}
console.log(titleRowIndex)
let headCell = createCustomElement("th", null, "Calcul", {"width": "45px"});
rows[titleRowIndex].appendChild(headCell);
for (let i = titleRowIndex + 1; i < rows.length; i ++) {
let cells = rows[i].getElementsByTagName("td");
let arrivalDateCell = cells[3]
let arrivalTimeCell = cells[4];
let seconds = parseInt(arrivalTimeCell.getElementsByTagName("span")[0].getAttribute("time"));
let arrival = new Date((serverTime + seconds) * 1000);
let hour = arrival.toLocaleTimeString("fr-FR");
arrivalDateCell.textContent = arrivalDateCell.textContent.replace(/(.*)\d\d:\d\d(.*)/, "$1" + hour + "$2");
let startPoint = searchPoint(cells[2].textContent);
let targetPoint = searchPoint(cells[1].textContent);
let calculatorCell = createCustomElement("td");
let calculatorForm = createCustomElement(
"form",
{
"method": "post",
"action": "/?s=tools&m=runtime_calculator&inta=calculate",
"title": "Calculateur de trajet",
},
null,
{
"display": "inline-block",
},
);
calculatorForm.appendChild(createCustomInput("hidden", "start_x", startPoint.x));
calculatorForm.appendChild(createCustomInput("hidden", "start_y", startPoint.y));
calculatorForm.appendChild(createCustomInput("hidden", "target_x", targetPoint.x));
calculatorForm.appendChild(createCustomInput("hidden", "target_y", targetPoint.y));
let calculatorImg = createCustomInput(
"image",
null,
null,
{"src": chrome.runtime.getURL("images/calculator.svg")},
{"width": "20px", "height": "20px", "border": "none"}
);
calculatorForm.appendChild(calculatorImg);
calculatorCell.appendChild(calculatorForm);
let calculatorFormBlank = calculatorForm.cloneNode(true);
calculatorFormBlank.setAttribute("target", "_blank");
calculatorFormBlank.setAttribute("title", "Calculateur de trajet dans nouvel onglet");
let calculatorBlankImg = calculatorFormBlank.getElementsByTagName("input")[4]
calculatorBlankImg.setAttribute("src", chrome.runtime.getURL("images/blank.svg"));
calculatorCell.appendChild(calculatorFormBlank);
rows[i].appendChild(calculatorCell);
}
}
function main() {
/* Exit immediately if not on game page */
let layCastleTopElements = document.getElementsByClassName("lay_castle_top");
if (layCastleTopElements.length === 0) {
return;
}
/* Exit immediately if extension has already been loaded */
let kaplus = document.getElementById("kaplus-marker");
if (kaplus) {
return;
}
/* Set marker to prevent loading extension several times */
document.body.appendChild(createCustomElement("div", {"id": "kaplus-marker"}, null, {"display": "none"}));
/* Remove ads banner on dom content loaded */
window.addEventListener("DOMContentLoaded", removeAdsBanner);
/* Customize navbar */
customizeNavbar(layCastleTopElements[0]); // test: OK
/* Parse url params and switch case */
let urlParams = new URLSearchParams(window.location.search);
let section = urlParams.get("s");
let module = urlParams.get("m");
let sub = urlParams.get("sub");
/* Choose action according to section, module and sub */
switch (section) {
case "ranking":
switch (module) {
case "player": case null:
showPlayersId(); // test: OK
break;
}
break;
case "ally":
switch (module) {
case "members":
showPlayersId(); // test: OK
break;
case "attacks":
showSecondsAndCalculator(); // test: OK
break;
}
break;
case "overview":
showVillageUnitPoints(); // test: FAILED because settlement element has been removed
break;
case "build_barracks":
switch (module) {
case "command": case null:
switch (sub) {
case null:
showBarrackSelectAllUnits(); // test: OK
break;
case "send":
showCountupTimeDecimals(); // test: OK
showOccurrencesInput(); // test: OK
break;
}
break;
}
break;
case "build_market":
switch (module) {
case "send": case null:
fixSelectVillageBug(); // test: OK
showThousandInputs(); // test: OK
fixSendResourcesInputsTypes(); // test: OK
break;
}
break;
case "info_player":
switch (module) {
case "profile": case null:
showPlayerUnitPointsAndId(); // test: OK
break;
}
break;
case "info_member":
showPlayersId(); // test: OK
break;
}
}
main();