[Premiumfeature] Vorschlag, um schneller Wein von A -> B zu managen

  • [Premiumfeature] Vorschlag, um schneller Wein von A -> B zu managen

    Guten Abend,

    mein Vorschlag bezieht sich auf ein mögliches neues Premiumfeature. Im Handelshafen sollen die Ziel-Städte eine Wein-Restzeit bekommen.

    Sicherlich gibt es die Handelsrouten womit man das "automatisiert" managen könnte und mit dem Premiumfeature stehen die Restzeiten des Weinausschanks im Nicht-Wein-Städte, allerdings muss man sich jedes mal mühsam hin und herklicken um sich die Städte zu "merken", was mich pers. stört (und nein, auf Papier schreiben möchte ich nicht).

    Das neue Feature kann gerne auch per Checkbox an/ausschaltbar gemacht werden.

    Screenshot im Vergleich:
    Momentan:

    Meine Idee:

    Script für die Grease/Tampermonkey/Developer zur Visualisierung:

    JavaScript Source Code

    1. !(async () => {
    2. let isPortOpened = document.querySelector("#port #tabSendTransporter");
    3. if (isPortOpened) {
    4. let isLockPresent = document.querySelector("#lockkk");
    5. if (isLockPresent) return;
    6. let qc = document.querySelectorAll("ul.cities .boxContent");
    7. let timeSamples = ["22h", "1T", "5T", "4M", "1Y", "-", "∞", "17m", "1s", "3T", "12m"]; // Users can have up to 11 target cities ;)
    8. qc.forEach((e, idx) => {
    9. e.parentElement.style.setProperty("height", "130px"); // Define space to place wine capacity time
    10. let innerDivWineTime = document.createElement("div");
    11. let myLockObject = document.createElement("div");
    12. myLockObject.id = "lockkk";
    13. innerDivWineTime.innerHTML = `<div style="top: 103px; position: relative; left:9px;" >Wein Restzeit: <span ${/[smh]/.exec(timeSamples[idx]) ? `style="color: red;`: `style="color: green;`} font-weight: bold">${timeSamples[idx]}</span></div>`;
    14. qc[idx].appendChild(innerDivWineTime);
    15. document.body.appendChild(myLockObject);
    16. });
    17. } else {
    18. alert("Bitte öffne den Handeshafen um mein Beispiel visuell anzuzeigen!");
    19. }
    20. })();
    Display All
    Ich hoffe euch gefällt dieser Vorschlag.


    LG

    srbinas
  • srbinas wrote:

    mit dem Premiumfeature stehen die Restzeiten des Weinausschanks im Nicht-Wein-Städte, allerdings muss man sich jedes mal mühsam hin und herklicken um sich die Städte zu "merken", was mich pers. stört
    Ich komme damit eigentlich recht gut klar.

    Ansonsten, da du ja anscheinend JavaScript programmieren kannst: Wieso baust du nicht ein entsprechendes Greasemonkey-Skript? Ich kenne mich mit JavaScript jetzt nicht so gut aus (habe aber schon in anderen, ähnlichen Sprachen programmiert), aber so, wie das für mich aussieht, hast du doch einen guten Teil der Arbeit mit dem Codefragment oben bereits erledigt. Was du halt noch machen müsstest, wäre, die timeSamples durch richtige Werte zu ersetzen. Du könntest zum Beispiel bei jedem Stadtaufruf aus dem aktuellen Weinbestand und Verbrauch errechnen, wann der Wein ausgeht und diesen Wert abspeichern. (Das macht natürlich dann kurzzeitig Probleme, wenn eine Handelsflotte gerade neuen Wein in die Stadt geliefert hat, aber sobald man die Stadt dann einmal aufgerufen hat, stimmt der Wert wieder.)
    Das Meer ist alles. Es bedeckt sieben Zehntel der Erde. Sein Atem ist rein und gesund. Es ist eine immense Wüste, wo ein Mann nie alleine ist, in dem er fühlen kann, wie das Leben aller in ihm bebt. Das Meer ist nur ein Behälter für alle die ungeheuren, übernatürlichen Dinge, die darin existieren; es ist nicht nur Bewegung und Liebe; es ist die lebende Unendlichkeit.
  • Auch wenn das etwas vom Thema abweicht, hier ein Vorschlag:

    @Entwickler-Team: Ihr könnt doch mehrere Wettbewerbe ausschreiben, wie z.B. die Programmierung von diversen Automatisen, die nach eurem Ermessen (nur) mit Ambrosia zu kaufen sind, mit entsprechenden Programmierungsvorgaben.
    Free-Lancer programmieren selbst auf dem Test-Server (oder anderen Server), die Kapazitäten sind ja vorhanden. Ihr oder wenn ihr wollt, die ika-Forum community entscheidet, welche Programmierung übernommen werden kann.
    Die erfolgreichen Free-Lancer erhalten (lebenslang) Ambro oder sonstige Geschenke.

    Es muss ja nicht das Entwickler-Team selbst sein, was neues erfindet.
  • @Nemo

    Habe soweit es selbst hingekriegt, später baue ich es im Tampermonkey ein, hatte jetzt keine Lust die Automatisierung dafür zu schreiben :D.

    Für die interessierten anbei der Code:
    Achtung: Bitte nur ausführen, wenn ihr Premium-User seit!

    JavaScript Source Code

    1. window.DN = {
    2. userHasPremium: window.dataSetForView && dataSetForView.hasPremiumAccount && dataSetForView.hasPremiumAccount === "1",
    3. console: (() => { // Ikariam runs log into nothing... restore them for testing purposes
    4. let iframe = document.getElementById("DNIframe");
    5. if (!iframe) {
    6. iframe = document.createElement("iframe");
    7. iframe.id = "DNIframe";
    8. document.body.appendChild(iframe); // No more restoring native window.console :/, its no more part of the window constructor...
    9. }
    10. return iframe.contentWindow.console;
    11. })()
    12. };
    13. function getLeftoverWineDuration() {
    14. if (!DN.userHasPremium) throw "You need to be a premium user in order to use this script!";
    15. return new Promise((resolve, error) => {
    16. let xhr = new XMLHttpRequest();
    17. let url = `${location.origin}/?view=premiumTradeAdvisor&oldView=premiumTradeAdvisor&cityId=${bgViewData.currentCityId}&selectedType=1&sideBarExt=${dataSetForView.viewParams.sideBarExt}&backgroundView=city¤tCityId=${bgViewData.currentCityId}&templateView=premiumTradeAdvisor&actionRequest=${dataSetForView.actionRequest}&ajax=1`;
    18. xhr.open("POST", url, true);
    19. xhr.onload = (e) => resolve(e);
    20. xhr.send(null);
    21. });
    22. }
    23. function displayWineTimeInOpenedPort() {
    24. let isPortOpened = document.querySelector("#port #tabSendTransporter");
    25. if (isPortOpened) {
    26. getLeftoverWineDuration().then((wineInformation) => {
    27. if (wineInformation && wineInformation.target.response && wineInformation.target.response.length > 0) {
    28. let parsedResponse = JSON.parse(wineInformation.target.response);
    29. let updateTemplateData = parsedResponse.find((element, index) => Array.isArray(element) && element[0] === "updateTemplateData");
    30. let consumptionTimeRemainings = Object.keys(updateTemplateData[1]).filter((element) => element.includes("consumption_time_remaining") && element.includes("city"));
    31. let queriedCities = document.querySelectorAll("ul.cities .boxContent");
    32. consumptionTimeRemainings.forEach(nextRemainingTime => {
    33. let cityId = /([0-9]+)/.exec(nextRemainingTime)[0];
    34. let currentCity = Array.prototype.slice.call(queriedCities).find((city) => city.parentElement.id.includes(cityId)); // NodeList to Array :D
    35. if (!currentCity) return; // Skip current city
    36. let wineConsumptionTimeLeft = /^([^ ]+)/.exec(updateTemplateData[1][nextRemainingTime].text)[0];
    37. let innerDivWineTime = document.createElement("div");
    38. currentCity.parentElement.style.setProperty("height", "130px"); // Define space to place wine capacity time
    39. innerDivWineTime.innerHTML = `<div style="top: 103px; position: relative; left:9px;" >Wein Restzeit: <span ${/[smh]/.exec(wineConsumptionTimeLeft) ? `style="color: red;`: `style="color: green;`} font-weight: bold">${wineConsumptionTimeLeft}</span></div>`;
    40. currentCity.appendChild(innerDivWineTime);
    41. });
    42. }
    43. });
    44. }
    45. }
    46. displayWineTimeInOpenedPort();
    Display All
    LG
    srbinas
  • Gerade versucht, das bei mir einzufügen, allerdings scheint es nicht zu funktionieren. Ich habe ein neues Userscript in Tampermonkey erstellt, das @match angepasst und deinen Code darunter eingefügt. Also:

    Source Code

    1. // ==UserScript==
    2. // @name Ika-Wein
    3. // @namespace http://tampermonkey.net/
    4. // @version 0.1
    5. // @description try to take over the world!
    6. // @author You
    7. // @match https://s33-de.ikariam.gameforge.com/*
    8. // @grant none
    9. // ==/UserScript==
    10. [Dein Quellcode]
    Display All
    Das Skript ist auf der Ikariamseite aktiv (wird mir im Tooltip des Tampermonkey-Symbols angezeigt), daran liegt es also nicht. Premium-User bin ich auch. Hast du eine Idee, was das Problem sein könnte?
    Das Meer ist alles. Es bedeckt sieben Zehntel der Erde. Sein Atem ist rein und gesund. Es ist eine immense Wüste, wo ein Mann nie alleine ist, in dem er fühlen kann, wie das Leben aller in ihm bebt. Das Meer ist nur ein Behälter für alle die ungeheuren, übernatürlichen Dinge, die darin existieren; es ist nicht nur Bewegung und Liebe; es ist die lebende Unendlichkeit.
  • Sorry für das Doppelpost (kann leider meine vorherigen Beiträge nicht editieren...)

    Anbei das vollständige Script zu meiner Idee für Tampermonkey @Nemo @Gameforge @all

    JavaScript Source Code

    1. // ==UserScript==
    2. // @name Display left over wine in the port
    3. // @version 0.1
    4. // @author srbinas
    5. // @match http*://*.ikariam.gameforge.com/*
    6. // ==/UserScript==
    7. window.DN = {
    8. userHasPremium: dataSetForView.hasPremiumAccount === "1",
    9. console: (() => { // Ikariam runs log into nothing... restore them for testing purposes
    10. let iframe = document.getElementById("DNIframe");
    11. if (!iframe) {
    12. iframe = document.createElement("iframe");
    13. iframe.id = "DNIframe";
    14. document.body.appendChild(iframe); // No more restoring native window.console :/, its no more part of the window constructor...
    15. }
    16. return iframe.contentWindow.console;
    17. })(),
    18. intervalMaster: null
    19. };
    20. // DN.console.log(DN.userHasPremium);
    21. class DOMTask {
    22. constructor(name, fn, runCount = 1, lockSelector = null) {
    23. this.name = name;
    24. this.fn = fn;
    25. this.runCount = runCount;
    26. this.currentRun = 0;
    27. this.lockSelector = lockSelector;
    28. }
    29. }
    30. class DOMDeployTasks {
    31. constructor() {
    32. this.domTasks = [];
    33. }
    34. addTask(domTask) {
    35. if (!(domTask instanceof DOMTask)) throw "Given arg is not type of DOMTask!";
    36. this.domTasks.push(domTask);
    37. }
    38. run() {
    39. this.domTasks.forEach(task => {
    40. if (document.querySelector(task.lockSelector)) {
    41. if (task.currentRun < task.runCount) {
    42. task.currentRun++;
    43. task.fn();
    44. // DN.console.log(`Executed ${task.name}!`);
    45. } else {
    46. // DN.console.log(`Skipped task ${task.name}! Exceeded runCount of ${task.runCount}!`);
    47. }
    48. } else {
    49. task.currentRun = 0;
    50. // DN.console.log(`Reset to zero due to unmatch lock condition anymore!`);
    51. }
    52. });
    53. }
    54. }
    55. if (window.self === window.top) {
    56. // Init interval for exec/unexec tasks
    57. const deployedTasks = new DOMDeployTasks();
    58. deployedTasks.addTask(new DOMTask(
    59. "displayWineTimeInOpenedPort", () => {
    60. displayWineTimeInOpenedPort();
    61. }, 1, "#port #tabSendTransporter:not([style*='display: none'])"));
    62. DN.intervalMaster = setInterval(() => {
    63. deployedTasks.run();
    64. }, 250);
    65. }
    66. // --------------------------------------------------------------------------------------------------
    67. function getLeftoverWineDuration() {
    68. if (!DN.userHasPremium) throw "You need to be a premium user in order to use this script!";
    69. let result = null;
    70. return new Promise((resolve, error) => {
    71. let xhr = new XMLHttpRequest();
    72. let url = `${location.origin}/?view=premiumTradeAdvisor&oldView=premiumTradeAdvisor&cityId=${bgViewData.currentCityId}&selectedType=1&sideBarExt=${dataSetForView.viewParams.sideBarExt}&backgroundView=city¤tCityId=${bgViewData.currentCityId}&templateView=premiumTradeAdvisor&actionRequest=${dataSetForView.actionRequest}&ajax=1`;
    73. xhr.open("POST", url, true);
    74. xhr.onload = (e) => resolve(e);
    75. xhr.send(null);
    76. });
    77. }
    78. function displayWineTimeInOpenedPort() {
    79. let isPortOpened = document.querySelector("#port #tabSendTransporter");
    80. if (isPortOpened) {
    81. getLeftoverWineDuration().then((wineInformation) => {
    82. if (wineInformation && wineInformation.target.response && wineInformation.target.response.length > 0) {
    83. let parsedResponse = JSON.parse(wineInformation.target.response);
    84. let updateTemplateData = parsedResponse.find((element, index) => Array.isArray(element) && element[0] === "updateTemplateData");
    85. let consumptionTimeRemainings = Object.keys(updateTemplateData[1]).filter((element) => element.includes("consumption_time_remaining") && element.includes("city"));
    86. let queriedCities = document.querySelectorAll("ul.cities .boxContent");
    87. consumptionTimeRemainings.forEach(nextRemainingTime => {
    88. let cityId = /([0-9]+)/.exec(nextRemainingTime)[0];
    89. let currentCity = Array.prototype.slice.call(queriedCities).find((city) => city.parentElement.id.includes(cityId)); // NodeList to Array :D
    90. if (!currentCity) return; // Skip current city
    91. let wineConsumptionTimeLeft = /^([^ ]+)/.exec(updateTemplateData[1][nextRemainingTime].text)[0];
    92. let innerDivWineTime = document.createElement("div");
    93. currentCity.parentElement.style.setProperty("height", "130px"); // Define space to place wine capacity time
    94. innerDivWineTime.innerHTML = `<div style="top: 103px; position: relative; left:9px;" >Wein Restzeit: <span ${/[smh]/.exec(wineConsumptionTimeLeft) ? `style="color: red;`: `style="color: green;`} font-weight: bold">${wineConsumptionTimeLeft}</span></div>`;
    95. currentCity.appendChild(innerDivWineTime);
    96. });
    97. }
    98. });
    99. }
    100. }
    Display All
    LG
    srbinas
  • So funktioniert es bei mir. Vielen Dank für das Skript und die Arbeit, die du dir damit gemacht hast. Auch wenn ich weiter oben geschrieben habe, dass ich das im Prinzip nicht so dringend brauche, ist es doch eine sehr angenehme Funktion.
    Vielleicht schaue ich mir bei Gelegenheit auch mal ein bisschen JavaScript an. Interessant sieht das jedenfalls schon aus.
    Das Meer ist alles. Es bedeckt sieben Zehntel der Erde. Sein Atem ist rein und gesund. Es ist eine immense Wüste, wo ein Mann nie alleine ist, in dem er fühlen kann, wie das Leben aller in ihm bebt. Das Meer ist nur ein Behälter für alle die ungeheuren, übernatürlichen Dinge, die darin existieren; es ist nicht nur Bewegung und Liebe; es ist die lebende Unendlichkeit.
  • Das "Problem" scheint ja geklärt :)
    Allerdings ein Hinweis in eigener Sache: das Nutzen von Scripten oder ähnlichem geschieht immer auf eigene Gefahr.
    und damit
    :closed1:
    doch zu früh? dann bitte eine PN an mich
    MfG Walkuere
    Ein Kluger bemerkt alles, ein Dummer macht über alles eine Bemerkung.