wip
This commit is contained in:
1
images/clock.svg
Normal file
1
images/clock.svg
Normal 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="M320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576C178.6 576 64 461.4 64 320C64 178.6 178.6 64 320 64zM296 184L296 320C296 328 300 335.5 306.7 340L402.7 404C413.7 411.4 428.6 408.4 436 397.3C443.4 386.2 440.4 371.4 429.3 364L344 307.2L344 184C344 170.7 333.3 160 320 160C306.7 160 296 170.7 296 184z"/></svg>
|
||||
|
After Width: | Height: | Size: 558 B |
@@ -1,3 +1,17 @@
|
||||
@keyframes blink {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#inner_footer {
|
||||
.inner_subcolumns {
|
||||
left: 0 !important;
|
||||
@@ -6,6 +20,16 @@
|
||||
|
||||
#content_wrapper > table {
|
||||
width: auto !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.borderlist {
|
||||
.autonomous:disabled {
|
||||
opacity: 0.3;
|
||||
}
|
||||
.autonomous.blink {
|
||||
animation: blink 2s infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.lay_castle_top {
|
||||
|
||||
337
src/kaplus.js
337
src/kaplus.js
@@ -1,7 +1,6 @@
|
||||
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;
|
||||
const AUTHORIZED_ALLIANCES = {
|
||||
"s58": ["NAZGUL"]
|
||||
};
|
||||
|
||||
function num(s) {
|
||||
return parseInt(s.replace(".", ""));
|
||||
@@ -119,10 +118,10 @@ function customizeNavbar(layCastleElement) {
|
||||
shortcutContainers[2].classList.add("shortcut_container_right");
|
||||
}
|
||||
|
||||
function countUpMs() {
|
||||
function countUpMs(tomorrow, after_tomorrow, movingDuration) {
|
||||
let arrivalDate = new Date(new Date().getTime() + movingDuration * 1000);
|
||||
let prefix = "";
|
||||
if (arrivalDate >= afterTomorrow) {
|
||||
if (arrivalDate >= after_tomorrow) {
|
||||
prefix = "le " + arrivalDate.getDate() + "." + arrivalDate.getMonth() + " ";
|
||||
} else if (arrivalDate > tomorrow) {
|
||||
prefix = "demain ";
|
||||
@@ -138,6 +137,34 @@ function countUpMs() {
|
||||
+ Math.floor(arrivalDate.getMilliseconds() / 100);
|
||||
}
|
||||
|
||||
function countdownMS(formattedDate) {
|
||||
let now = new Date();
|
||||
if (formattedDate.startsWith("à")) {
|
||||
let start = new Date();
|
||||
let hms = formattedDate.replace(/^à (\d\d:\d\d:\d\d) heures$/, "$1").split(":");
|
||||
start.setHours(parseInt(hms[0]));
|
||||
start.setMinutes(parseInt(hms[1]));
|
||||
start.setSeconds(parseInt(hms[2]));
|
||||
return start.getTime() - now.getTime();
|
||||
}
|
||||
if (formattedDate.startsWith("demain")) {
|
||||
let start = new Date(now.getTime() + 24*60*60*1000);
|
||||
let hms = formattedDate.replace(/^demain à (\d\d:\d\d:\d\d) heures$/, "$1").split(":");
|
||||
start.setHours(parseInt(hms[0]));
|
||||
start.setMinutes(parseInt(hms[1]));
|
||||
start.setSeconds(parseInt(hms[2]));
|
||||
return start.getTime() - now.getTime();
|
||||
}
|
||||
let start = new Date();
|
||||
let hms = formattedDate.replace(/^le (\d\d)\.(\d\d) à (\d\d:\d\d:\d\d) heures$/, "$1:$2:$3");
|
||||
start.setDate(parseInt(hms[0]));
|
||||
start.setMonth(parseInt(hms[1]));
|
||||
start.setHours(parseInt(hms[0]));
|
||||
start.setMinutes(parseInt(hms[1]));
|
||||
start.setSeconds(parseInt(hms[2]));
|
||||
return start.getTime() - now.getTime();
|
||||
}
|
||||
|
||||
function removeAdsBanner() {
|
||||
/* Remove iframe banner */
|
||||
document.getElementById("banner_skyscraper").remove();
|
||||
@@ -207,6 +234,256 @@ function showPlayerUnitPointsAndId() {
|
||||
playerPropertiesTbody.insertBefore(createKeyValueRow("Id:", playerId), playerPropertiesRows[2]);
|
||||
}
|
||||
|
||||
function showPlanerAutonomous() {
|
||||
// Exit if no attack is planed
|
||||
let mainContentPane = document.getElementsByClassName("contentpane")[1];
|
||||
let planTable = mainContentPane.getElementsByClassName("borderlist")[2];
|
||||
let planRows = planTable.getElementsByTagName("tr");
|
||||
|
||||
setInterval(function() {
|
||||
for (let i = 0; i < planRows.length; i ++) {
|
||||
let planCells = planRows[i].getElementsByTagName("td");
|
||||
if (planCells.length < 9) {
|
||||
break;
|
||||
}
|
||||
let startCell = planCells[4];
|
||||
let endCell = planCells[5];
|
||||
let countdownCell = planCells[6];
|
||||
let countdownSpan = countdownCell.firstChild;
|
||||
if (countdownSpan.textContent === "0:00:00") {
|
||||
countdownSpan.textContent = "en retard";
|
||||
startCell.style.color = "red";
|
||||
endCell.style.color = "red";
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
if (planRows.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get an existing target from plan table
|
||||
let targetCell = planRows[1].getElementsByTagName("td")[2];
|
||||
let targetXY = targetCell.getElementsByTagName("a")[1].textContent.split("|");
|
||||
|
||||
// Get token by submitting a fake support
|
||||
let urlParams = new URLSearchParams(window.location.search);
|
||||
let villageId = urlParams.get("village");
|
||||
let xhr = new XMLHttpRequest();
|
||||
let troopToken = null;
|
||||
xhr.addEventListener("readystatechange", function () {
|
||||
if (xhr.readyState === xhr.DONE) {
|
||||
let parser = new DOMParser();
|
||||
let doc = parser.parseFromString(xhr.responseText, "text/html");
|
||||
let quantityDivs = doc.getElementsByClassName("quantity");
|
||||
let unit = null;
|
||||
for (let i = 0; i < quantityDivs.length; i ++) {
|
||||
let quantityInput = quantityDivs[i].getElementsByTagName("input")[0];
|
||||
let quantityClick = quantityDivs[i].getElementsByClassName("click")[0];
|
||||
if (quantityClick.textContent !== "(0)") {
|
||||
unit = quantityInput.getAttribute("name");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unit === null) {
|
||||
alert("Il faut avoir au moins une unité dans le village actuel pour déterminer le jeton de sécurité!");
|
||||
}
|
||||
|
||||
let xhrSend = new XMLHttpRequest();
|
||||
let formData = new FormData();
|
||||
formData.set(unit, "1");
|
||||
formData.set("send_x", targetXY[0]);
|
||||
formData.set("send_y", targetXY[1]);
|
||||
formData.set("support", "Envoyer du renfort");
|
||||
xhrSend.addEventListener("readystatechange", function () {
|
||||
if (xhrSend.readyState === xhrSend.DONE) {
|
||||
let parser = new DOMParser();
|
||||
let doc = parser.parseFromString(xhrSend.responseText, "text/html");
|
||||
let form = doc.getElementsByTagName("form")[0];
|
||||
let action = form.getAttribute("action");
|
||||
troopToken = action.replace(/^.*(p=([a-z0-9]+)).*$/, "$2");
|
||||
}
|
||||
});
|
||||
xhrSend.open("POST", "/?village=" + villageId + "&s=build_barracks&m=command&sub=send");
|
||||
xhrSend.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
let formParams = new URLSearchParams(formData);
|
||||
xhrSend.send(formParams.toString());
|
||||
}
|
||||
})
|
||||
xhr.open("GET", "/?village=" + villageId + "&s=build_barracks");
|
||||
xhr.send();
|
||||
|
||||
// Display autonomous cell for each planed attack
|
||||
let planHeaderCells = planRows[0].getElementsByTagName("th");
|
||||
planHeaderCells[6].textContent = "Manuel";
|
||||
planRows[0].insertBefore(createCustomElement("th", null, "Autonome"), planHeaderCells[6]);
|
||||
planRows[0].insertBefore(createCustomElement("th", null, null, {"width": "18px"}), planHeaderCells[0]);
|
||||
for (let i = 1; i < planRows.length; i ++) {
|
||||
let planCells = planRows[i].getElementsByTagName("td");
|
||||
|
||||
let autonomousMarkerCell = createCustomElement("td");
|
||||
planRows[i].insertBefore(autonomousMarkerCell, planCells[0]);
|
||||
|
||||
let startCell = planCells[4];
|
||||
let timeCounterCell = planCells[6];
|
||||
let timeCounterSpan = timeCounterCell.getElementsByTagName("span")[0];
|
||||
timeCounterSpan.setAttribute("reload", "false");
|
||||
|
||||
let autonomousCell = createCustomElement("td");
|
||||
let autonomousForm = createCustomElement("form", null, null, {"white-space": "nowrap"});
|
||||
|
||||
let attackLink = planCells[7].getElementsByTagName("a")[0]
|
||||
let attackParams = new URLSearchParams(attackLink.getAttribute("href").replace(/^\/\?(.*)$/, "$1"));
|
||||
for (let [key, value] of attackParams) {
|
||||
switch (key) {
|
||||
case "s": case "m":
|
||||
break;
|
||||
default:
|
||||
let autonomousHidden = createCustomInput("hidden", key, value);
|
||||
autonomousForm.appendChild(autonomousHidden);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let autonomousOccurrencesBox = createCustomElement(
|
||||
"div",
|
||||
{"title": "Préciser le nombre d'occurrences souhaité"},
|
||||
null,
|
||||
{"display": "inline-block", "border": "1px solid grey", "vertical-align": "text-bottom", "margin": "0 3px"},
|
||||
);
|
||||
let autonomousOccurrencesPrefix = createCustomElement("span", null, "x", {"margin": "0 3px", "color": "grey"});
|
||||
let autonomousOccurrencesInput = createCustomInput(
|
||||
"number",
|
||||
"occurrences",
|
||||
"1",
|
||||
{"class": "autonoumous occurrences"},
|
||||
{"display": "inline-block", "width": "35px", "border": "none"},
|
||||
);
|
||||
autonomousOccurrencesBox.appendChild(autonomousOccurrencesPrefix);
|
||||
autonomousOccurrencesBox.appendChild(autonomousOccurrencesInput);
|
||||
autonomousForm.appendChild(autonomousOccurrencesBox);
|
||||
|
||||
let autonomousAttack = createCustomInput(
|
||||
"image",
|
||||
null,
|
||||
null,
|
||||
{"src": "/img/command/attack.png", "title": "Pogrammer une attaque autonome", "class": "autonomous attack"},
|
||||
{"display": "inline-block", "margin": "0 3px", "border": "none"},
|
||||
);
|
||||
autonomousForm.appendChild(autonomousAttack);
|
||||
let autonomousSupport = createCustomInput(
|
||||
"image",
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"src": "/img/command/support.png",
|
||||
"title": "Programmer un renfort autonome",
|
||||
"class": "autonomous support",
|
||||
},
|
||||
{"display": "inline-block", "margin": "0 3px", "border": "none"},
|
||||
);
|
||||
autonomousForm.appendChild(autonomousSupport);
|
||||
let autonomousCancel = createCustomInput(
|
||||
"image",
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"src": "/img/ico_delete.png",
|
||||
"title": "Annuler la programmation autonome",
|
||||
"class": "autonomous cancel",
|
||||
"disabled": "disabled",
|
||||
},
|
||||
{"display": "inline-block", "margin": "0 3px", "border": "none"},
|
||||
);
|
||||
autonomousForm.appendChild(autonomousCancel);
|
||||
|
||||
let timeoutID = null;
|
||||
autonomousForm.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// Handle cancel button
|
||||
if (event.submitter.classList.contains("cancel")) {
|
||||
if (timeoutID !== null) {
|
||||
clearTimeout(timeoutID);
|
||||
timeoutID = null;
|
||||
autonomousMarkerCell.firstChild.remove();
|
||||
autonomousOccurrencesInput.removeAttribute("disabled");
|
||||
autonomousAttack.removeAttribute("disabled");
|
||||
autonomousSupport.removeAttribute("disabled");
|
||||
autonomousCancel.setAttribute("disabled", "disabled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit now if too late
|
||||
if (timeCounterSpan.textContent === "en retard" || timeCounterSpan.textContent === "0:00:00") {
|
||||
alert("Impossible de programmer le lancement autonome car l'heure de départ est déjà dépassée!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit now if already programed
|
||||
if (timeoutID !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse form data
|
||||
let formData = new FormData(this);
|
||||
let occurrences = parseInt(formData.get("occurrences").toString())
|
||||
formData.delete("occurrences");
|
||||
if (event.submitter.classList.contains("attack")) {
|
||||
formData.set("attack", "Attaquer");
|
||||
}
|
||||
|
||||
// Program autonomous attack or support
|
||||
let ms = countdownMS(startCell.textContent);
|
||||
console.log("setTimeout", ms);
|
||||
timeoutID = setTimeout(function() {
|
||||
for (let i = 0; i < occurrences; i ++) {
|
||||
let xhrTimeout = new XMLHttpRequest();
|
||||
xhrTimeout.open("POST", "/?s=build_barracks&m=command&a=sendTroop&p=" + troopToken);
|
||||
xhrTimeout.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
let formParams = new URLSearchParams(formData);
|
||||
xhrTimeout.send(formParams.toString());
|
||||
}
|
||||
autonomousMarkerCell.firstChild.classList.remove("blink");
|
||||
autonomousOccurrencesInput.setAttribute("disabled", "disabled");
|
||||
autonomousAttack.setAttribute("disabled", "disabled");
|
||||
autonomousSupport.setAttribute("disabled", "disabled");
|
||||
autonomousCancel.setAttribute("disabled", "disabled");
|
||||
}, ms);
|
||||
|
||||
// Add blinking marker
|
||||
if (event.submitter.classList.contains("attack")) {
|
||||
let attackImg = createCustomElement(
|
||||
"img",
|
||||
{
|
||||
"src": "/img/command/attack.png",
|
||||
"title": "Attaque autonome programmée",
|
||||
"class": "autonomous blink",
|
||||
}
|
||||
)
|
||||
autonomousMarkerCell.appendChild(attackImg);
|
||||
} else {
|
||||
let supportImg = createCustomElement(
|
||||
"img",
|
||||
{
|
||||
"src": "/img/command/support.png",
|
||||
"title": "Renfort autonome programmé",
|
||||
"class": "autonomous blink",
|
||||
}
|
||||
)
|
||||
autonomousMarkerCell.appendChild(supportImg);
|
||||
}
|
||||
autonomousOccurrencesInput.setAttribute("disabled", "disabled");
|
||||
autonomousAttack.setAttribute("disabled", "disabled");
|
||||
autonomousSupport.setAttribute("disabled", "disabled");
|
||||
autonomousCancel.removeAttribute("disabled");
|
||||
})
|
||||
autonomousCell.appendChild(autonomousForm);
|
||||
planRows[i].insertBefore(autonomousCell, planCells[7]);
|
||||
}
|
||||
}
|
||||
|
||||
function showVillageUnitPoints() {
|
||||
let settlementElt = document.getElementById("settlement");
|
||||
if (settlementElt === null) {
|
||||
@@ -339,9 +616,13 @@ function showBarrackSelectAllUnits() {
|
||||
}
|
||||
|
||||
function showCountupTimeDecimals() {
|
||||
let tomorrow = new Date(new Date().getTime() + 24*60*60*1000);
|
||||
tomorrow.setHours(0, 0, 0, 0);
|
||||
let after_tomorrow = new Date(tomorrow.getTime() + 24*60*60*1000);
|
||||
|
||||
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 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);
|
||||
@@ -349,7 +630,7 @@ function showCountupTimeDecimals() {
|
||||
newRow.appendChild(newRightCell);
|
||||
oldCell.parentElement.parentElement.insertBefore(newRow, oldCell.parentElement);
|
||||
oldCell.parentElement.style.display = "none";
|
||||
setInterval(countUpMs, 100);
|
||||
setInterval(countUpMs, 100, tomorrow, after_tomorrow, movingDuration);
|
||||
}
|
||||
|
||||
function showOccurrencesInput() {
|
||||
@@ -384,7 +665,9 @@ function showOccurrencesInput() {
|
||||
}
|
||||
})
|
||||
xhr.open(this.method, this.action, true);
|
||||
xhr.send(formData);
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
let formParams = new URLSearchParams(formData);
|
||||
xhr.send(formParams.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -523,12 +806,31 @@ function showSecondsAndCalculator() {
|
||||
}
|
||||
|
||||
function main() {
|
||||
|
||||
/* Exit immediately if not on game page */
|
||||
let layCastleTopElements = document.getElementsByClassName("lay_castle_top");
|
||||
if (layCastleTopElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Exit immediately if not authorized */
|
||||
let xhrAlly = new XMLHttpRequest();
|
||||
let serverID = window.location.hostname.replace(/^(s\d+)-.*$/, "$1");
|
||||
if (serverID in AUTHORIZED_ALLIANCES) {
|
||||
xhrAlly.addEventListener("readystatechange", function () {
|
||||
if (xhrAlly.readyState === xhrAlly.DONE) {
|
||||
let parser = new DOMParser();
|
||||
let doc = parser.parseFromString(xhrAlly.responseText, "text/html");
|
||||
let h1 = doc.getElementsByTagName("h1")[0];
|
||||
if (!AUTHORIZED_ALLIANCES[serverID].includes(h1.textContent)) {
|
||||
window.location.replace("about:blank");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
xhrAlly.open("GET", "/?s=ally");
|
||||
xhrAlly.send();
|
||||
|
||||
/* Exit immediately if extension has already been loaded */
|
||||
let kaplus = document.getElementById("kaplus-marker");
|
||||
if (kaplus) {
|
||||
@@ -548,7 +850,6 @@ function main() {
|
||||
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) {
|
||||
@@ -571,6 +872,14 @@ function main() {
|
||||
}
|
||||
break;
|
||||
|
||||
case "tools":
|
||||
switch (module) {
|
||||
case "attack_planer":
|
||||
showPlanerAutonomous();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "overview":
|
||||
showVillageUnitPoints(); // test: FAILED because settlement element has been removed
|
||||
break;
|
||||
@@ -578,14 +887,12 @@ function main() {
|
||||
case "build_barracks":
|
||||
switch (module) {
|
||||
case "command": case null:
|
||||
switch (sub) {
|
||||
case null:
|
||||
let sendCommandForm = document.getElementById("sendCommandForm");
|
||||
if (sendCommandForm !== null) {
|
||||
showBarrackSelectAllUnits(); // test: OK
|
||||
break;
|
||||
case "send":
|
||||
} else {
|
||||
showCountupTimeDecimals(); // test: OK
|
||||
showOccurrencesInput(); // test: OK
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user