shigatora / LG Tools

// ==UserScript==
// @name         LG Tools
// @version      0.51
// @description  Tools to make your Grepolis prettier.
// @author       Vít Dolínek
// @include      http://*.grepolis.com/game/*
// @include      https://*.grepolis.com/game/*
// @icon64       https://st2.depositphotos.com/5943796/11382/v/950/depositphotos_113825054-stock-illustration-initial-letter-lg-green-swoosh.jpg
// @require      https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js
// @copyright    2020, LG (https://openuserjs.org/users/shigatora)
// @licence      MIT
// ==/UserScript==

const w = unsafeWindow || window;
const $ = w.jQuery || jQuery;
const troops = {};
let troopOptionSelected = {};
let tradeUnitSelected;
const farmPopulation = {
  1: 114,
  2: 121,
  3: 134,
  4: 152,
  5: 175,
  6: 206,
  7: 245,
  8: 291,
  9: 341,
  10: 399,
};

/**
 * Loads player's currently available troops.
 */
function loadTroops() {
  const towns = _.values(ITowns.getTowns());

  _.each(
    GameData.units,
    (unit) =>
      (troops[unit.id] = {
        name: unit.name,
        count: {
          inside: 0,
          outside: 0,
        },
      })
  );

  towns.map((town) => {
    const unitsInside = town.units();
    const unitsOutside = town.unitsOuter();

    for (const [name, value] of Object.entries(unitsInside)) {
      _.set(
        troops[name].count,
        "inside",
        parseInt(troops[name].count.inside) + value
      );
    }

    for (const [name, value] of Object.entries(unitsOutside)) {
      _.set(
        troops[name].count,
        "outside",
        parseInt(troops[name].count.outside) + value
      );
    }
  });
}

/**
 * Shows movements in conquest overview.
 * @param newChild
 * @param refChild
 */
function countConquestMovements(newChild, refChild) {
  const movementTab = $(document)
    .find("#unit_movements")
    .closest(".gpwindow_content .tab_content");
  const wrapper = $("<div />", {
    class: "lgt-conquest-movements town_groups_list",
    style:
      "width: 99%; display: flex; justify-content: center; position: relative !important; font-size: 20px;",
  });
  const supportMovementCount = movementTab.find(".support.incoming").length;
  const attackMovementCount = movementTab.find(".attack.incoming").length;

  const supportMovementWrapper = $("<div />", {
    style:
      "display: flex; align-items: center; padding: 0 5px; color: #a0c82d;",
  });
  const supportMovementIcon = $("<span />", {
    class: "support_icon",
  });
  const supportMovementText = $("<span />", {
    text: supportMovementCount,
    style: "padding-left: 4px;",
  });
  supportMovementWrapper.append(supportMovementIcon);
  supportMovementWrapper.append(supportMovementText);

  const attackMovementWrapper = $("<div />", {
    style: "display: flex; align-items: center; padding: 0 5px; color: red;",
  });
  const attackMovementIcon = $("<span />", {
    class: "attack_icon",
  });
  const attackMovementText = $("<span />", {
    text: attackMovementCount,
    style: "padding-left: 4px;",
  });
  attackMovementWrapper.append(attackMovementIcon);
  attackMovementWrapper.append(attackMovementText);

  wrapper.append(attackMovementWrapper);
  wrapper.append(supportMovementWrapper);

  if (!$(document).find(".lgt-conquest-movements").length) {
    wrapper.insertBefore(movementTab, refChild);
  } else {
    $(document).find(".lgt-conquest-movements").html(wrapper);
  }
}

/**
 * Shows movements in forum posts and private message posts.
 * @param newChild
 * @param refChild
 */
function countForumConquestMovements(newChild, refChild) {
  const movementTabs = $(".fight_report_classic.conquest.published");

  movementTabs.each((index, element) => {
    const wrapper = $("<div />", {
      class: "lgt-conquest-movements town_groups_list",
      style:
        "width: 99%; display: flex; justify-content: center; position: relative !important; font-size: 20px; margin: 10px 0;",
    });
    const supportMovementCount = $(element).find(".support.incoming").length;
    const attackMovementCount =
      $(element).find(".attack_sea.incoming").length +
      $(element).find(".attack_land.incoming").length;

    const supportMovementWrapper = $("<div />", {
      style:
        "display: flex; align-items: center; padding: 0 5px; color: #a0c82d;",
    });
    const supportMovementIcon = $("<span />", {
      class: "support_icon",
    });
    const supportMovementText = $("<span />", {
      text: supportMovementCount,
      style: "padding-left: 4px; font-weight: bold;",
    });
    supportMovementWrapper.append(supportMovementIcon);
    supportMovementWrapper.append(supportMovementText);

    const attackMovementWrapper = $("<div />", {
      style: "display: flex; align-items: center; padding: 0 5px; color: red;",
    });
    const attackMovementIcon = $("<span />", {
      class: "attack_icon",
    });
    const attackMovementText = $("<span />", {
      text: attackMovementCount,
      style: "padding-left: 4px; font-weight: bold;",
    });
    attackMovementWrapper.append(attackMovementIcon);
    attackMovementWrapper.append(attackMovementText);

    wrapper.append(attackMovementWrapper);
    wrapper.append(supportMovementWrapper);

    if (!$(element).find(".lgt-conquest-movements").length) {
      wrapper.insertBefore($(element).find("#unit_movements li")[0], refChild);
    } else {
      $(this).find(".lgt-conquest-movements").html(wrapper);
    }
  });
}

/**
 * Counts population usage in every city and displays it in town list overview.
 * @param townId
 */
function populationUsage(townId = null) {
  let buildings = GameData.buildings;
  layout_main_controller.sub_controllers[14].controller.town_groups_list_view
    .render;

  Object.values(ITowns.getTowns()).map((town) => {
    if (townId && town.id !== townId) return;
    let populationUsedOnBuildings = 0;
    const buildingLevels = town.buildings().getLevels();
    const maxPopulationWithoutBonuses =
      buildingLevels.farm > 10
        ? Math.floor(
            buildings.farm.farm_factor *
              Math.pow(buildingLevels.farm, buildings.farm.farm_pow)
          )
        : farmPopulation[buildingLevels.farm];
    const thermalBathFactor = town.getBuildings().getBuildingLevel("thermal")
      ? 1.1
      : 1.0;
    const plowResearchValue = town.getResearches().attributes.plow ? 200 : 0;
    const extraPopulation = town.getPopulationExtra();
    const isPygmalionActive = town.god() === "aphrodite";

    const pygmalionBonus = isPygmalionActive
      ? town.getBuildings().getBuildingLevel("farm") * 5
      : 0;

    const maximumPopulationWithBonuses =
      maxPopulationWithoutBonuses * thermalBathFactor +
      plowResearchValue +
      pygmalionBonus +
      extraPopulation;

    for (const building in buildingLevels) {
      if (buildingLevels.hasOwnProperty(building)) {
        populationUsedOnBuildings += Math.round(
          buildings[building].pop *
            Math.pow(buildingLevels[building], buildings[building].pop_factor)
        );
      }
    }

    const populationUsedInMilitary = parseInt(
      maximumPopulationWithBonuses -
        (populationUsedOnBuildings + town.getAvailablePopulation()),
      10
    );

    const percentageOfPopulationFree = Math.round(
      (populationUsedInMilitary /
        (maximumPopulationWithBonuses - populationUsedOnBuildings)) *
        100
    );

    let percentageColor = "";

    if (percentageOfPopulationFree <= 20) percentageColor = "red";
    if (percentageOfPopulationFree > 20 && percentageOfPopulationFree <= 70)
      percentageColor = "#ffa600";
    if (percentageOfPopulationFree >= 70) percentageColor = "#49d004";

    const percentageDiv = $(document).find(
      `.item.town_group_town[data-townid=${town.id}] .population-percentage`
    );

    const percentage = $("<div />", {
      class: "population-percentage",
      style: `float: right; color: ${percentageColor};text-shadow: 0.5px 0.5px 0.5px black, 0.5px 0.5px 1px black;`,
      html: `${percentageOfPopulationFree}%`,
    });

    if (percentageDiv.length) {
      percentageDiv.html(percentage[0].outerHTML);
    } else {
      $(document)
        .find(`.item.town_group_town[data-townid=${town.id}]`)
        .append(percentage[0].outerHTML);
    }
  });
}

/**
 * Initializes trading between cities.
 * @param newChild
 * @param refChild
 */
function cityTrader(newChild, refChild) {
  if (ITowns.towns[Game.townId].getBuildings().getBuildingLevel("market") < 1) return;
  $.each($(document).find("[class^=trade_tab_target_]"), (index, element) => {
    let tradeTabId = element.className.match(/trade_tab_target_(\d+)/)[1];

    if ("undefined" == typeof troopOptionSelected[tradeTabId])
      troopOptionSelected[tradeTabId] = {
        troop: null,
        percent: 0,
      };

    if (!$(element).find(`#trade_input_${tradeTabId}`).length) {
      let previousSliderValue = 0;

      function calculateResources(v, t = null) {
        let dividedResourceValue = 0;
        let totalWood = 0;
        let totalStone = 0;
        let totalIron = 0;
        previousSliderValue = v;

        if ($(`.lgt_troop_select_unit_${tradeTabId}`).val() || t) {
          const unit =
            GameData.units[
              $(`.lgt_troop_select_unit_${tradeTabId}`).val() || t
            ];
          const totalResourceCost =
            unit.resources.wood + unit.resources.stone + unit.resources.iron;
          const ratioWood = unit.resources.wood / totalResourceCost;
          const ratioStone = unit.resources.stone / totalResourceCost;
          const ratioIron = unit.resources.iron / totalResourceCost;

          totalWood = Math.floor(v * ratioWood);
          totalStone = Math.floor(v * ratioStone);
          totalIron = Math.floor(v * ratioIron);
        } else {
          dividedResourceValue = Math.floor(v / 3);
        }

        $(element)
          .find("#trade_type_wood input")
          .select()
          .val(dividedResourceValue || totalWood)
          .blur();
        $(element)
          .find("#trade_type_stone input")
          .select()
          .val(dividedResourceValue || totalStone)
          .blur();
        $(element)
          .find("#trade_type_iron input")
          .select()
          .val(dividedResourceValue || totalIron)
          .blur();
        $(element).find(`#trade_input_${tradeTabId}`).val(v);
      }

      $(`<div class="trade-slider-wrapper" style="display: flex;width: 100%;align-items: center;justify-content: center;">
            <div class="windowmgr_slider" style="width: 30%">
                <div class="grepo_slider" id="lgt_trage_slider_${tradeTabId}">
                    <div class="button_down left js-button-left"></div>
                    <div class="bar js-slider js-slider-handle-container">
                    </div>
                <div class="button_up right js-button-right"></div>
                </div>
            </div>
            <input type="text" class="lgt_troop_select_unit_${tradeTabId}" hidden />
            <div class="textbox" style="width:10%">
                <div class="left"></div>
                <div class="right"></div>
                <div class="middle">
                  <div class="initial-message-box js-empty" style="display: none;"></div>
                  <div class="ie7fix"><input type="text" id="trade_input_${tradeTabId}" tabindex="1" placeholder=""
                   pattern="[0-9]*"></div>
                  <div class="clear-button js-clear"></div>
                </div>
                <div class="error-msg js-txt-error-msg"></div>
            </div>
        </div>`).insertBefore($(element).find("#duration_container"), refChild);

      const slider = $(`#lgt_trage_slider_${tradeTabId}`).grepoSlider({
        min: 0,
        max: ITowns.getCurrentTown().getAvailableTradeCapacity(),
        step: ITowns.getCurrentTown().getAvailableTradeCapacity() / 10,
        value: Math.round(
          (ITowns.getCurrentTown().getAvailableTradeCapacity() / 100) *
            troopOptionSelected[tradeTabId].percent
        ),
      });

      const troopRatioSelector = $("<div />", {
        id: `lgt_troop_selector_${tradeTabId}`,
        class: `dropdown default`,
        style: "width: 100px; position: absolute; left: 30px; top: 98px;",
      }).insertBefore($(element).find(".content .resource_selector")[0]);
      troopRatioSelector
        .dropdown({
          id: tradeTabId,
          options: Object.values(GameData.units).map((troopInformation) => ({
            value: troopInformation.id,
            name: troopInformation.name,
          })),
          value:
            $(`.lgt_troop_select_unit_${tradeTabId}`).val() ||
            troopOptionSelected[tradeTabId].troop ||
            null,
        })
        .on("dd:change:value", function (e, i) {
          troopOptionSelected[tradeTabId].troop = i;
          $(`.lgt_troop_select_unit_${tradeTabId}`).val(i);
          tradeUnitSelected = i;
          slider.trigger("sl:change:value");
        });

      if (troopOptionSelected[tradeTabId].percent) {
        const tradeAmountSelected = Math.round(
          (ITowns.getCurrentTown().getAvailableTradeCapacity() / 100) *
            troopOptionSelected[tradeTabId].percent
        );

        calculateResources(
          tradeAmountSelected,
          troopOptionSelected[tradeTabId].troop
        );
      }

      slider.on("sl:change:value", (e, _sl, v) => {
        v = v || previousSliderValue;
        troopOptionSelected[tradeTabId].percent = Math.round(
          (v / ITowns.getCurrentTown().getAvailableTradeCapacity()) * 100
        );
        calculateResources(v, tradeUnitSelected);
      });
    }
  });
}

/**
 * Initializes and handles buttons that send resources needed for City Festival.
 */
function cultureTrader() {
  $.each($(document).find("[class^=trade_tab_target_]"), (index, element) => {
    let tradeTabId = element.className.match(/trade_tab_target_(\d+)/)[1];

    if (!ITowns.isMyTown(tradeTabId)) return;

    const resourceIndicators = $(element).find(".town-capacity-indicator");
    $.each(resourceIndicators, (index, element) => {
      let top, type;
      if (index === 0) {
        top = 218;
        type = "wood";
      }
      if (index === 1) {
        top = 251;
        type = "stone";
      }
      if (index === 2) {
        top = 286;
        type = "iron";
      }
      if ($(element).find(".culture-trade").length !== 3) {
        $(`<div class="btn_trade_button culture-trade button_new" data-townId="${tradeTabId}"
            data-type="${type}" style="width: 33px;position: absolute;top: ${top}px;right: 55px;">
          <div class="left"></div>
          <div class="right"></div>
          <div class="caption js-caption"><img src="https://gpus.innogamescdn.com/images/game/overviews/culture_25x25.png" style="position: absolute;right: 2px;top: -1px;" align="absmiddle"><div class="effect js-effect"></div></div>
      </div>`).insertAfter(element);
      }
    });
  });

  $(".culture-trade").on("click", function () {
    const town = ITowns.getTown($(this).data("townid"));
    const resourceType = $(this).data("type");
    const currentResources = town.getCurrentResources();

    if (resourceType === "wood" || resourceType === "iron") {
      let resourcesNeeded = 15000 - currentResources[resourceType];
      resourcesNeeded > ITowns.getCurrentTown().getAvailableTradeCapacity()
        ? (resourcesNeeded = ITowns.getCurrentTown().getAvailableTradeCapacity())
        : resourcesNeeded;

      resourcesNeeded > 0
        ? $(this)
            .closest("[class^=trade_tab_target_]")
            .find(`#trade_type_${resourceType} input`)
            .select()
            .val(resourcesNeeded)
            .blur()
        : null;
    }

    if (resourceType === "stone") {
      let resourcesNeeded = 18000 - currentResources[resourceType];
      resourcesNeeded > ITowns.getCurrentTown().getAvailableTradeCapacity()
        ? (resourcesNeeded = ITowns.getCurrentTown().getAvailableTradeCapacity())
        : "";
      resourcesNeeded > 0
        ? $(this)
            .closest("[class^=trade_tab_target_]")
            .find(`#trade_type_${resourceType} input`)
            .select()
            .val(resourcesNeeded)
            .blur()
        : null;
    }
  });
}

/**
 * Initialize all required particles on game:load event.
 */
$(document).on("game:load", function () {
  "use strict";

  var windows = require("game/windows/ids");

  $(document).ajaxComplete(function (d, f, c) {
    if ("undefined" != typeof c) {
      d = c.url.replace(/\/game\/(.*)\?.*/, "$1");
      const urlParams = new URLSearchParams(c.url);
      var l =
        "frontend_bridge" !== d
          ? d
          : -1 < c.url.indexOf("json")
          ? JSON.parse(unescape(c.url).split("&")[3].split("=")[1]).window_type
          : d;
      if ("frontend_bridge" === d) {
        var m = WM.getWindowByType(l)[0];
      }
      $.each(Layout.wnd.getAllOpen(), function (c, d) {
        c = Layout.wnd.GetByID(d.getID());
        switch (c.getController()) {
          case "command_info":
            switch (c.getContext().sub) {
              case "command_info_conquest_movements":
                countConquestMovements();
                break;
            }
            break;
          case "alliance_forum":
            countForumConquestMovements();
            break;
          case "message":
            countForumConquestMovements();
            break;
          case "town_overviews_command_overview":
            populationUsage();
            break;
          case "town_info":
            switch (c.getContext().sub) {
              case "town_info_trading":
                cityTrader();
                cultureTrader();
                break;
            }
            break;
        }
      });
    }
  });

  (function () {
    let i = 0;
    while (
      layout_main_controller.sub_controllers[i].name !== "town_name_area"
    ) {
      i++;
    }

    layout_main_controller.sub_controllers[
      i
    ].controller.town_groups_list_view.render_old =
      layout_main_controller.sub_controllers[
        i
      ].controller.town_groups_list_view.render;

    layout_main_controller.sub_controllers[
      i
    ].controller.town_groups_list_view.render = function () {
      layout_main_controller.sub_controllers[
        i
      ].controller.town_groups_list_view.render_old();
      populationUsage();
    };

    loadTroops();
  })();

  (function () {
    const troopOverviewIcon = $("<div />", {
      class: "icon js-caption",
      style: `background: url(https://gppt.innogamescdn.com/images/game/autogenerated/layout/layout_d1cf0d4.png) no-repeat 0 -635px;
              width: 26px;
              height: 27px;
              position: absolute;
              right: 10%;
              top: 3%;`,
    });
    const troopOverviewButton = $("<div />", {
      class: "circle_button",
      style: "position: absolute; right: 33px; top: 0; height: 31px",
    }).append(troopOverviewIcon);
    troopOverviewButton.bind("click", () => WF.open("lgt_troopoverview"));

    const helpIcon = $("<span />", {
      style: "position: absolute; color: #fff; top: 7px; right: 12px;",
    }).text("?");
    const helpButton = $("<div />", {
      class: "circle_button",
      style: "position: absolute; right: 0; top: 0; height: 31px",
    });
    helpButton.append(helpIcon);
    helpButton.bind("click", () => WF.open("lgt_help"));

    const cityOverviewIcon = $("<div />", {
      class: "pointer",
    });
    const cityOverviewButton = $("<div />", {
      class: "circle_button city_overview",
      style: "position: absolute; right: 66px; top: 0; height: 31px",
    }).append(cityOverviewIcon);
    cityOverviewButton.bind("click", () => WF.open("lgt_cityoverview"));

    const toolbarMiddle = $(".nui_toolbar .middle");
    toolbarMiddle.append(troopOverviewButton);
    toolbarMiddle.append(cityOverviewButton);
    toolbarMiddle.append(helpButton);
  })();

  (function () {
    require("game/windows/ids").LgT_TroopOverview = "lgt_troopoverview";
    (function () {
      function b(type) {
        loadTroops();
        let wrapper = $("<div />", {
          id: "troop_overview_wrapper",
        });
        _.each(troops, (unit, unitKey) => {
          let text;
          switch (type) {
            case "all":
              text = unit.count.inside + unit.count.outside;
              break;
            case "outside":
              text = unit.count.outside;
              break;
            case "inside":
              text = unit.count.inside;
              break;
          }
          let troopCount = $("<span />", {
            style:
              "font-size: inherit; bottom: 0; right: 0; text-shadow: 1px 1px 1px black, 1px 1px 2px black;",
            text: text,
          });
          let unitBox = $("<div />", {
            class: `unit index_unit bold unit_icon40x40 ${unitKey}`,
          }).append(troopCount);
          wrapper.append(unitBox);
        });

        return wrapper;
      }

      (function () {
        var ae = w.GameControllers.TabController,
          a = ae.extend({
            initialize: function () {
              ae.prototype.initialize.apply(this, arguments);
            },
            render: function () {
              this.getWindowModel().showLoading();
              this.$el.html(b("all"));
              this.getWindowModel().hideLoading();
            },
          });
        w.GameViews.LgTV_TroopOverviewAll = a;
      })();
      (function () {
        var oe = w.GameControllers.TabController,
          o = oe.extend({
            initialize: function () {
              oe.prototype.initialize.apply(this, arguments);
              this.registerListeners();
            },
            registerListeners: function () {
              $.Observer("town:units:change").subscribe(this._units.bind(this));
            },
            render: function () {
              this.getWindowModel().showLoading();
              this.$el.html(b("outside"));
              this.getWindowModel().hideLoading();
            },
            _units: function () {
              setTimeout(() => {
                this.render();
              }, 100);
            },
          });

        w.GameViews.LgTV_TroopOverviewOutside = o;
      })();
      var ie = w.GameControllers.TabController,
        i = ie.extend({
          initialize: function () {
            ie.prototype.initialize.apply(this, arguments);
            this.registerListeners();
          },
          registerListeners: function () {
            $.Observer("town:units:change").subscribe(this._units.bind(this));
          },
          render: function () {
            this.getWindowModel().showLoading();
            this.$el.html(b("inside"));
            this.getWindowModel().hideLoading();
          },
          _units: function () {
            setTimeout(() => {
              this.render();
            }, 100);
          },
        });
      w.GameViews.LgTV_TroopOverviewInside = i;
    })();
  })();

  (function () {
    function a() {
      return `
                <div class="keyboard" style="
                        width: 20px;
                        height: 20px;
                        border: 1px solid;
                        background-color: #fff;
                        font-weight: 900;
                        text-align: center;
                        font-size: medium;
                        margin: 5px;
                        display: inline-block;
                    ">F</div> - Farming villages (Premium required)<br />
                <div class="keyboard" style="
                        width: 20px;
                        height: 20px;
                        border: 1px solid;
                        background-color: #fff;
                        font-weight: 900;
                        text-align: center;
                        font-size: medium;
                        margin: 5px;
                        display: inline-block;
                    ">C</div> - Culture overview (Premium required)<br />
            `;
    }

    require("game/windows/ids").LgT_Help = "lgt_help";

    var ie = w.GameControllers.TabController,
      i = ie.extend({
        initialize: function () {
          ie.prototype.initialize.apply(this, arguments);
        },
        render: function () {
          this.getWindowModel().showLoading();
          this.$el.html(a());
          this.getWindowModel().hideLoading();
        },
      });

    w.GameViews.LgTV_Help = i;
  })();

  (function () {
    function a() {
      const castedPowers = Object.values(
        ITowns.getCurrentTown().getCastedPowers()
      );
      const wrapper = $("<div />");

      castedPowers.map((castedPower) => {
        const tooltip = GameDataPowers.getTooltipPowerData(
          GameData.powers[castedPower.power_id],
          castedPower.configuration,
          castedPower.configuration.level
        );
        const powerImage = $("<div />", {
          class: `casted_power power_icon45x45 ${GameDataPowers.getCssPowerId(
            castedPower
          )} ${
            castedPower.configuration.level
              ? `lvl lvl${castedPower.configuration.level}`
              : ""
          }`,
          style: "width: 45px; height: 45px;",
        });
        const powerTextWrapper = $("<div />", {
          style:
            "display: flex; flex-direction: column; margin: 0 5px; max-width: calc(100% - 60px)",
        });
        const powerTextExpiration = $("<div />", {
          html: `<b>${
            castedPower.end_at
              ? `Power until: ${readableUnixTimestamp(
                  castedPower.end_at,
                  "player_timezone",
                  {
                    extended_date: !0,
                  }
                )}`
              : "Permanently"
          }</b>`,
        });
        const powerTextDescription = $("<div />").html(tooltip.i_effect).text();
        const powerWrapper = $("<div />", {
          style: "display: flex; width: 100%; padding: 5px",
        });

        powerTextWrapper.append(powerTextExpiration);
        powerTextWrapper.append(powerTextDescription);
        powerWrapper.append(powerImage);
        powerWrapper.append(powerTextWrapper);

        wrapper.append(powerWrapper);
      });

      return wrapper;
    }

    require("game/windows/ids").LgT_CityOverview = "lgt_cityoverview";

    var ie = w.GameControllers.TabController,
      i = ie.extend({
        initialize: function () {
          ie.prototype.initialize.apply(this, arguments);
          this.registerListeners();
        },
        registerListeners: function () {
          $(document).on(GameEvents.town.town_switch, () => this.render());
        },
        render: function () {
          this.getWindowModel().showLoading();
          this.$el.html(a());
          this.getWindowModel().hideLoading();
        },
      });

    w.GameViews.LgTV_CityOverviewEffects = i;
  })();

  (function () {
    require("game/windows/ids").LgT_CityOverview = "lgt_cityoverview";
    var a = w.GameViews,
      b = w.WindowFactorySettings,
      c = require("game/windows/ids"),
      e = require("game/windows/tabs"),
      f = c.LgT_CityOverview;
    b[f] = function (b) {
      b = b || {};

      return us.extend({
        title: "City Overview",
        window_type: f,
        minheight: 200,
        maxheight: 630,
        width: 830,
        tabs: [
          {
            type: "effects",
            title: "Effects",
            content_view_constructor: a.LgTV_CityOverviewEffects,
            hidden: false,
          },
        ],
        max_instances: 1,
        activepagenr: 0,
        minimizable: !0,
      });
    };
  })();

  (function () {
    require("game/windows/ids").LgT_Help = "lgt_help";
    var a = w.GameViews,
      b = w.WindowFactorySettings,
      c = require("game/windows/ids"),
      e = require("game/windows/tabs"),
      f = c.LgT_Help;
    b[f] = function (b) {
      b = b || {};

      return us.extend({
        title: "LG Tools Help",
        window_type: f,
        minheight: 200,
        maxheight: 630,
        width: 830,
        tabs: [
          {
            type: "shortcuts",
            title: "Shortcuts",
            content_view_constructor: a.LgTV_Help,
            hidden: false,
          },
        ],
        max_instances: 1,
        activepagenr: 0,
        minimizable: !0,
      });
    };
  })();

  (function () {
    require("game/windows/ids").LgT_TroopOverview = "lgt_troopoverview";
    var a = w.GameViews,
      b = w.WindowFactorySettings,
      c = require("game/windows/ids"),
      e = require("game/windows/tabs"),
      f = c.LgT_TroopOverview;
    b[f] = function (b) {
      b = b || {};

      return us.extend({
        title: "Troop Overview",
        window_type: f,
        minheight: 200,
        maxheight: 630,
        width: 500,
        tabs: [
          {
            type: "all",
            title: "All",
            content_view_constructor: a.LgTV_TroopOverviewAll,
            hidden: false,
          },
          {
            type: "inside",
            title: "Home",
            content_view_constructor: a.LgTV_TroopOverviewInside,
            hidden: false,
          },
          {
            type: "outside",
            title: "Outside",
            content_view_constructor: a.LgTV_TroopOverviewOutside,
            hidden: false,
          },
        ],
        max_instances: 1,
        activepagenr: 0,
        minimizable: !0,
      });
    };
  })();

  (function () {
    $("head").append(`
      <style>
        .farm_village_island_available {
            background: red !important;
        }
        .farm_village_island_farmed {
            background: green !important;
        }
        .farm_village_town_hidden {
            display: none;
        }
      </style>
    `);
  })();
});