// ==UserScript== // @name Grepolis Resources Manager // @version 2.0_ALPHA // @include /http[s]{0,1}://[a-z]{2}[0-9]{1,2}\.grepolis\.com/game*/ // @include https://*.forum.grepolis.com/* // @require http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js // @require https://code.jquery.com/ui/1.12.1/jquery-ui.js // @description A little handy script to help with resource management and more // @author MajorOrbital // @copyright 2020+ // @grant unsafeWindow // @grant GM_addStyle // @namespace https://greasyfork.org/users/451401 // @downloadURL none // ==/UserScript== //The game window, gamedata can be accessed through this constant. const uw = unsafeWindow; //https://imgur.com/a/WmetAfe //#region CSS GM_addStyle(` :root { --main: #ffe2a2 } #GRM_window { background-color: var(--main); display: none; height: 550px; width: 780px; z-index: 1100; position: absolute; top: 100px; left: 30vw; border: 2px black solid } #GRM_toolbar { height: 30px; border-bottom: 2px black solid; } #GRM_toolbar_list { list-style-type: none; margin: 0; padding-top: 3px; padding-left: 1px; overflow: hidden; top: 10px; } #GRM_title { padding-top: 3px; float: left; width: 40%; text-align: left; } #GRM_building { max-width: 360px; position: relative; left: 10px; } #GRM_buildings { margin-left: 5px; } #GRM_troops_container { margin-left: 5px; } #GRM_close { padding-top: 5px; float: left; } #GRM_gods{ height: 100px; width: 100px; position: relative; top: -415px; left: 50px; } .GRM_toolbar_item { height: 25px; float: left; width: 27%; text-align: center; border-left: 1px solid black; border-right: 1px solid black; border-top: 1px solid black; border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; margin: 1px } #GRM_close_img { margin-left: 10px; } #GRM_population_container{ max-width: 120px; position: relative; left: 5px; bottom: 450px; font-weight: bold; } #GRM_pop_icon{ position: relative; top: 2px; left: 5px; } .GRM_building_image { height: 40px; width: 40px; letter-spacing: -1px; margin: 0; display: inline-grid; } .GRM_building_level { position: relative; bottom: -25px; right: -10px; color: white; max-height: 18px; font-weight: bolder; } .GRM_selector { height: 40px; width: 30px; top: 10px; display: inline; position: relative; } .GRM_troop_input { width: 36px; } .GRM_building_input { width: 35px; } input.invalid { border: 2px solid red; background-color: rgba(128, 0, 0, 0.3) } input.valid { border: 2px solid green; background-color: rgba(0, 128, 0, 0.3) } .GRM_troop_container { max-width: 50px; z-index: 5; } .GRM_special_container { width: 168px; height: 42px; border: 1px solid black; overflow: hidden; /* add this to contain floated children */ } .GRM_special_child { width: 40px; height: 40px; float: left; margin-left: 1px; margin-right: 1px; padding-top: 1px; padding-bottom: 1px; } .GRM_label{ max-width: 450px; margin-top: 5px; margin-right: 0px; margin-bottom: 5px; margin-left: 0px; font-weight: bold; } .GRM_border{ border: #c78e25; border-width: medium; border-style: solid; } `); //#endregion class Utils { static checkMouseClicked(x, y, coords) { return ( coords.x <= x && x <= coords.x + 30 && coords.y <= y && y <= coords.y + 30 ); } static all_gods() { return "https://i.imgur.com/Kvb5gqn.png"; } static artemis() { return "https://i.imgur.com/yNL9x1M.png"; } static hades() { return "https://i.imgur.com/Via8HPf.png"; } static poseidon() { return "https://i.imgur.com/w2LtW83.png"; } static hera() { return "https://i.imgur.com/eNTFFg1.png"; } static athena() { return "https://i.imgur.com/u8SRGdE.png"; } static zeus() { return "https://i.imgur.com/35HpxKg.png"; } static no_god() { return "https://i.imgur.com/dFBR5Jd.png"; } static max_levels = { main: 25, hide: 10, place: 1, lumber: 40, stoner: 40, ironer: 40, market: 30, docks: 30, barracks: 30, wall: 25, storage: 35, farm: 45, academy: 36, temple: 30 }; static farm_pop = [ 14, 38, 69, 105, 145, 189, 237, 288, 342, 399, 458, 520, 584, 651, 720, 790, 863, 938, 1015, 1094, 1174, 1257, 1341, 1426, 1514, 1602, 1693, 1785, 1878, 1973, 2070, 2168, 2267, 2368, 2470, 2573, 2678, 2784, 2891, 3000, 3109, 3220, 3332, 3446, 3560 ]; //#region costs static main_cost = [ 0, 1, 3, 6, 9, 13, 17, 21, 25, 30, 35, 40, 46, 52, 58, 64, 70, 77, 84, 91, 98, 106, 113, 121, 129, 137 ]; static resources_cost = [ 0, 1, 2.4, 3.9, 5.7, 5.7, 9.4, 11.4, 13.5, 15.6, 17.8, 20, 22.3, 24.7, 27.1, 29.5, 32, 34.5, 37.1, 39.7, 42.3, 45, 47.6, 50.4, 53.1, 55.9, 58.7, 61.5, 64.4, 67.3, 70.2, 73.1, 76.1, 79.1, 82.1, 85.1, 88.2, 91.3, 94.3, 97.5, 100.6 ]; static barracks_cost = [ 0, 1, 2.5, 4.2, 6.1, 8.1, 10.3, 12.5, 14.9, 17.4, 20, 22.6, 25.3, 28.1, 30.9, 33.8, 36.8, 39.8, 42.8, 46, 49.1, 52.3, 55.6, 58.9, 62.3, 65.7, 69.1, 72.6, 76.1, 79.6, 83.2 ]; static docks_cost = [ 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120 ]; static hide_cost = [0, 3, 4.2, 5.2, 6, 6.7, 7.3, 7.9, 8.5, 9, 9.5]; static academy_cost = [ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108 ]; static temple_cost = [ 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150 ]; static market_cost = [ 0, 2, 4.3, 6.7, 9.2, 11.7, 14.4, 17, 19.7, 22.4, 25.2, 28, 30.8, 33.6, 36.5, 39.3, 42.2, 45.1, 48.1, 51, 54, 56.9, 59.9, 62.9, 66, 69, 72, 75.1, 78.1, 81.2, 84.3 ]; static wall_cost = [ 0, 2, 4.5, 7.2, 10, 12.9, 16, 19.1, 22.3, 25.6, 28.9, 32.3, 35.7, 39.2, 42.7, 46.3, 49.9, 53.5, 57.2, 60.9, 64.6, 68.4, 72.2, 76, 79.8, 83.7 ]; //#endregion static boar_img = "https://i.imgur.com/1HUB4xG.jpg"; static envoy_img = "https://i.imgur.com/nbXIVhL.png"; static griffin_img = "https://i.imgur.com/G0TYw28.jpg"; static centaur_img = "https://i.imgur.com/Y954Jv4.png"; static pegasus_img = "https://i.imgur.com/qusNCkM.png"; static harpy_img = "https://i.imgur.com/pCxA9u0.png"; static medusas_img = "https://i.imgur.com/3DdtHrv.png"; static cerberus_img = "https://i.imgur.com/BjLWnrL.png"; static eryn_img = "https://i.imgur.com/1FvJy0t.png"; static cyclops_img = "https://i.imgur.com/E8v5wu9.png"; static hydra_img = "https://i.imgur.com/tbc0PK1.png"; static minotaur_img = "https://i.imgur.com/Lw0vKSU.png"; static manticore_img = "https://i.imgur.com/bik0Jzj.png"; static unit_img = "https://i.imgur.com/xLOtNgs.png"; static lightship_img = "https://i.imgur.com/Y5WorTq.png"; static slow_transporter_img = "https://i.imgur.com/43NVBNT.png"; static bireme_img = "https://i.imgur.com/kLQCM99.png"; static catapult_img = "https://i.imgur.com/oFEOsXo.png"; static demolitionship_img = "https://i.imgur.com/JNfJ3h0.png"; static fast_transporter_img = "https://i.imgur.com/WYCQUZo.png"; static trireme_img = "https://i.imgur.com/0YlGkCP.png"; static colo_img = "https://i.imgur.com/e0W5k39.png"; static getMaxLevel(name) { switch (name) { case "main": return max_levels.main; case "hide": return max_levels.hide; case "place": return max_levels.place; case "lumber": return max_levels.lumber; case "stoner": return max_levels.stoner; case "ironer": return max_levels.ironer; case "market": return max_levels.market; case "docks": return max_levels.docks; case "barracks": return max_levels.barracks; case "wall": return max_levels.wall; case "storage": return max_levels.storage; case "farm": return max_levels.farm; case "academy": return max_levels.academy; case "temple": return max_levels.temple; default: return 1; } } static getSpecialBuilding(specialList) { for (let i in specialList) { if (specialList[i][1] === 1) return specialList[i][0]; } return null; } static getCostFromBuilding(key, value) { switch (key) { case "main": return Utils.main_cost[value]; case "hide": return Utils.hide_cost[value]; case "place": return 1; case "lumber": return Utils.resources_cost[value]; case "stoner": return Utils.resources_cost[value]; case "ironer": return Utils.resources_cost[value]; case "market": return Utils.market_cost[value]; case "docks": return Utils.docks_cost[value]; case "barracks": return Utils.barracks_cost[value]; case "wall": return Utils.wall_cost[value]; case "storage": return 0; case "farm": return 0; case "academy": return Utils.academy_cost[value]; case "temple": return Utils.temple_cost[value]; case "theater": return value === 1 ? 60 : 0; case "thermal": return value === 1 ? 60 : 0; case "library": return value === 1 ? 60 : 0; case "lighthouse": return value === 1 ? 60 : 0; case "tower": return value === 1 ? 60 : 0; case "statue": return value === 1 ? 60 : 0; case "oracle": return value === 1 ? 60 : 0; case "trade_office": return value === 1 ? 60 : 0; default: return 0; } } static getMythCost(n, god) { console.log("god :", god); console.log("n :", n); switch (god) { case "artemis": return n === 1 ? 20 : 35; case "athena": return n === 1 ? 12 : 20; case "poseidon": return n === 1 ? 40 : 50; case "hades": return n === 1 ? 30 : 55; case "zeus": return n === 1 ? 30 : 45; case "hera": return n === 1 ? 14 : 18; default: return 0; } } } class View { constructor() {} addMenuItem() { $("#ui_box > div.nui_main_menu > div.middle > div.content > ul").append( `
  • GRM
  • ` ); } initializeWindow() { $("body").append(`

    Enter the amount of troops you want of each type in here.

    The current maximum possible amount of each troop (+ your choices above)

    0 0 0 0 0 0 0 0
    0000/0000
    `); } fillGRMWindow(town) { $("#GRM_city_name").text(`${town.getName()}`); const buildings = town.buildings; $("#GRM_main_level").text(`${buildings.main}`); $("#GRM_hide_level").text(`${buildings.hide}`); $("#GRM_place_level").text(`${buildings.place}`); $("#GRM_lumber_level").text(`${buildings.lumber}`); $("#GRM_stoner_level").text(`${buildings.stoner}`); $("#GRM_ironer_level").text(`${buildings.ironer}`); $("#GRM_market_level").text(`${buildings.market}`); $("#GRM_docks_level").text(`${buildings.docks}`); $("#GRM_barracks_level").text(`${buildings.barracks}`); $("#GRM_wall_level").text(`${buildings.wall}`); $("#GRM_storage_level").text(`${buildings.storage}`); $("#GRM_farm_level").text(`${buildings.farm}`); $("#GRM_academy_level").text(`${buildings.academy}`); $("#GRM_temple_level").text(`${buildings.temple}`); $("#GRM_main_input").val(`${buildings.main}`); $("#GRM_hide_input").val(`${buildings.hide}`); $("#GRM_place_input").val(`${buildings.place}`); $("#GRM_lumber_input").val(`${buildings.lumber}`); $("#GRM_stoner_input").val(`${buildings.stoner}`); $("#GRM_ironer_input").val(`${buildings.ironer}`); $("#GRM_market_input").val(`${buildings.market}`); $("#GRM_docks_input").val(`${buildings.docks}`); $("#GRM_barracks_input").val(`${buildings.barracks}`); $("#GRM_wall_input").val(`${buildings.wall}`); $("#GRM_storage_input").val(`${buildings.storage}`); $("#GRM_farm_input").val(`${buildings.farm}`); $("#GRM_academy_input").val(`${buildings.academy}`); $("#GRM_temple_input").val(`${buildings.temple}`); var json_data = uw.ITowns.getCurrentTown() .getBuildings() .getBuildings(); var specialList = []; var counter = 0; for (var i in json_data) { if (counter !== 14) { counter++; continue; } specialList.push([i, json_data[i]]); } var special_1 = Utils.getSpecialBuilding(specialList.slice(0, 4)); var special_2 = Utils.getSpecialBuilding(specialList.slice(4)); if (special_1 !== null) { $(`#GRM_${special_1}`) .removeClass("GRM_passive") .addClass("GRM_active") .css( "background", `url('https://gpnl.innogamescdn.com/images/game/main/${special_1}.png')` ); } if (special_2 !== null) { $(`#GRM_${special_2}`) .removeClass("GRM_passive") .addClass("GRM_active") .css( "background", `url('https://gpnl.innogamescdn.com/images/game/main/${special_2}.png')` ); } $("#GRM_used_pop").text(`${town.getBuildingCost()}`); $("#GRM_total_pop").text(`${town.getTotalPopulation()}`); let god = town.god; this.changeIcon(god, $("#GRM_gods")); this.fillTroops( town.getTotalPopulation() - parseInt(town.getBuildingCost()), god ); } changeIcon(god, element) { switch (god) { case "artemis": $(element).prop("src", (Presenter.saved = Utils.artemis())); $("#GRM_myth_1_pos > img").prop("src", Utils.boar_img); $("#GRM_myth_2_pos > img").prop("src", Utils.griffin_img); $("#GRM_myth_1_want > img").prop("src", Utils.boar_img); $("#GRM_myth_2_want > img").prop("src", Utils.griffin_img); break; case "athena": $(element).prop("src", (Presenter.saved = Utils.athena())); $("#GRM_myth_1_pos > img").prop("src", Utils.centaur_img); $("#GRM_myth_2_pos > img").prop("src", Utils.pegasus_img); $("#GRM_myth_1_want > img").prop("src", Utils.centaur_img); $("#GRM_myth_2_want > img").prop("src", Utils.pegasus_img); break; case "poseidon": $(element).prop("src", (Presenter.saved = Utils.poseidon())); $("#GRM_myth_1_pos > img").prop("src", Utils.cyclops_img); $("#GRM_myth_2_pos > img").prop("src", Utils.hydra_img); $("#GRM_myth_1_want > img").prop("src", Utils.cyclops_img); $("#GRM_myth_2_want > img").prop("src", Utils.hydra_img); break; case "hades": $(element).prop("src", (Presenter.saved = Utils.hades())); $("#GRM_myth_1_pos > img").prop("src", Utils.cerberus_img); $("#GRM_myth_2_pos > img").prop("src", Utils.eryn_img); $("#GRM_myth_1_want > img").prop("src", Utils.cerberus_img); $("#GRM_myth_2_want > img").prop("src", Utils.eryn_img); break; case "zeus": $(element).prop("src", (Presenter.saved = Utils.zeus())); $("#GRM_myth_1_pos > img").prop("src", Utils.minotaur_img); $("#GRM_myth_2_pos > img").prop("src", Utils.manticore_img); $("#GRM_myth_1_want > img").prop("src", Utils.minotaur_img); $("#GRM_myth_2_want > img").prop("src", Utils.manticore_img); break; case "hera": $(element).prop("src", (Presenter.saved = Utils.hera())); $("#GRM_myth_1_pos > img").prop("src", Utils.harpy_img); $("#GRM_myth_2_pos > img").prop("src", Utils.medusas_img); $("#GRM_myth_1_want > img").prop("src", Utils.harpy_img); $("#GRM_myth_2_want > img").prop("src", Utils.medusas_img); break; default: $(element).prop("src", (Presenter.saved = Utils.no_god())); } } fillTroops(population, god) { console.log("god (fillTroops) :", god); const lightship_cost = 10; const bireme_cost = 8; const trireme_cost = 16; const demolitionship_cost = 8; const fast_transporter_cost = 21; const slow_transporter_cost = 39; const myth_1_cost = Utils.getMythCost(1, god); const myth_2_cost = Utils.getMythCost(2, god); const catapult_cost = 15; const colo_cost = 170; let ls_want = parseInt($("#GRM_ls_want > input").val()); let bir_want = parseInt($("#GRM_bir_want > input").val()); let trir_want = parseInt($("#GRM_trir_want > input").val()); let demo_want = parseInt($("#GRM_demo_want > input").val()); let colo_want = parseInt($("#GRM_colo_want > input").val()); let cata_want = parseInt($("#GRM_cata_want > input").val()); let envoy_want = parseInt($("#GRM_envoy_want > input").val()); let myth_1_want = parseInt($("#GRM_myth_1_want > input").val()); let myth_2_want = parseInt($("#GRM_myth_2_want > input").val()); let ls_pos = parseInt(population / lightship_cost); let bir_pos = parseInt(population / bireme_cost); let trir_pos = parseInt(population / trireme_cost); let demo_pos = parseInt(population / demolitionship_cost); let fast_pos = parseInt(population / fast_transporter_cost); let slow_pos = parseInt(population / slow_transporter_cost); let myth_1_pos = parseInt(population / myth_1_cost); let myth_2_pos = parseInt(population / myth_2_cost); $("#GRM_ls_pos > input").val(ls_pos); $("#GRM_bir_pos > input").val(bir_pos); $("#GRM_trir_pos > input").val(trir_pos); $("#GRM_demo_pos > input").val(demo_pos); $("#GRM_land_fast_pos > input").val(fast_pos); $("#GRM_land_slow_pos > input").val(slow_pos); $("#GRM_myth_1_pos > input").val(myth_1_pos); $("#GRM_myth_2_pos > input").val(myth_2_pos); } } class Model { constructor() { this._id = 0; this._towns = []; } initTowns() { uw.ITowns.towns_collection.getTowns().forEach(town => { let temp = new Town( town.attributes.id, town.attributes.name, town.attributes.god ); const t = uw.ITowns.getTown(town.id); temp.buildings = t.getBuildings().getBuildings(); temp.plow = t.getResearches().attributes.plow; temp.populationBoost = t.getPopulationExtra(); temp.getTotalPopulation(); temp.getBuildingCost(); this.towns.push(temp); }); } getTown(id) { for (let i = 0; i < this._towns.length; i++) { const town = this._towns[i]; if (town.id === id) { return town; } } } update() { return; } get towns() { return this._towns; } get id() { return this.id; } set id(id) { this._id = id; } } class Town { constructor(id, name, god) { this._id = id; this._name = name; this._buildings = { main: 1, hide: 0, place: 1, lumber: 0, stoner: 0, ironer: 0, market: 0, docks: 0, barracks: 0, wall: 0, storage: 0, farm: 1, academy: 0, temple: 0, theater: 0, thermal: 0, library: 0, lighthouse: 0, tower: 0, statue: 0, oracle: 0, trade_office: 0 }; this._population_boost = 0; this._has_plow = false; this._god = god; } getTotalPopulation() { let farm = Utils.farm_pop[this._buildings.farm - 1]; let thermal = this._buildings.thermal === 1; let total = thermal ? farm * 1.1 + this._population_boost : farm + this._population_boost; total = this._has_plow ? total + 200 : total; return total; } getBuildingCost() { var totalCost = 0; for (const key in this.buildings) { if (this.buildings.hasOwnProperty(key)) { const value = this.buildings[key]; totalCost += Utils.getCostFromBuilding(key, value); } } return parseInt(totalCost); } get id() { return this._id; } get buildings() { return this._buildings; } set buildings(b) { this._buildings = b; } get plow() { return this._has_plow; } /** * @param {Boolean} bool */ set plow(bool) { this._has_plow = bool; } get populationBoost() { return this._population_boost; } /** * @param {Number} boost */ set populationBoost(boost) { this._population_boost = boost; } get god() { return this._god; } /** * @param {String} god */ set god(god) { this._god = god; } getName() { return this._name; } } class Presenter { static saved = null; static artemis = { x: 17, y: 1 }; static athena = { x: 54, y: 1 }; static zeus = { x: 1, y: 26 }; static poseidon = { x: 17, y: 69 }; static hera = { x: 54, y: 69 }; static hades = { x: 69, y: 26 }; constructor(model, view) { this._model = model; this._view = view; } //uw.ITowns.getCurrentTown() addEventHandlers() { var temp = this; $("#GRM_button").on("click", function() { if (temp._model.towns.length === 0) { temp._model.initTowns(); } const town = temp._model.getTown(uw.ITowns.getCurrentTown().id); temp.openWindow(town); }); function switchTown() { if ($("#GRM_window").css("display") != "block") return; setTimeout(() => { temp._view.fillGRMWindow( temp._model.getTown(uw.ITowns.getCurrentTown().id) ); }, 100); } $("#ui_box > div.town_name_area > div.btn_next_town.button_arrow.right").on( "click", switchTown ); $("#ui_box > div.town_name_area > div.btn_prev_town.button_arrow.left").on( "click", switchTown ); $("#GRM_window").draggable(); $("#GRM_close_img").on("click", function() { $("#GRM_window").css("display", "none"); }); $(".GRM_input_building").each(function() { $(this).on("input", function() { var input = $(this); var value = input.val(); var attr_name = input.attr("name"); var name = attr_name.substring(0, attr_name.length - 6); var max = Utils.getMaxLevel(name); let int = parseInt(value); if (isNaN(parseInt(int)) || int < 0 || int > max) { input.removeClass("valid").addClass("invalid"); } else { input.removeClass("invalid").addClass("valid"); } temp._model.update(); temp._view.fillGRMWindow(); }); }); $(".GRM_special_child").each(function() { $(this).on("click", function() { const el = $(this).first(); const name = el.attr("id").substr(4); const parent = el.parent(); if (el.hasClass("GRM_active")) { el.removeClass("GRM_active").addClass("GRM_passive"); el.css( "background", `url('https://gpnl.innogamescdn.com/images/game/main/${name}_passive.png')` ); } else if (el.hasClass("GRM_passive")) { const active_el = parent.children(".GRM_active").first(); if (active_el.length !== 0) { const active_name = active_el.attr("id").substr(4); active_el.removeClass("GRM_active").addClass("GRM_passive"); active_el.css( "background", `url('https://gpnl.innogamescdn.com/images/game/main/${active_name}_passive.png')` ); } el.removeClass("GRM_passive").addClass("GRM_active"); el.css( "background", `url('https://gpnl.innogamescdn.com/images/game/main/${name}.png')` ); } }); }); $("#GRM_gods") .hover( function() { Presenter.saved = $(this).prop("src"); $(this).prop("src", Utils.all_gods()); }, function() { $(this).prop("src", Presenter.saved); } ) .click(function(e) { var parentOffset = $(this).offset(); var relX = e.pageX - parentOffset.left; var relY = e.pageY - parentOffset.top; if (Utils.checkMouseClicked(relX, relY, Presenter.artemis)) { temp._view.changeIcon("artemis", this); } if (Utils.checkMouseClicked(relX, relY, Presenter.athena)) { temp._view.changeIcon("athena", this); } if (Utils.checkMouseClicked(relX, relY, Presenter.zeus)) { temp._view.changeIcon("zeus", this); } if (Utils.checkMouseClicked(relX, relY, Presenter.hades)) { temp._view.changeIcon("hades", this); } if (Utils.checkMouseClicked(relX, relY, Presenter.poseidon)) { temp._view.changeIcon("poseidon", this); } if (Utils.checkMouseClicked(relX, relY, Presenter.hera)) { temp._view.changeIcon("hera", this); } }); } openWindow(town) { this._view.fillGRMWindow(town); $("#GRM_window").css("display", "block"); } } startup(); function startup() { "use strict"; let view = new View(); let model = new Model(); let presenter = new Presenter(model, view); view.addMenuItem(); view.initializeWindow(); presenter.addEventHandlers(); }