Skip to content

Instantly share code, notes, and snippets.

@Silvyre
Last active May 20, 2024 18:16
Show Gist options
  • Save Silvyre/7e73756f108dc987a0d12d609e615371 to your computer and use it in GitHub Desktop.
Save Silvyre/7e73756f108dc987a0d12d609e615371 to your computer and use it in GitHub Desktop.
πŸ§™πŸ‘ AutoControl for Colonist.io (ACCio): play Colonist.io using your keyboard! Setup instructions in comments below.
{"customEntities":{"script":[["1",{"name":"wall.js","value":{"mdTime":1641400238352,"srcCode":"await ACCio(_ => {\n socketGameSend.buildCityWall();\n selectNextAfterDelay();\n});"}}],["2",{"name":"setup.js","value":{"mdTime":1656815986599,"srcCode":" try {\n return ACCio(_ => console.log(\"ACCio is already enabled! Try refreshing if you're having trouble.\"));\n }\n catch (e) { console.error(e) }\n\n try {\n await ACtl.runInPageCtx('https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js');\n }\n catch {\n return ACtl.runInPageCtx(_ => console.error('ACCio failed to load all required libraries.'));\n }\n\n ACCio = new Proxy(ACtl.runInPageCtx, {\n apply: (target, thisArg, argumentsList) => {\n if (['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) {\n return;\n }\n\n try { return target(...argumentsList); }\n catch (e) { console.error(e) }\n }\n });\n\n await ACtl.runInPageCtx(_ => waitForKeyElements('canvas[style*=\"touch-action: none\"]', async _ => {\n if (window.accioEnabled) {\n return;\n }\n\n await new Promise(r => setTimeout(r, 500));\n\n if (!uiGameTradeInfoController) {\n console.error('ACCio could not find the required Window attribute - try refreshing the page.');\n return;\n }\n\n canvas = document.querySelector('canvas');\n gameManager = uiGameTradeInfoController.uiGameManager;\n socketGameSend = gameManager.socketGameSend;\n eventController = gameManager.eventController;\n mechanics = eventController.uiGameMechanics;\n tradeController = gameManager.tradeController;\n bankController = gameManager.bankController;\n mapController = gameManager.mapController;\n mapView = mapController.mapView;\n highlightController = mapController.highlightController;\n highlightDiceController = mechanics.find(o => o.highlightDiceNumbers);\n cardController = mechanics.find(o => o.getCardFromHand);\n popupController = mechanics.find(o => o.popupW);\n selectPlayerToStealController = mechanics.find(o => o.updateCheckmark);\n robberController = mechanics.find(o => o.lastRobberTile);\n stateController = mechanics.find(o => o.displayActionState);\n expandableButtons = gameManager?.actionsController?.buttonViews?.filter(o => o.expandedButtons?.length >= 0) || [];\n turnButtonView = gameManager.actionsController.buttonViews.find(o => o.action.toString().includes('TurnButton'));\n CardCountView = mechanics.find(o => o.initResourceCardCountViews).cardCountViewContainer.children.at(-1).constructor;\n gameState = gameManager.gameState;\n mapState = gameState.mapState;\n myColor = gameState.myColor;\n hideBankCards = gameState.gameSettings.hideBankCards;\n tileCorners = mapState.tileState.tileCorners;\n tileEdges = mapState.tileState.tileEdges;\n tileFaces = mapState.tileState.tiles;\n hexH = mapView.hexagonHeight;\n hexW = mapView.hexagonWidth;\n\n a_ = ['None', 'GameSetupPlaceSettlement', 'GameSetupPlaceCity', 'GameSetupRoadPlacement', 'PlaceRoad', 'PlaceRoadForFree', 'PlaceSettlement', 'PlaceCity', 'PlaceCityWithDiscount', 'PlaceShip', 'PlaceShipForFree', 'SelectShipToMove', 'MoveShip', 'PlaceCityWall', 'PlaceCityWallForFree', 'PlaceKnight', 'PlaceKnightForFree', 'UpgradeKnight', 'UpgradeKnightForFree', 'ActivateKnight', 'SelectKnightToTakeAction', 'SelectKnightAction', 'MoveKnightOffTurn', 'SelectKnightToRemove', 'PlaceRobberOrPirate', 'PlaceRobberOnly', 'PlacePirateOnly', 'SelectWhoToRob', 'SelectCardsToDiscard', 'SelectProgressCardsToDiscard', 'Place2MoreRoadBuilding', 'Place1MoreRoadBuilding', 'Select2ResourcesForYearOfPlenty', 'Select1ResourceForMonopoly', 'SelectCardsForPendingDistributions', 'PlaceMetropolis', 'SelectProgressCard', 'SelectCityToPillage', 'PlaceMerchant', 'SelectDiceForAlchemist', 'SelectTileProductionNumbersToSwap', 'SelectPlayerForDeserter', 'SelectRoadToRemove', 'DiplomatSelectWhetherToPlaceNewEdgePiece', 'IntrigueSelectKnightToMove', 'SpySelectPlayer', 'SpySelectProgressCard', 'SelectCardsForWedding', 'CommercialHarborSelectPlayerAndResource', 'CommercialHarborOpponentSelectsCard', 'MasterMerchantSelectPlayer', 'MasterMerchantSelectCards', 'MerchantFleetSelectResource', 'ResourceMonopolySelectResource', 'CommodityMonopolySelectResource'].reduce((obj, e, idx) => ({ [e]: idx, ...obj }), {});\n b_ = ['Empty', 'Settlement', 'City', 'DestroyedCity', 'KnightActiveLevel1', 'KnightActiveLevel2', 'KnightActiveLevel3', 'KnightInactiveLevel1', 'KnightInactiveLevel2', 'KnightInactiveLevel3'].reduce((obj, e, idx) => ({ [e]: idx, ...obj }), {});\n c_ = ['ResourceBack', 'Lumber', 'Brick', 'Wool', 'Grain', 'Ore', 'DevelopmentBack', 'Knight', 'VictoryPoint', 'Monopoly', 'RoadBuilding', 'YearOfPlenty', 'CommodityBack', 'Cloth', 'Coin', 'Paper', 'ProgressCardTradeBack', 'ProgressCardTradeCommercialHarbor', 'ProgressCardTradeMasterMerchant', 'ProgressCardTradeMerchant', 'ProgressCardTradeMerchantFleet', 'ProgressCardTradeResourceMonopoly', 'ProgressCardTradeCommodityMonopoly', 'ProgressCardPoliticsBack', 'ProgressCardPoliticsBishop', 'ProgressCardPoliticsConstitution', 'ProgressCardPoliticsDeserter', 'ProgressCardPoliticsDiplomat', 'ProgressCardPoliticsIntrigue', 'ProgressCardPoliticsSaboteur', 'ProgressCardPoliticsSpy', 'ProgressCardPoliticsWarlord', 'ProgressCardPoliticsWedding', 'ProgressCardScienceBack', 'ProgressCardScienceAlchemist', 'ProgressCardScienceCrane', 'ProgressCardScienceEngineer', 'ProgressCardScienceInventor', 'ProgressCardScienceIrrigation', 'ProgressCardScienceMedicine', 'ProgressCardScienceMining', 'ProgressCardSciencePrinter', 'ProgressCardScienceRoadBuilding', 'ProgressCardScienceSmith'].reduce((obj, e, idx) => ({ [e]: idx, [idx]: e, ...obj }), {});\n e_ = ['ContinueGame', 'GameStateUpdated', 'PlayerControllerStateUpdated', 'DiceStateUpdated', 'BankStateUpdated', 'MapStateUpdated', 'GameSettingsUpdated', 'AmountOfCardsToDiscardUpdated', 'AmountOfCardsToSelect', 'SelectCardsToDiscard', 'SelectCardsFromBankUsingDevelopmentCard', 'SelectCardsForPendingDistribution', 'SelectCardToGiveToAnotherPlayer', 'ConfirmUseDevelopmentCard', 'PlayersTakingAction', 'PlayersDoneTakingAction', 'StealDevelopmentCardFromPlayer', 'StealResourceCardFromPlayer', 'SelectPlayer', 'SelectPlayerForDevelopmentCard', 'SelectPlayerAndCard', 'SelectDice', 'GivePlayerCardFromTile', 'ExchangeCards', 'CloseTradeUI', 'ShowTradeUI', 'EmbargoStatusUpdated', 'RemoveTradeOffer', 'TradeOfferRejected', 'TradeOfferAccepted', 'NewTradeOfferReceived', 'BoldTextInTradeWindow', 'CloseDiscardCardUI', 'ShowDiscardCardUI', 'ClosePopupUI', 'CancelSpecialBuildPhase', 'SetRoadEdgeHighlight', 'SetShipEdgeHighlight', 'SetCornerHighlight', 'SetTileHighlight', 'HighlightDiceNumbersForInventor', 'VoteReceived', 'PlayerReceivedAchievement', 'CavasResized', 'ClickedMultiButton', 'SpectatorCountUpdated', 'KnightStateReceived', 'KnightStateUpdated', 'BarbarianInvasionStateUpdated', 'CityImprovementStateReceived', 'CityImprovementStateUpdated', 'ForceShowCityImprovementButtons', 'UnlockedCityImprovments', 'PlayerReceivedMetropolis', 'MerchantStateReceived', 'MerchantStateUpdated', 'GameEnd', 'GameEndRematchTextUpdated', 'GameEndShowMap', 'GameEndHideMap', 'ActivateRedDice', 'HoveredOverPlayerInformationArrow', 'PointerOutPlayerInformationView', 'RobberMoved', 'MerchantBankTradeRatioActive'].reduce((obj, e, idx) => ({ [e]: idx, ...obj }), {});\n n_ = ['ChatSubmit', 'UpdateNickName', 'ClickedLobbyGameListButton', 'RequestLobbyRoomList', 'ClickedStartTutorial', 'ClickedBotGame', 'ClickedCreateRoom', 'ClickedJoinRoom', 'AccessGameLink', 'ClickedSpectateGame', 'ClickedReconnectGame', 'ClickedChangeIcon', 'EnteredMatchmaking', 'ClickedDice', 'SelectedTile', 'SelectedTiles', 'SelectedPlayer', 'PassedTurn', 'SelectedCards', 'BuyDevelopmentCard', 'WantToBuildRoad', 'ConfirmBuildRoad', 'ConfirmRemoveRoad', 'WantToBuildSettlement', 'ConfirmBuildSettlement', 'WantToBuildCity', 'ConfirmBuildCity', 'WantToBuildShip', 'ConfirmBuildShip', 'WantToMoveShip', 'SelectedShipToMove', 'ConfirmMoveShip', 'WantToBuildCityWall', 'ConfirmBuildCityWall', 'WantToPlaceKnight', 'ConfirmPlaceKnight', 'WantToUpgradeKnight', 'ConfirmUpgradeKnight', 'WantToActivateKnight', 'ConfirmActivateKnight', 'WantToTakeKnightAction', 'SelectKnightToTakeAction', 'ConfirmMoveKnight', 'ConfirmMoveKnightOffTurn', 'ConfirmRemoveKnight', 'ConfirmCityUpgrade', 'ConfirmBuildMetropolis', 'ConfirmPillageCity', 'ConfirmDicePair', 'CancelAction', 'ClickedDevelpomentCard', 'CreatedPlayerOffer', 'AcceptedOffer', 'TakeAcceptedOffer', 'RejectedOffer', 'CreatedCounterOffer', 'ClickedEmbargo', 'RequestActionSwap', 'RequestSpecialBuildPhase', 'CancelSpecialBuildPhase', 'RoomReadyToStart', 'RoomSelectColor', 'RoomStartGame', 'RoomKickPlayer', 'RoomAddBot', 'RoomSettingChangePrivateGame', 'RoomSettingUpdateGameModeSetting', 'RoomSettingUpdateMapSetting', 'RoomSettingUpdateDiceSetting', 'RoomSettingChangeVictoryPointsToWin', 'RoomSettingChangeKarmaActive', 'RoomSettingChangeCardDiscardLimit', 'RoomSettingChangeFriendlyRobber', 'RoomSettingChangeMaxPlayers', 'RoomSettingChangeHideBankCards', 'RoomSettingChangeGameSpeed', 'RoomSettingChangeBotSpeed', 'ClickedRematch', 'Vote', 'ClickedFindGame', 'ClickedCancelFindGame', 'DisconnectedFromSocketServer', 'RequestToJoinMatchmakingMatch', 'ExitedMatchmaking'].reduce((obj, e, idx) => ({ [e]: idx, ...obj }), {});\n t_ = ['GameSetup', 'Dice', 'Turn', 'GameEnd', 'SpecialBuildPhase'].reduce((obj, e, idx) => ({ [e]: idx, ...obj }), {});\n p_ = ['None', 'Robber', 'Pirate'].reduce((obj, e, idx) => ({ [e]: idx, ...obj }), {});\n et_ = ['Empty', 'Road', 'Ship'].reduce((obj, e, idx) => ({ [e]: idx, ...obj }), {});\n\n cType = { North: 0, South: 1 };\n eType = { NorthWest: 0, West: 1, SouthWest: 2 };\n\n selectedHL = null;\n selectedDiceHL = null;\n selectedDiceView = null;\n selectedInventorTile = null;\n hoveredOverPlayerInformationArrow = false;\n lastPlayer = null;\n lastTurnState = null;\n lastActionState = null;\n lastEvent = null;\n passTurnTexture = null;\n\n const gameMode = gameState.gameSettings?.settingTexts()?.at(4)?.at(1);\n isSF = gameMode?.includes('Seafarers');\n isCK = gameMode?.includes('Cities & Knights');\n\n const moveInArray = (arr, fromIdx, toIdx) => {\n const elem = arr.at(fromIdx);\n arr.splice(fromIdx, 1);\n arr.splice(toIdx, 0, elem);\n };\n\n const highlightBg = (view, color) => {\n if (!view.hasHighlightedBg) {\n view.hasHighlightedBg = true;\n }\n else {\n view.children.splice(0, 1);\n }\n\n view.drawBg();\n moveInArray(view.children, -1, 0);\n\n view.bg.geometry.graphicsData.at(0).fillStyle.color = color || 0xffffff;\n view.bg.geometry.graphicsData.at(0).fillStyle.alpha = color ? 0.3 : 0;\n };\n\n const _activateEndTurn = turnButtonView.activateEndTurn.bind(turnButtonView);\n const _deactivateEndTurn = turnButtonView.deactivateEndTurn.bind(turnButtonView);\n const _sendEvent = eventController.sendEvent.bind(eventController);\n\n eventController.sendEvent = async (v, e) => {\n _sendEvent(v, e);\n \n await new Promise(r => setTimeout(r, 100));\n \n const takingTurn = gameState.currentTurnPlayerColor == myColor;\n const takingOffTurnAction = gameState.playersTakingOffTurnAction.includes(myColor);\n\n if (takingTurn && gameState.currentTurnState == t_.Dice && !getPopupView()) {\n const canUseAlchemist = getCardViews().flatMap(cv => cv.cardData.allowableTurnStates).includes(t_.Dice) && gameState.currentActionState == a_.None;\n \n if (canUseAlchemist) {\n selectNextCardAfterDelay(25);\n return; \n }\n }\n\n canvas.style.border = `2px solid ${takingTurn || takingOffTurnAction ? 'orange' : 'transparent'}`; \n };\n\n tradeController.rightExchangeController.updateBankRatios = () => {\n const that = tradeController.rightExchangeController;\n const e = gameState.myBankTradeRatios.getAllBankTradeRatios()\n , t = that.bankRatioContainer.width / e.length;\n e.sort((e,t)=>e.resource > t.resource ? 1 : -1);\n for (const [a,i] of e.entries()) {\n const e = new CardCountView(t * a,0,t,that.bankRatioContainer.height,that.bankRatioContainer,i.resource);\n e.updateText(i.tradeRatio + \":1\");\n e.view.setClickAction(() => that.exchangeView.cardContainer.addNewCardOfType(i.resource));\n that.cardViews.push(e);\n that.cardViewsWithBoldedText.includes(e.cardData.cardEnum) && e.boldText();\n if (i.tradeRatio < 4) {\n highlightBg(e, i.tradeRatio == 2 ? 0x00ff00 : 0xffff00);\n }\n }\n };\n\n const getEnhancedPopupInfoForDistribution = (e, forAqueduct = true) => {\n const t = e.selectCardFormat.amountOfCardsToSelect;\n const warnings = [];\n const reminders = [];\n\n for (let resource = c_.Lumber; resource <= c_.Ore; resource++) {\n let amt = getQuestionMarkAmountForCard(gameState.bank.totalResourceCardOfType(resource), hideBankCards);\n\n const myProduction = getNonGoldProductionForNumber(\n [myColor],\n gameState.lastDice1 + gameState.lastDice2,\n resource\n );\n\n const otherProduction = getNonGoldProductionForNumber(\n gameState.getOtherActivePlayerColors(),\n gameState.lastDice1 + gameState.lastDice2,\n resource\n );\n\n const totalProduction = t + otherProduction + (forAqueduct ? 0 : myProduction);\n\n if (amt == 0) {\n warnings.push(`⚠️ The bank has no ${c_[resource]} left!`);\n }\n else if (hideBankCards ? amt == '?' : amt <= 7) {\n if (totalProduction > 1 && totalProduction <= 7) {\n warnings.push(`⚠️ The bank is low on ${c_[resource]}.`);\n }\n else if (totalProduction > 8) {\n warnings.push(`⚠️ The bank will not have enough ${c_[resource]} for everyone!`);\n }\n }\n\n if (!forAqueduct && myProduction > 0 && amt != 0) {\n reminders.push(`βž• You will also produce ${myProduction} ${c_[resource]}.`);\n }\n }\n\n if (warnings.length) {\n warnings.unshift('\\n');\n }\n\n if (reminders.length) {\n reminders.unshift('\\n');\n }\n\n return {\n imageTextureName: forAqueduct ? \"icon_aqueduct\" : \"tile_gold\",\n title: `${warnings.length ? '⚠️ ' : ''}${forAqueduct ? \"Aqueduct\" : \"Gold Tile\"}`,\n body: \"Take \" + (1 == t ? t + \" resource\" : t + \" resources\") + \" from the bank\" + warnings.join('\\n') + reminders.join('\\n')\n }\n };\n\n if (isCK) {\n const _setNewView = popupController.setNewView.bind(popupController);\n\n popupController.setNewView = (e, t) => {\n if (e?.popupImageAndDescription?.constructor?.getPopupInformationForAqueductDistribution) {\n e.popupImageAndDescription.constructor.getPopupInformationForAqueductDistribution = e => getEnhancedPopupInfoForDistribution(e);\n e.popupImageAndDescription.constructor.getPopupInformationForGoldTileDistribution = e => getEnhancedPopupInfoForDistribution(e, false);\n }\n _setNewView(e, t);\n }\n }\n\n const _displayActionState = stateController.displayActionState.bind(stateController);\n\n stateController.displayActionState = e => {\n _displayActionState(e);\n\n const takingOffTurnAction = gameState.playersTakingOffTurnAction.includes(myColor);\n\n if (\n !takingOffTurnAction &&\n gameState.currentTurnPlayerColor == lastPlayer &&\n gameState.currentTurnState == lastTurnState &&\n gameState.currentActionState == lastActionState &&\n gameState.currentActionState != a_.SelectCityToPillage\n ) {\n return;\n }\n\n if ([\n a_.SelectCityToPillage,\n a_.Place1MoreRoadBuilding,\n a_.PlaceRobberOnly,\n a_.PlaceRobberOrPirate,\n a_.PlacePirateOnly,\n a_.MoveKnightOffTurn\n ].includes(gameState.currentActionState) && lastActionState) {\n selectNextAfterDelay();\n }\n\n if ([\n a_.SelectProgressCard,\n a_.SelectProgressCardsToDiscard,\n a_.SpySelectProgressCard\n ].includes(gameState.currentActionState) && lastActionState) {\n selectNextCardAfterDelay(25);\n }\n\n lastPlayer = gameState.currentTurnPlayerColor;\n lastTurnState = gameState.currentTurnState;\n lastActionState = gameState.currentActionState;\n };\n\n getQuestionMarkAmountForCard = (e, t) => t ? 0 == e ? \"0\" : e <= 7 ? \"?\" : e <= 13 ? \"??\" : \"???\" : String(e);\n\n bankController.update =_=> {\n const e = gameState.bank\n , t = gameState.gameSettings.hideBankCards\n , a = e.totalDevelopmentCards()\n , i = (0,\n getQuestionMarkAmountForCard)(a, t);\n bankController.developmentCardCountView.updateText(i);\n let shouldExpandBank = false;\n for (const a of bankController.resourceCardCountViews) {\n const i = e.totalResourceCardOfType(a.cardData.cardEnum);\n a.updateText((0,\n getQuestionMarkAmountForCard)(i, t))\n if (i <= 7) {\n highlightBg(a, i == 0 ? 1 : 0xff0000);\n if (i == 0 || a.cardData.cardEnum >= c_.Cloth) {\n shouldExpandBank = true;\n }\n }\n else {\n highlightBg(a);\n }\n }\n if (shouldExpandBank && !bankController.isBankInterfaceExpanded()) {\n bankController.expandBankInterface();\n }\n else {\n bankController.contractBankInterface();\n }\n };\n\n getMyCorners =_=> tileCorners.reduce((acc, tc, idx) => {\n if (tc.owner == myColor) {\n acc.push(idx);\n }\n return acc;\n }, []);\n\n getMyEdges =_=> tileEdges.reduce((acc, te, idx) => {\n if (te.owner == myColor) {\n acc.push(idx);\n }\n return acc;\n }, []);\n\n getNonGoldProductionForNumber = (players, n, resource) => {\n const myCorners = tileCorners.filter(tc => (!players || players.includes(tc.owner)) && tc.buildingType >= b_.Settlement && tc.buildingType <= b_.DestroyedCity);\n\n const commMap = { [c_.Wool]: c_.Cloth, [c_.Ore]: c_.Coin, [c_.Lumber]: c_.Paper };\n\n const production = tileFaces.reduce((cardEnums, t) => {\n if (t.diceNumber == n && t.tileType >= c_.Lumber && t.tileType <= c_.Ore && !robberController.lastRobberTile.sameTileHex(t)) {\n\n t.hexFace.corners().forEach(c => {\n const building = myCorners.find(({ hexCorner: hc }) => hc.sameCorner(c));\n\n if (!building) {\n return;\n }\n\n cardEnums.push(t.tileType);\n\n if (building.buildingType == b_.City) {\n cardEnums.push(isCK ? commMap[t.tileType] || t.tileType : t.tileType);\n }\n });\n }\n return cardEnums;\n }, []);\n\n return resource ? production.filter(res => res == resource).length : production;\n };\n\n openTrade = (withCommodities = false) => {\n const controller = mechanics.find(o => o.getTradeOffer);\n\n for (let c = c_.Lumber; c <= (withCommodities ? c_.Paper : c_.Ore); c++) {\n if (c == c_.Ore + 1) {\n c = c_.Cloth;\n }\n\n const offer = controller.getTradeOffer();\n const wanted = offer.wantedResources.cards;\n\n if (!wanted.includes(c) && tradeController.leftExchangeController.canAddResource(c)) {\n offer.offeredResources.addCards([c]);\n\n const offerToCounter = getLastCounterableOffer();\n\n if (offerToCounter) {\n socketGameSend.createdCounterOffer(offerToCounter.id, offer);\n }\n else {\n socketGameSend.createdPlayerOffer(offer);\n }\n }\n }\n };\n\n getLastCounterableOffer =_=> uiGameTradeInfoController.offers.find(({ offer, idx }) => (\n !offer.isCounterOffer &&\n offer.creator != myColor &&\n (!offerWasAcceptedByMe(offer) || remainingOffersAreUncounterable(idx))\n ))?.offer;\n\n counterOffer =_=> {\n const offer = getLastCounterableOffer();\n if (offer) {\n tradeController.editOffer(offer);\n }\n };\n\n clickCardInInventory = (card, cardViews) => {\n cardViews.some(cv => {\n if (cv.cardData.cardEnum == card) {\n return cv.view._events.click.fn() || true;\n }\n });\n };\n\n selectProgressCard = (reverse = false) => {\n const a = [...new Set((getPopupView()?.selectCardContainer?.cardsToSelectFrom || getPopupView().playerCardContainer).cardInventory.getAllCardEnums().filter(e => e > c_.Paper))];\n\n const b = [...a];\n b.unshift(b.pop());\n\n const nextCardMap = Object.assign(...b.map((k, i) => ({ [k]: a[i] })));\n const prevCardMap = Object.assign(...a.map((k, i) => ({ [k]: b[i] })));\n\n const selectFromInv = (getPopupView()?.selectCardContainer?.cardsToSelectFrom || getPopupView().playerCardContainer).cardInventory.cardViews.filter(({ cardData: c }) => c.cardEnum > c_.Paper);\n const selectedInv = (getPopupView()?.selectCardContainer?.cardsSelected || getPopupView().selectedCardContainer).cardInventory;\n\n let [selected] = selectedInv.getAllCardEnums();\n\n clickCardInInventory(selected ? (reverse ? prevCardMap[selected] : nextCardMap[selected]) : a.at(0 - reverse), selectFromInv);\n };\n\n getPopupView =_=> popupController?.currentView;\n\n getSelectedCard = getAlchemist => getCardViews().find(({ cardData: c }) =>\n c.cardEnum == (getAlchemist ? c_.ProgressCardScienceAlchemist : getPopupView()?.cardEnum));\n\n selectCardFromHand = resource => {\n try { tradeController.clickedTrade(); }\n catch (e) { console.error(e) }\n\n try { !tradeController.editingOffer && counterOffer(); }\n catch (e) { console.error(e) }\n\n try { getPopupView().playerCardContainer.cardClickAction(resource); }\n catch (e) { console.error(e) }\n\n try { getPopupView().selectCardView.clickedCardToSelectFrom(resource); }\n catch (e) { console.error(e) }\n\n tradeController.leftExchangeController.clickedResourceCard(resource);\n };\n\n selectCardsFromHand = (resource, max = false) => {\n try { tradeController.clickedTrade(); }\n catch (e) { console.error(e) }\n\n const numResources = tradeController.leftExchangeController.getAllActiveCards().filter(r => r == resource).length;\n const { tradeRatio } = gameState.myBankTradeRatios.bankTradeRatios.find(r => r.resource == resource);\n const numToAdd = Math.floor(numResources / tradeRatio) ** max * tradeRatio * (numResources >= tradeRatio);\n\n [...Array(numToAdd)].forEach(_ => {\n try { getPopupView().playerCardContainer.cardClickAction(resource); }\n catch (e) { console.error(e) }\n\n try { getPopupView().selectCardView.clickedCardToSelectFrom(resource); }\n catch (e) { console.error(e) }\n\n try { tradeController.leftExchangeController.clickedResourceCard(resource); }\n catch (e) { console.error(e) }\n });\n };\n\n selectCardFromElsewhere = resource => {\n try {\n if (getPopupView()?.clickedTopResource) {\n try { getPopupView()?.clickedTopResource(resource); }\n catch (e) { console.error(e) }\n }\n else {\n try { tradeController.clickedTrade(); }\n catch (e) { console.error(e) }\n\n try { if (!tradeController.editingOffer) { counterOffer(); } }\n catch (e) { console.error(e) }\n\n try { clickCardInInventory(resource, getPopupView().selectedCardContainer.cardInventory.cardViews); }\n catch (e) { console.error(e) }\n }\n }\n catch (e) { console.error(e) }\n\n tradeController.rightExchangeController.exchangeView.cardContainer.addNewCardOfType(resource);\n };\n\n offerWasAcceptedByMe = offer => {\n return uiGameTradeInfoController.tradeInfoContainer?.children?.some(c => {\n const playerIcon = c?.leftProposal?.children[2];\n const acceptedOfferFound = playerIcon?.children[1]?._texture?.textureCacheIds?.includes('icon_check');\n\n return acceptedOfferFound && offer.id == c?.offer?.id && playerIcon?.playerState?.color == myColor;\n });\n };\n\n remainingOffersAreUncounterable = idx => {\n const remainingOffers = uiGameTradeInfoController.offers.slice(idx + 1);\n return !remainingOffers.some(offer => !offer.isCounterOffer);\n };\n\n setSelectedHighlight = hl => selectedHL = hl || getHighlightViews().at(0);\n\n getSelectedHighlight =_=> {\n if (!getHighlightViews().includes(selectedHL)) {\n setSelectedHighlight();\n }\n\n return selectedHL;\n };\n\n getHighlightedPart =_=> {\n const cornersHighlighted = highlightController.corners.length;\n const edgesHighlighted = highlightController.roadEdges.length || highlightController.shipEdges.length;\n const tilesHighlighted = highlightController.tiles.length;\n\n const multiplePartTypesHighlighted = [ cornersHighlighted, edgesHighlighted, tilesHighlighted ].filter(Boolean).length > 1;\n\n if (multiplePartTypesHighlighted) {\n return 'Multiple';\n }\n else if (cornersHighlighted) {\n return 'Corner';\n }\n else if (edgesHighlighted) {\n return 'Edge';\n }\n else if (tilesHighlighted) {\n return 'Face';\n }\n };\n\n multiplePartTypesHighlighted =_=> {\n return getHighlightedPart() == 'Multiple';\n };\n\n xyzToHexPart = (x, y, z, part) => {\n return this[`tile${part}s`].find(({ [`hex${part}`]: p }) =>\n p.x == x && p.y == y && (part == 'Face' || p.z == z)\n )[`hex${part}`];\n };\n\n hexPartToPixels = ({ x, y, z }, p) => {\n try {\n const part = p || getHighlightedPart();\n const toPixel = part == 'Edge' ? 'centerPointToPixel' : 'toPixel';\n\n return xyzToHexPart(x, y, z, part)[toPixel](mapView.mapCenter, hexH / 2);\n }\n catch (e) { console.error(e) }\n };\n\n pixelsToHexPart = ({ x, y }, p) => {\n const part = p || getHighlightedPart();\n const toPixel = part == 'Edge' ? 'centerPointToPixel' : 'toPixel';\n const tolerance = part == 'Face' ? hexH / 3 : 10;\n\n return this[`tile${part}s`].find(({ [`hex${part}`]: hexPart }) => {\n const p = hexPart[toPixel](mapView.mapCenter, hexH / 2);\n return Math.abs(p.x - x) < tolerance && Math.abs(p.y - y) < tolerance;\n })[`hex${part}`];\n };\n\n getNextHighlightInArray = (direction = 'up') => {\n const hl = getSelectedHighlight();\n const reverse = ['down', 'left'].includes(direction);\n\n if (reverse) {\n return getHighlightViews().at(\n (getHighlightViews().indexOf(hl) + 1) % getHighlightViews().length\n );\n }\n else {\n const nextIdx = getHighlightViews().indexOf(hl) - 1;\n return getHighlightViews().at(nextIdx >= 0 ? nextIdx : getHighlightViews().length - 1);\n }\n };\n\n findHighlight = (coords, part) => {\n if (!coords) {\n return;\n }\n\n try {\n const { x, y } = coords;\n const tolerance = (part || getHighlightedPart()) == 'Face' ? hexH / 3 : 10;\n return getHighlightViews().find(({ center: c }) => Math.abs(c.x - x) < tolerance && Math.abs(c.y - y) < tolerance);\n }\n catch (e) { console.error(e) }\n };\n\n getHighlightInDirection = dir => {\n if (multiplePartTypesHighlighted()) {\n return getNextHighlightInArray(dir);\n }\n\n const hl = getSelectedHighlight();\n const hlPart = getHighlightedPart();\n const current = pixelsToHexPart(hl.center);\n\n const { x: currX, y: currY, z: currZ } = current;\n\n if (hlPart == 'Corner') {\n if (gameState.currentActionState == a_.PlaceKnight || getHighlightViews().length < tileCorners.filter(c => !c.restrictedStartingPlacement).length / 4) {\n return getNextHighlightInArray(dir);\n }\n\n this.upCorner = d => ({ x: currX + Math.floor((d + !currZ) / 2), y: currY - Math.floor((d + !currZ) / 2) * 2, z: (d + currZ) % 2 });\n this.downCorner = d => ({ x: currX - Math.floor((d + currZ) / 2), y: currY + Math.floor((d + currZ) / 2) * 2, z: (d + currZ) % 2 });\n this.rightCorner = d => ({ x: currX + Math.floor((d + !currZ) / 2), y: currY - (d % 2) * (1 - currZ * 2), z: (d + currZ) % 2 });\n this.leftCorner = d => ({ x: currX - Math.floor((d + currZ) / 2), y: currY - (d % 2) * (1 - currZ * 2), z: (d + currZ) % 2 });\n\n const maxDistance = Math.ceil(Math.sqrt(tileCorners.length) + 2);\n\n for (let distance = 1; distance <= maxDistance; distance++) {\n const nextHex = this[`${dir}Corner`](distance);\n\n const nextHL = findHighlight(hexPartToPixels(nextHex));\n if (nextHL) {\n return nextHL;\n }\n }\n\n return hl;\n }\n else if (hlPart == 'Edge') {\n return getNextHighlightInArray(dir);\n }\n else if (hlPart == 'Face') {\n if (getHighlightViews().length < tileFaces.length / 5) {\n return getNextHighlightInArray(dir);\n }\n\n this.upFace = d => ({ x: currX + d, y: currY - d });\n this.downFace = d => ({ x: currX - d, y: currY + d });\n this.rightFace = d => ({ x: currX + d, y: currY + 0 });\n this.leftFace = d => ({ x: currX - d, y: currY + 0 });\n\n const maxDistance = Math.ceil(Math.sqrt(tileFaces.length) + 2);\n\n for (let distance = 1; distance <= maxDistance; distance++) {\n const nextHex = this[`${dir}Face`](distance);\n\n const nextHL = findHighlight(hexPartToPixels(nextHex));\n if (nextHL) {\n return nextHL;\n }\n }\n\n const someDirectionWorks = [upFace, downFace, rightFace, leftFace].filter(f => f != this[`${dir}Face`]).some(face => {\n return Array.from(Array(maxDistance).keys()).some(distance => {\n return findHighlight(hexPartToPixels(face(distance + 1)));\n });\n });\n\n return someDirectionWorks ? hl : getNextHighlightInArray(dir);\n }\n };\n\n getHighlightViews =_=> highlightController.highlightViews;\n\n selectHighlight = hl => {\n if (!highlightController.highlightViews.length) {\n return;\n }\n\n const\n roadAndShipEdges = highlightController.shipEdges.filter(e => highlightController.roadEdges.includes(e)),\n allEdges = [...new Set([...highlightController.roadEdges, ...highlightController.shipEdges])],\n idx = getHighlightViews().indexOf(hl);\n\n let tileCornerWillBeHighlighted = false;\n let tileFaceWillBeHighlighted = false;\n\n try { tileCornerWillBeHighlighted = findHighlight(hexPartToPixels(pixelsToHexPart(hl.center, 'Corner'), 'Corner'), 'Corner') } catch (e) { console.error(e) }\n try { tileFaceWillBeHighlighted = findHighlight(hexPartToPixels(pixelsToHexPart(hl.center, 'Face'), 'Face'), 'Face') } catch (e) { console.error(e) }\n\n if (gameState.currentTurnState == t_.GameSetup || roadAndShipEdges.includes(allEdges[idx])) {\n hl._events.click.fn();\n }\n else if (multiplePartTypesHighlighted() ? tileFaceWillBeHighlighted : highlightController.tiles.length) {\n const\n face = pixelsToHexPart(hl.center, 'Face'),\n a = mapController.mapView.getTileLeftCenterCircle(face),\n i = 2.5 * a.radius,\n e = .7 * i * highlightController.buttonScaleForMobile,\n o = a.x - e / 2,\n n = a.y + i / 2;\n\n gameState.currentActionState == a_.SelectKnightAction\n ? highlightController.confirmActionController.showConfirmation(a.x - i / 2, a.y - i / 2, i, o, n, e, _ => hl._events.click.fn())\n : hl._events.click.fn();\n }\n else if (multiplePartTypesHighlighted() ? false : allEdges.length) {\n const\n edge = tileEdges.at(allEdges[idx]).hexEdge,\n a = edge.endPoints()[0].toPixel(mapView.mapCenter, hexH / 2),\n i = edge.endPoints()[1].toPixel(mapView.mapCenter, hexH / 2),\n n = Math.sqrt((a.x - i.x) ** 2 + (a.y - i.y) ** 2) / 2,\n o = (a.x + i.x) / 2 - n / 2,\n s = (a.y + i.y) / 2 - n / 2,\n e = 1.1 * n,\n r = (a.x + i.x) / 2 - e / 2,\n l = (a.y + i.y) / 2 + n / 2;\n\n highlightController.confirmActionController.showConfirmation(o, s, n, r, l, e, _ => {\n highlightController.confirmedEdgeSelection(allEdges[idx]);\n });\n\n const edgeIdx = tileEdges.findIndex(({ hexEdge }) => hexEdge == edge);\n const { roadEdges, shipEdges } = highlightController;\n const roadOnlyEdges = roadEdges.filter(e => !shipEdges.includes(e));\n const shipOnlyEdges = shipEdges.filter(e => !roadEdges.includes(e));\n\n if (roadOnlyEdges.includes(edgeIdx) && isSF) {\n highlightController.confirmActionController.whiteHighlightView._tintRGB += 5e2;\n }\n else if (shipOnlyEdges.includes(edgeIdx)) {\n highlightController.confirmActionController.whiteHighlightView._tintRGB -= 2e3;\n }\n }\n else if (multiplePartTypesHighlighted() ? tileCornerWillBeHighlighted : highlightController.corners.length) {\n const\n corner = tileCorners.at(highlightController.corners[idx]).hexCorner,\n a = corner.toPixel(mapView.mapCenter, hexH / 2),\n i = 1.2 * mapView.cornerCircleR,\n e = 1.1 * i * highlightController.buttonScaleForMobile,\n n = a.x - e / 2,\n o = a.y + i / 2;\n\n highlightController.confirmActionController.showConfirmation(a.x - i / 2, a.y - i / 2, i, n, o, e, ()=>{\n highlightController.confirmedCornerSelection(highlightController.corners[idx])\n });\n }\n\n setSelectedHighlight(hl);\n highlightController.highlightViews.pop();\n };\n\n deselectHighlight =_=> selectedHL = null;\n\n selectNextPlayer = (reverse = false) => {\n try {\n let playerAvatars, selectPlayer, firstPlayer, selectedPlayerIdx = 0 - reverse;\n\n const pv = getPopupView() || selectPlayerToStealController;\n\n if (selectPlayerToStealController?.isWrongState() == false) {\n selectPlayer = player => pv.selectPlayerAction(player);\n playerAvatars = pv.ui.playerAvatarContainer.playerAvatars;\n }\n else if (pv.selectPlayerAction) {\n selectPlayer = player => pv.selectPlayerAction(player);\n playerAvatars = (pv.selectPlayerView || pv).playerSelectorContainer.playerAvatars;\n }\n else {\n selectPlayer = player => pv.playerClickPlayerAvatar(player);\n playerAvatars = (pv.selectPlayerView || pv).playerSelectorContainer.playerAvatars;\n }\n\n selectedPlayer = playerAvatars.find((avatar, idx) => {\n if (idx == 0) {\n firstPlayer = avatar.playerState.color;\n }\n if (avatar.alpha == 1) {\n selectedPlayerIdx = idx;\n return true;\n }\n })?.playerState?.color;\n\n selectPlayer(\n playerAvatars.at((selectedPlayerIdx + 1 * (selectedPlayer && (reverse ? -1 : 1))) % playerAvatars.length).playerState.color\n );\n }\n catch (e) { console.error(e) }\n };\n\n selectNext = (direction = 'up') => {\n try {\n selectNextPlayer(['down', 'left'].includes(direction));\n }\n catch (e) { console.error(e) }\n\n try {\n if (gameState.currentActionState == a_.SelectTileProductionNumbersToSwap) {\n selectNextInventorTile(direction);\n return;\n }\n }\n catch (e) { console.error(e) }\n\n try {\n let currHL = getSelectedHighlight();\n let nextHL;\n\n if (currHL && !getHighlightViews().length) {\n return;\n }\n\n if (currHL) {\n nextHL = getHighlightInDirection(direction);\n }\n\n selectHighlight(nextHL || currHL || getHighlightViews()[0]);\n }\n catch (e) { console.error(e) }\n };\n\n confirmSelection =_=> {\n if (!selectPlayerToStealController.isWrongState()) {\n selectPlayerToStealController.checkAction();\n return;\n }\n\n const hl = getSelectedHighlight();\n\n if (hl) {\n try { \n highlightController.confirmActionController.confirmButton._events.click.fn();\n }\n catch (e) { console.error(e) }\n }\n };\n\n selectNextAfterDelay = (ms = 200) => setTimeout(_ => selectNext(), ms);\n\n selectNextPlayerAfterDelay = (ms = 150) => setTimeout(_ => selectNextPlayer(), ms);\n\n selectNextCardAfterDelay = (ms = 150) => setTimeout(_ => selectNextCard(), ms);\n\n selectNextDiceViewAfterDelay = (ms = 150) => setTimeout(_ => {\n if (getPopupView()?.bottomDiceContainer && !getPopupView().bottomDiceContainer.isDiceSelected()) {\n selectNextDiceView();\n }\n }, ms);\n\n closePopUps =_=> document.querySelector('.popup-notification .btn_general_check')?.click();\n\n getCardContainerView =_=> cardController.cardContainerView;\n\n getCardViews =_=> getCardContainerView().cardInventory.cardViews.slice(getCardContainerView().getPartitionCardIndex());\n\n canSelectCardNextAgain = currentCard => {\n const { cardEnum } = currentCard.cardData;\n const devCardVP = gameState.getPlayerWithColor(myColor).victoryPointState.totalVictoryPointsOfType([2]);\n const numCards = getCardViews().length;\n\n return (\n numCards > 1 &&\n numCards > devCardVP &&\n [...new Set(getCardContainerView().cardInventory.cardViews.reduce((acc, { cardData: c }) => { if (c.cardTypeEnum > 1 && ![c_.VictoryPoint, cardEnum].includes(c.cardEnum)) { acc.push(c.cardEnum) }; return acc; }, []))].length\n );\n };\n\n hasDevelopmentOrProgressCards =_=> getCardViews().find(({ cardData: c }) => c.cardTypeEnum > 1);\n\n selectNextInventorTile = dir => {\n let inventorTiles = highlightDiceController.diceProbabilityViewsBeingHighlighted;\n\n if (!selectedInventorTile) {\n selectedInventorTile = inventorTiles.at(0);\n }\n else {\n const { x: currX, y: currY } = selectedInventorTile.hexFace;\n\n inventorTiles = inventorTiles.filter(({ hexFace: f }) => !(f.x == currX && f.y == currY));\n\n this.upFace = d => ({ x: currX + d, y: currY - d });\n this.downFace = d => ({ x: currX - d, y: currY + d });\n this.rightFace = d => ({ x: currX + d, y: currY + 0 });\n this.leftFace = d => ({ x: currX - d, y: currY + 0 });\n\n const maxDistance = Math.ceil(Math.sqrt(tileFaces.length) + 2);\n\n for (let distance = 1; distance <= maxDistance; distance++) {\n const n = this[`${dir}Face`](distance);\n const nextInventorTile = inventorTiles.find(({ hexFace: f }) => f.x == n.x && f.y == n.y);\n if (nextInventorTile) {\n selectedInventorTile = nextInventorTile;\n break;\n }\n }\n }\n\n const\n face = selectedInventorTile.hexFace,\n a = mapController.mapView.getTileLeftCenterCircle(face),\n i = 2.5 * a.radius,\n e = .7 * i * highlightController.buttonScaleForMobile,\n o = a.x - e / 2,\n n = a.y + i / 2;\n\n highlightController.confirmActionController.showConfirmation(a.x - i, a.y - i / 3, i * 2, o, n - i, e, _ => selectedInventorTile.diceProbabilityView._events.click.fn());\n highlightController.confirmActionController.whiteHighlightView._alpha = 0.75;\n };\n\n selectNextDiceView = (reverse = false) => {\n try {\n if (!getPopupView()?.topDiceContainer || getPopupView()?.areBothDiceSelected()) {\n return;\n }\n\n let diceViews;\n let currentDiceView;\n\n if (!getPopupView().topDiceContainer.isDiceSelected()) {\n diceViews = getPopupView().topDiceContainer.diceViews;\n }\n else {\n diceViews = getPopupView().bottomDiceContainer.diceViews;\n }\n\n const currentDV = diceViews.find(v => v._alpha == 1);\n const selectedNum = currentDV?.diceNumber;\n\n const nextDV = diceViews.at(selectedNum ? (selectedNum - reverse * 2) % 6 : 0 - reverse);\n\n selectedDiceView?.inactiveOpacity();\n selectedDiceView = nextDV;\n selectedDiceView.activeOpacity();\n }\n catch (e) { console.error(e) }\n };\n\n selectNextCard = (reverse = false, multiple = 1) => {\n try {\n if (gameState.currentActionState == a_.SelectDiceForAlchemist) {\n selectNextDiceView(reverse);\n return;\n }\n }\n catch (e) { console.error(e) }\n\n try {\n selectProgressCard(reverse);\n return;\n }\n catch (e) { console.error(e) }\n\n try {\n if (!hasDevelopmentOrProgressCards()) {\n return;\n }\n\n const canUseAlchemist = gameState.currentTurnState == t_.Dice && getCardViews().flatMap(cv => cv.cardData.allowableTurnStates).includes(t_.Dice) && gameState.currentActionState == a_.None;\n\n let c = getSelectedCard(canUseAlchemist);\n let shouldSelectNext, nextCardEnum;\n\n if (!c) {\n c = getCardViews().at(0 - reverse);\n shouldSelectNext = c.cardData.cardEnum == c_.VictoryPoint;\n }\n else if (!canUseAlchemist) {\n const oldEnum = c.cardData.cardEnum;\n const idx = getCardViews().indexOf(c);\n c = getCardViews().at((idx + multiple * (1 - reverse * 2)) % getCardViews().length);\n shouldSelectNext = [oldEnum, c_.VictoryPoint, c_.ProgressCardScienceAlchemist].includes(c.cardData.cardEnum);\n }\n\n if (shouldSelectNext && canSelectCardNextAgain(c)) {\n selectNextCard(reverse, multiple + 1);\n return;\n }\n\n if (gameState.currentActionState == a_.SelectProgressCardsToDiscard) {\n getPopupView().playerCardContainer.cardInventory.cardViews.find(d => d.cardData.cardEnum == c.cardData.cardEnum).view._events.click.fn();\n }\n else if (c.isValidTurnState() && c.canClickCard()) {\n const { imageFileName: imageTextureName, tipTitle: title, popupBody: body, cardEnum } = c.cardData;\n const cardEvent = { cardEnum, popupInformation: { imageTextureName, title, body } };\n\n if ([c_.ProgressCardTradeMerchant, c_.ProgressCardTradeMerchantFleet].includes(cardEnum)) {\n const hasTwoForOnePorts = tileCorners.filter(tc => tc.owner == myColor && tc.portType > 1 && tc.buildingType >= b_.Settlement && tc.buildingType <= b_.DestroyedCity).length;\n\n if (hasTwoForOnePorts) {\n cardEvent.popupInformation.title = `⚠️ ${cardEvent.popupInformation.title}`;\n cardEvent.popupInformation.body += '\\n\\n⚠️ You own at least one 2:1 port.';\n }\n }\n else if ([c_.ProgressCardScienceIrrigation, c_.ProgressCardScienceMining].includes(cardEnum)) {\n const warnings = [];\n const resource = cardEnum == c_.ProgressCardScienceIrrigation ? c_.Grain : c_.Ore;\n const amt = getQuestionMarkAmountForCard(gameState.bank.totalResourceCardOfType(resource), hideBankCards);\n\n if (amt == 0) {\n warnings.push(`⚠️ The bank has no ${c_[resource]} left!`);\n }\n else if (hideBankCards ? amt == '?' : amt <= 7) {\n warnings.push(`⚠️ The bank is low on ${c_[resource]}.`);\n }\n\n if (warnings.length) {\n warnings.unshift('\\n');\n }\n\n cardEvent.popupInformation.title = `${warnings.length ? '⚠️ ': ''}${cardEvent.popupInformation.title}`;\n cardEvent.popupInformation.body += warnings.join('\\n');\n }\n else if (cardEnum == c_.ProgressCardScienceRoadBuilding && isSF) {\n const pirateAffectedEdges = tileFaces.find(t => t.tilePieceTypes == p_.Pirate).hexFace.corners().reduce((adjEdges, c) => {\n const edges = c.touchingEdges().filter(edge => !adjEdges.some(e => e.sameEdge(edge)));\n return [...edges, ...adjEdges];\n }, []);\n\n const myPirateAffectedEdges = tileEdges.filter(tc => tc.owner == myColor && tc.type == et_.Ship && pirateAffectedEdges.some(pc => tc.hexEdge.sameEdge(pc)));\n\n const pirateAffectedCorners = tileFaces.find(t => t.tilePieceTypes == p_.Pirate).hexFace.corners();\n\n const myPirateAffectedCorners = tileCorners.filter(tc => tc.owner == myColor && tc.buildingType >= 1 && tc.buildingType <= 3 && pirateAffectedCorners.some(pc => tc.hexCorner.sameCorner(pc)));\n\n if ([...myPirateAffectedEdges, ...myPirateAffectedCorners].length) {\n cardEvent.popupInformation.title = `⚠️ ${cardEvent.popupInformation.title}`;\n cardEvent.popupInformation.body += '\\n\\n⚠️ Nearby Pirate Ship may restrict ship placements.';\n }\n }\n\n socketGameSend.requestActionSwap(n_.ClickedDevelpomentCard);\n eventController.sendEvent(cardEvent, e_.ConfirmUseDevelopmentCard);\n }\n }\n catch (e) { console.error(e) }\n };\n\n accioEnabled = true;\n console.log('πŸ§™πŸ‘ ACCio enabled!');\n }, false, 1000));"}}],["3",{"name":"cityWallRandom.js","value":{"mdTime":1638883706807,"srcCode":"await ACCio(_ => getMyCorners().forEach(i => socketGameSend.confirmBuildCityWall(i)));"}}],["4",{"name":"city.js","value":{"mdTime":1641400221535,"srcCode":"await ACCio(_ => {\n socketGameSend.buildCity();\n selectNextAfterDelay();\n});"}}],["5",{"name":"ship.js","value":{"mdTime":1641431002339,"srcCode":"await ACCio(_ => {\n try {\n highlightController.confirmActionController.shipButton.action();\n return;\n }\n catch {}\n\n socketGameSend.buildShip();\n selectNextAfterDelay();\n});"}}],["6",{"name":"road.js","value":{"mdTime":1641430970391,"srcCode":"await ACCio(_ => {\n try {\n highlightController.confirmActionController.roadButton.action();\n return;\n }\n catch {}\n\n socketGameSend.buildRoad();\n selectNextAfterDelay();\n});"}}],["7",{"name":"settlement.js","value":{"mdTime":1641400194348,"srcCode":"await ACCio(_ => {\n socketGameSend.buildSettlement();\n selectNextAfterDelay();\n});"}}],["8",{"name":"cityRandom.js","value":{"mdTime":1638883422454,"srcCode":"await ACCio(_ => getMyCorners().forEach(i => socketGameSend.confirmBuildCity(i)));"}}],["9",{"name":"dev_ci.js","value":{"mdTime":1643079245372,"srcCode":"await ACCio(_ => {\n try { socketGameSend.buyDevCard(); }\n catch {}\n\n [0, 1, 2].forEach(i => socketGameSend.confirmCityUpgrade(i));\n\n selectNextAfterDelay(350);\n\n try { expandableButtons.forEach(btn => btn.hideButtons()); }\n catch {}\n});"}}],["10",{"name":"moveShip.js","value":{"mdTime":1641400250902,"srcCode":"await ACCio(_ => {\n socketGameSend.moveShip();\n selectNextAfterDelay();\n});"}}],["11",{"name":"moveShipRandom.js","value":{"mdTime":1638885054603,"srcCode":"await ACCio(_ => getMyEdges().forEach(i => socketGameSend.selectedShipToMove(i)));"}}],["12",{"name":"knight.js","value":{"mdTime":1641400258286,"srcCode":"await ACCio(_ => {\n socketGameSend.placeKnight();\n selectNextAfterDelay();\n});"}}],["13",{"name":"knightActivate.js","value":{"mdTime":1641400262568,"srcCode":"await ACCio(_ => {\n socketGameSend.activateKnight();\n selectNextAfterDelay();\n});"}}],["14",{"name":"knightActivateRandom.js","value":{"mdTime":1638885401691,"srcCode":"await ACCio(_ => getMyCorners().forEach(i => socketGameSend.confirmActivateKnight(i)));"}}],["15",{"name":"knightUpgrade.js","value":{"mdTime":1641400267074,"srcCode":"await ACCio(_ => {\n socketGameSend.upgradeKnight();\n selectNextAfterDelay();\n});"}}],["16",{"name":"knightUpgradeRandom.js","value":{"mdTime":1638885668955,"srcCode":"await ACCio(_ => getMyCorners().forEach(i => socketGameSend.confirmUpgradeKnight(i)));"}}],["17",{"name":"knightAction.js","value":{"mdTime":1641400277160,"srcCode":"await ACCio(_ => {\n socketGameSend.takeKnightAction();\n selectNextAfterDelay();\n});"}}],["18",{"name":"knightActionRandom.js","value":{"mdTime":1638885831922,"srcCode":"await ACCio(_ => getMyCorners().forEach(i => socketGameSend.confirmSelectKnightToTakeAction(i)));"}}],["19",{"name":"lumber.js","value":{"mdTime":1638886315826,"srcCode":"await ACCio(_ => selectCardFromHand(c_.Lumber));"}}],["20",{"name":"brick.js","value":{"mdTime":1638886360847,"srcCode":"await ACCio(_ => selectCardFromHand(c_.Brick));"}}],["21",{"name":"wool.js","value":{"mdTime":1638886395821,"srcCode":"await ACCio(_ => selectCardFromHand(c_.Wool));"}}],["22",{"name":"grain.js","value":{"mdTime":1638886412570,"srcCode":"await ACCio(_ => selectCardFromHand(c_.Grain));"}}],["23",{"name":"ore.js","value":{"mdTime":1638886425248,"srcCode":"await ACCio(_ => selectCardFromHand(c_.Ore));"}}],["24",{"name":"cloth.js","value":{"mdTime":1638886434463,"srcCode":"await ACCio(_ => selectCardFromHand(c_.Cloth));"}}],["25",{"name":"paper.js","value":{"mdTime":1638886445634,"srcCode":"await ACCio(_ => selectCardFromHand(c_.Paper));"}}],["26",{"name":"coin.js","value":{"mdTime":1638886478080,"srcCode":"await ACCio(_ => selectCardFromHand(c_.Coin));"}}],["27",{"name":"lumberOther.js","value":{"mdTime":1638886838021,"srcCode":"await ACCio(_ => selectCardFromElsewhere(c_.Lumber));"}}],["28",{"name":"brickOther.js","value":{"mdTime":1638886940054,"srcCode":"await ACCio(_ => selectCardFromElsewhere(c_.Brick));"}}],["29",{"name":"woolOther.js","value":{"mdTime":1638889800513,"srcCode":"await ACCio(_ => selectCardFromElsewhere(c_.Wool));"}}],["30",{"name":"grainOther.js","value":{"mdTime":1638889810527,"srcCode":"await ACCio(_ => selectCardFromElsewhere(c_.Grain));"}}],["31",{"name":"oreOther.js","value":{"mdTime":1638889842864,"srcCode":"await ACCio(_ => selectCardFromElsewhere(c_.Ore));"}}],["32",{"name":"clothOther.js","value":{"mdTime":1638889862038,"srcCode":"await ACCio(_ => selectCardFromElsewhere(c_.Cloth));"}}],["33",{"name":"coinOther.js","value":{"mdTime":1638889877528,"srcCode":"await ACCio(_ => selectCardFromElsewhere(c_.Coin));"}}],["34",{"name":"paperOther.js","value":{"mdTime":1638889889359,"srcCode":"await ACCio(_ => selectCardFromElsewhere(c_.Paper));"}}],["35",{"name":"tradeSubmit.js","value":{"mdTime":1638891729426,"srcCode":"await ACCio(_ => tradeController.clickedActionButton());"}}],["36",{"name":"tradeComplete.js","value":{"mdTime":1641750242798,"srcCode":"await ACCio(_ => { \n uiGameTradeInfoController.offers.some(o => {\n return o.view?.creatorProposal?.playerAvatars?.some?.(p => { \n const acceptedOfferFound = p?.children[1]?._texture?.textureCacheIds?.includes('icon_check');\n\n if (acceptedOfferFound) {\n socketGameSend.takeAcceptedOffer(o.offer.id, p.playerState.color);\n }\n \n return acceptedOfferFound;\n });\n });\n});"}}],["37",{"name":"tradeAgree.js","value":{"mdTime":1638891844419,"srcCode":"await ACCio(_ => {\n uiGameTradeInfoController.offers.some(({ offer }) => {\n if (!offer.isCounterOffer && !offerWasAcceptedByMe(offer)) {\n socketGameSend.acceptedOffer(offer.id);\n offer.updateResponse(myColor, 1);\n return true;\n }\n });\n});\n"}}],["38",{"name":"tradeReject.js","value":{"mdTime":1640833006776,"srcCode":"await ACCio(_ => {\n uiGameTradeInfoController.offers.some(({ offer }) => {\n if (!offer.isCounterOffer && !offerWasAcceptedByMe(offer)) {\n socketGameSend.rejectedOffer(offer.id);\n return true;\n }\n });\n});\n"}}],["39",{"name":"tradeCounterOffer.js","value":{"mdTime":1639109694127,"srcCode":"await ACCio(_ => {\n uiGameTradeInfoController.offers.some(({ offer, idx }) => {\n if (\n !offer.isCounterOffer\n && offer.creator != myColor\n && (!offerWasAcceptedByMe(offer) || remainingOffersAreUncounterable(idx))\n ) {\n tradeController.editOffer(offer);\n return true;\n }\n });\n});\n"}}],["40",{"name":"tradeClearAll.js","value":{"mdTime":1639177751199,"srcCode":"await ACCio(_ => {\n try { if (!tradeController.editingOffer) { counterOffer(); } }\n catch {}\n\n tradeController.resetTradeWindow();\n});"}}],["41",{"name":"tradeClearOffered.js","value":{"mdTime":1639177759580,"srcCode":"await ACCio(_ => {\n try { if (!tradeController.editingOffer) { counterOffer(); } }\n catch {}\n\n tradeController.leftExchangeController.updatePlayerCards();\n});"}}],["42",{"name":"tradeClearWanted.js","value":{"mdTime":1639177765751,"srcCode":"await ACCio(_ => {\n try { if (!tradeController.editingOffer) { counterOffer(); } }\n catch {}\n\n tradeController.rightExchangeController.updateAndShowUI();\n});"}}],["43",{"name":"cancel.js","value":{"mdTime":1641751089872,"srcCode":"await ACCio(_ => {\n try { socketGameSend.cancelAction(); }\n catch {}\n\n try { getPopupView().clickedCancelAction(); }\n catch {}\n\n try { tradeController.closeTradeUI(); }\n catch {}\n\n try { expandableButtons.forEach(btn => btn.hideButtons()); }\n catch {}\n\n try { closePopUps(); }\n catch {}\n});"}}],["44",{"name":"roll.js","value":{"mdTime":1638891360485,"srcCode":"await ACCio(_ => socketGameSend.clickedDice());"}}],["45",{"name":"endTurn.js","value":{"mdTime":1641435789407,"srcCode":"await ACCio(_ => {\n socketGameSend.clickedPassTurn();\n});\n"}}],["46",{"name":"surprise.js","value":{"mdTime":1639842899027,"srcCode":"await ACCio(_ => {\n const getWordiestMethodName = obj => {\n return Object.getOwnPropertyNames(Object.getPrototypeOf(obj)).sort((a, b) => b.length - a.length)[0];\n };\n\n const getPropHash = obj => {\n return hash(Object.getOwnPropertyNames(Object.getPrototypeOf(obj)).join(''));\n };\n\n const hash = str => {\n let hash = 0, i, chr;\n if (str.length === 0) {\n return hash;\n }\n for (i = 0; i < str.length; i++) {\n chr = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + chr;\n hash |= 0;\n }\n return hash;\n };\n\n const decrypt = (key, data) => {\n return Array.from(data, (c, i) => String.fromCharCode(c.charCodeAt() ^ key.charCodeAt(i % key.length))).join('').split(',');\n };\n\n const propHash = 689972192;\n const ciphertext = '1\\x07\\x1D\\x11\\x16*\\x12\\x16U|\\x05\\x02\\x16\\v-0\\n\\x17I=\\x1E\\x04\\n*C\\x11\\x06\\x10V\\x03\\x02\\x17N\\x01\\x11\\x1B\\x01\\x06D\\x02\"0\\x1D?M';\n\n const obj = mechanics.find(o => getPropHash(o) === propHash);\n\n if (!obj) {\n console.error('ACCio says: the surprise requires the Cities & Knights expansion!');\n return;\n }\n\n const key = getWordiestMethodName(obj);\n obj[key](...decrypt(key, ciphertext));\n});"}}],["47",{"name":"setupCheckWindow.js","value":{"mdTime":1638983152658,"srcCode":""}}],["48",{"name":"specialBuild.js","value":{"mdTime":1641108352273,"srcCode":"await ACCio(_ => {\n mechanics.find(o => o.toggleSpecialBuildPhase).clickedSpecialBuildPhaseButton();\n});"}}],["49",{"name":"initialize.js","value":{"mdTime":1639073885133,"srcCode":"ACCio = async _ => {\n await ACtl.runInPageCtx(_ => {\n console.error('ACCio called');\n });\n}"}}],["50",{"name":"selectRight.js","value":{"mdTime":1639612904254,"srcCode":"await ACCio(_ => selectNext('right'));"}}],["51",{"name":"selectLeft.js","value":{"mdTime":1639613001043,"srcCode":"await ACCio(_ => selectNext('left'));"}}],["52",{"name":"selectConfirm.js","value":{"mdTime":1643346254777,"srcCode":"await ACCio(_ => {\n const shouldSelectNext = getPopupView();\n\n try { getPopupView().clickedCheckAction(); }\n catch {}\n\n try { getPopupView().checkAction(); }\n catch {}\n\n try {\n getPopupView().selectCardView.confirmationButtons.checkButton.action();\n }\n catch {}\n \n confirmSelection();\n\n if (shouldSelectNext) {\n try {\n selectedDiceView?._events?.click?.fn();\n selectNextDiceViewAfterDelay();\n }\n catch {}\n\n selectNextAfterDelay();\n }\n\n try {\n highlightDiceController.confirmationPopup.confirmationButtons.checkButton.action();\n }\n catch {}\n\n try {\n if (!shouldSelectNext) {\n selectNextPlayerAfterDelay();\n }\n }\n catch {}\n\n closePopUps();\n});"}}],["53",{"name":"selectNextCard.js","value":{"mdTime":1639276833094,"srcCode":"await ACCio(_ => selectNextCard());"}}],["54",{"name":"selectPrevCard.js","value":{"mdTime":1639276857770,"srcCode":"await ACCio(_ => selectNextCard(true));"}}],["55",{"name":"selectUp.js","value":{"mdTime":1639613039482,"srcCode":"await ACCio(_ => selectNext('up'));"}}],["56",{"name":"selectDown.js","value":{"mdTime":1639613091176,"srcCode":"await ACCio(_ => selectNext('down'));"}}],["57",{"name":"tradeOpen.js","value":{"mdTime":1640827121476,"srcCode":"await ACCio(_ => openTrade());\n"}}],["58",{"name":"tradeOpenComms.js","value":{"mdTime":1640827352788,"srcCode":"await ACCio(_ => openTrade(true));\n"}}],["59",{"name":"tradeRejectAll.js","value":{"mdTime":1641435796202,"srcCode":"await ACCio(_ => {\n try {\n uiGameTradeInfoController.offers.forEach(({ offer }) => {\n socketGameSend.rejectedOffer(offer.id);\n });\n } catch {}\n});\n"}}],["60",{"name":"clothRatio.js","value":{"mdTime":1643048255027,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Cloth));"}}],["61",{"name":"togglePlayerInfo.js","value":{"mdTime":1642973242899,"srcCode":"ACCio(_ => {\n if (!isCK) {\n return;\n }\n\n if (!hoveredOverPlayerInformationArrow) {\n eventController.sendEvent(null, e_.HoveredOverPlayerInformationArrow);\n }\n else {\n eventController.sendEvent(null, e_.PointerOutPlayerInformationView);\n }\n\n hoveredOverPlayerInformationArrow ^= true;\n});"}}],["62",{"name":"lumberRatio.js","value":{"mdTime":1643047995499,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Lumber));"}}],["63",{"name":"brickRatio.js","value":{"mdTime":1643048010513,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Brick));"}}],["64",{"name":"woolRatio.js","value":{"mdTime":1643048073354,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Wool));"}}],["65",{"name":"grainRatio.js","value":{"mdTime":1643048134255,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Grain));"}}],["66",{"name":"oreRatio.js","value":{"mdTime":1643048168205,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Ore));"}}],["67",{"name":"coinRatio.js","value":{"mdTime":1643048304676,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Coin));"}}],["68",{"name":"paperRatio.js","value":{"mdTime":1643048416328,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Paper));"}}],["69",{"name":"lumberRatioMax.js","value":{"mdTime":1643074072330,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Lumber, true));"}}],["70",{"name":"brickRatioMax.js","value":{"mdTime":1643074372836,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Brick, true));"}}],["71",{"name":"woolRatioMax.js","value":{"mdTime":1643074405810,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Wool, true));"}}],["72",{"name":"grainRatioMax.js","value":{"mdTime":1643074436960,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Grain, true));"}}],["73",{"name":"oreRatioMax.js","value":{"mdTime":1643074466680,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Ore, true));"}}],["74",{"name":"clothRatioMax.js","value":{"mdTime":1643074493191,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Cloth, true));"}}],["75",{"name":"coinRatioMax.js","value":{"mdTime":1643074524005,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Coin, true));"}}],["76",{"name":"paperRatioMax.js","value":{"mdTime":1643074550805,"srcCode":"await ACCio(_ => selectCardsFromHand(c_.Paper, true));"}}],["77",{"name":"focusChat.js","value":{"mdTime":1643345509179,"srcCode":"ACCio(_ => document.querySelector('#game-chat-input').focus());"}}],["78",{"name":"focusGame.js","value":{"mdTime":1643345754188,"srcCode":"ACtl.runInPageCtx(_ => document.activeElement.blur());"}}]],"tse":[]},"mouseGest":{},"scrtEdtr":{"theme":"default ACtrl-dark"},"sections":[{"id":"2","name":"ACCio – Setup πŸ§™"},{"id":"1","name":"ACCio – BasicsΒ β€†πŸŽ²"},{"id":"3","name":"ACCio – Cards β€†πŸ‘"},{"id":"4","name":"ACCio – Trades πŸ’±"},{"id":"5","name":"ACCio – Selectβ€†β€†πŸ§©"}],"trigActList":[["64",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:19"}}],"targets":"currentTab"}],"sctnId":"3","title":"LUMBER: select a Lumber card from your hand.","triggers":[{"combins":[{"block":0,"eventId":529,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["56",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:27"}}],"targets":"currentTab"}],"sctnId":"3","title":"LUMBER (other): select a Lumber card from elsewhere (e.g. wanted cards, cards-to-discard, Aqueduct...)","triggers":[{"combins":[{"block":0,"eventId":529,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["41",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:62"}}],"targets":"currentTab"}],"sctnId":"3","title":"LUMBER (ratio): select a number of Lumber cards from your hand equal to your trade ratio (4, 3 or 2).","triggers":[{"combins":[{"block":0,"eventId":529,"preconds":[{"keyEvt":17},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["70",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:69"}}],"targets":"currentTab"}],"sctnId":"3","title":"LUMBER (max. ratio): select a number of Lumber cards equal to the highest multiple of your trade ratio.","triggers":[{"combins":[{"block":1,"eventId":529,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["63",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:20"}}],"targets":"currentTab"}],"sctnId":"3","title":"BRICK: select a Brick card from your hand.","triggers":[{"combins":[{"block":0,"eventId":530,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["55",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:28"}}],"targets":"currentTab"}],"sctnId":"3","title":"BRICK (other): select a Brick card from elsewhere.","triggers":[{"combins":[{"block":0,"eventId":530,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["42",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:63"}}],"targets":"currentTab"}],"sctnId":"3","title":"BRICK (ratio): select a number of Brick cards from your hand equal to your trade ratio (4, 3 or 2).","triggers":[{"combins":[{"block":0,"eventId":530,"preconds":[{"keyEvt":17},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["72",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:70"}}],"targets":"currentTab"}],"sctnId":"3","title":"BRICK (max. ratio): select a number of Brick cards equal to the highest multiple of your trade ratio.","triggers":[{"combins":[{"block":0,"eventId":530,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["62",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:21"}}],"targets":"currentTab"}],"sctnId":"3","title":"WOOL: select a Wool card from your hand. πŸ‘","triggers":[{"combins":[{"block":0,"eventId":531,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["54",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:29"}}],"targets":"currentTab"}],"sctnId":"3","title":"WOOL (other): select a Wool card from elsewhere. πŸ‘","triggers":[{"combins":[{"block":0,"eventId":531,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["43",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:64"}}],"targets":"currentTab"}],"sctnId":"3","title":"WOOL (ratio): select a number of Wool cards from your hand equal to your trade ratio (4, 3 or 2). πŸ‘","triggers":[{"combins":[{"block":0,"eventId":531,"preconds":[{"keyEvt":17},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["74",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:71"}}],"targets":"currentTab"}],"sctnId":"3","title":"WOOL (max. ratio): select a number of Wool cards equal to the highest multiple of your trade ratio.","triggers":[{"combins":[{"block":0,"eventId":531,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["61",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:22"}}],"targets":"currentTab"}],"sctnId":"3","title":"GRAIN: select a Grain card from your hand.","triggers":[{"combins":[{"block":0,"eventId":532,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["53",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:30"}}],"targets":"currentTab"}],"sctnId":"3","title":"GRAIN (other): select a Grain card from elsewhere.","triggers":[{"combins":[{"block":0,"eventId":532,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["65",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:65"}}],"targets":"currentTab"}],"sctnId":"3","title":"GRAIN (ratio): select a number of Grain cards from your hand equal to your trade ratio (4, 3 or 2).","triggers":[{"combins":[{"block":0,"eventId":532,"preconds":[{"keyEvt":17},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["75",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:72"}}],"targets":"currentTab"}],"sctnId":"3","title":"GRAIN (max. ratio): select a number of Grain cards equal to the highest multiple of your trade ratio.","triggers":[{"combins":[{"block":0,"eventId":532,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["60",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:23"}}],"targets":"currentTab"}],"sctnId":"3","title":"ORE: select an Ore card from your hand.","triggers":[{"combins":[{"block":0,"eventId":533,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["52",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:31"}}],"targets":"currentTab"}],"sctnId":"3","title":"ORE (other): select an Ore card from elsewhere.","triggers":[{"combins":[{"block":0,"eventId":533,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["66",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:66"}}],"targets":"currentTab"}],"sctnId":"3","title":"ORE (ratio): select a number of Ore cards from your hand equal to your trade ratio (4, 3 or 2).","triggers":[{"combins":[{"block":0,"eventId":533,"preconds":[{"keyEvt":17},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["76",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:73"}}],"targets":"currentTab"}],"sctnId":"3","title":"ORE (max. ratio): select a number of Ore cards equal to the highest multiple of your trade ratio.","triggers":[{"combins":[{"block":0,"eventId":533,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["59",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:24"}}],"targets":"currentTab"}],"sctnId":"3","title":"CLOTH: select a Cloth card from your hand.","triggers":[{"combins":[{"block":0,"eventId":534,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["51",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:32"}}],"targets":"currentTab"}],"sctnId":"3","title":"CLOTH (other): select a Cloth card from elsewhere.","triggers":[{"combins":[{"block":0,"eventId":534,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["67",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:60"}}],"targets":"currentTab"}],"sctnId":"3","title":"CLOTH (ratio): select a number of Cloth cards from your hand equal to your trade ratio (4, 3 or 2).","triggers":[{"combins":[{"block":0,"eventId":534,"preconds":[{"keyEvt":17},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["77",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:74"}}],"targets":"currentTab"}],"sctnId":"3","title":"CLOTH (max. ratio): select a number of Cloth cards equal to the highest multiple of your trade ratio.","triggers":[{"combins":[{"block":0,"eventId":534,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["58",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:26"}}],"targets":"currentTab"}],"sctnId":"3","title":"COIN: select a Coin card from your hand.","triggers":[{"combins":[{"block":0,"eventId":535,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["50",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:33"}}],"targets":"currentTab"}],"sctnId":"3","title":"COIN (other): select a Coin card from elsewhere.","triggers":[{"combins":[{"block":0,"eventId":535,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["68",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:67"}}],"targets":"currentTab"}],"sctnId":"3","title":"COIN (ratio): select a number of Coin cards from your hand equal to your trade ratio (4, 3 or 2).","triggers":[{"combins":[{"block":0,"eventId":535,"preconds":[{"keyEvt":17},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["78",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:75"}}],"targets":"currentTab"}],"sctnId":"3","title":"COIN (max. ratio): select a number of Coin cards equal to the highest multiple of your trade ratio.","triggers":[{"combins":[{"block":0,"eventId":535,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["57",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:25"}}],"targets":"currentTab"}],"sctnId":"3","title":"PAPER: select a Paper card from your hand.","triggers":[{"combins":[{"block":0,"eventId":536,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["49",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:34"}}],"targets":"currentTab"}],"sctnId":"3","title":"PAPER (other): select a Paper card from elsewhere.","triggers":[{"combins":[{"block":0,"eventId":536,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["69",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:68"}}],"targets":"currentTab"}],"sctnId":"3","title":"PAPER (ratio): select a number of Paper cards from your hand equal to your trade ratio (4, 3 or 2).","triggers":[{"combins":[{"block":0,"eventId":536,"preconds":[{"keyEvt":17},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["79",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:76"}}],"targets":"currentTab"}],"sctnId":"3","title":"PAPER (max. ratio): select a number of Paper cards equal to the highest multiple of your trade ratio.","triggers":[{"combins":[{"block":0,"eventId":536,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["71",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:77"}}],"targets":"currentTab"}],"sctnId":"1","title":"FOCUS CHAT: shifts focus from the game canvas to the text chat.","triggers":[{"combins":[{"block":1,"eventId":9,"preconds":[],"repCount":2,"wildcard":2}],"preconds":{"caretState":{"off":true},"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["73",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:78"}}],"targets":"currentTab"}],"sctnId":"1","title":"FOCUS GAME: shifts focus from text chat to the game canvas.","triggers":[{"combins":[{"block":1,"eventId":9,"preconds":[],"repCount":2,"wildcard":2}],"preconds":{"caretState":{"on":true},"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["45",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:44"}}],"targets":"currentTab"}],"sctnId":"1","title":"DICE ROLL: rolls the dice.","triggers":[{"combins":[{"block":0,"eventId":68,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["44",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:43"}}],"targets":"currentTab"}],"sctnId":"1","title":"CANCEL: cancels current action, closes your trade window and dismisses pop-ups.","triggers":[{"combins":[{"block":0,"eventId":27,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["46",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:43"}}],"targets":"currentTab"},{"sequence":[{"action":"runScript","params":{"scriptId":"script:59"}}],"targets":"currentTab"},{"sequence":[{"action":"runScript","params":{"scriptId":"script:45"}}],"targets":"currentTab"}],"sctnId":"1","title":"END TURN / REJECT OFFERS: ends your turn and/or rejects/cancels all trade offers.","triggers":[{"combins":[{"block":0,"eventId":190,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["2",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:6"}}],"targets":"currentTab"}],"sctnId":"1","title":"ROAD: build a Road at spot of your choice.","triggers":[{"combins":[{"block":0,"eventId":82,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["1",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:7"}}],"targets":"currentTab"}],"sctnId":"1","title":"SETTLEMENT: build a Settlement at a spot of your choice.","triggers":[{"combins":[{"block":0,"eventId":83,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["4",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:4"}}],"targets":"currentTab"}],"sctnId":"1","title":"CITY (choice): build a City at a spot of your choice.","triggers":[{"combins":[{"block":0,"eventId":67,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["5",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:4"}}],"targets":"currentTab"},{"sequence":[{"action":"runScript","params":{"scriptId":"script:8"}}],"targets":"currentTab"}],"sctnId":"1","title":"CITY (random): build and place a City at a randomly-determined spot.","triggers":[{"combins":[{"block":0,"eventId":67,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["6",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:9"}}],"targets":"currentTab"}],"sctnId":"1","title":"DEV CARD / CITY UPGRADE: buy a Development Card or all available City Upgrades.","triggers":[{"combins":[{"block":0,"eventId":86,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["14",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:48"}}],"targets":"currentTab"}],"sctnId":"1","title":"SPECIAL BUILD PHASE: request a Special Build Phase.","triggers":[{"combins":[{"block":0,"eventId":32,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["7",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:1"}}],"targets":"currentTab"}],"sctnId":"1","title":"CITY WALL (choice): build a City Wall upon a City of your choice.","triggers":[{"combins":[{"block":0,"eventId":87,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["8",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:1"}}],"targets":"currentTab"},{"sequence":[{"action":"runScript","params":{"scriptId":"script:3"}}],"targets":"currentTab"}],"sctnId":"1","title":"CITY WALL (random): build and place a City Wall upon a randomly-chosen City.","triggers":[{"combins":[{"block":0,"eventId":87,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["9",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:5"}}],"targets":"currentTab"}],"sctnId":"1","title":"SHIP: build a Ship at a spot of your choice.","triggers":[{"combins":[{"block":0,"eventId":69,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["10",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:10"}}],"targets":"currentTab"}],"sctnId":"1","title":"MOVE SHIP (choice): move an available Ship of your choice to a spot of your choice.","triggers":[{"combins":[{"block":0,"eventId":81,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["21",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:10"}}],"targets":"currentTab"},{"sequence":[{"action":"runScript","params":{"scriptId":"script:11"}}],"targets":"currentTab"}],"sctnId":"1","title":"MOVE SHIP (random): move a randomly-chosen available Ship to a spot of your choice.","triggers":[{"combins":[{"block":0,"eventId":81,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["11",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:12"}}],"targets":"currentTab"}],"sctnId":"1","title":"KNIGHT: build a Knight at a spot of your choice.","triggers":[{"combins":[{"block":0,"eventId":75,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["22",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:13"}}],"targets":"currentTab"}],"sctnId":"1","title":"ACTIVATE KNIGHT (choice): 'feed' a Knight of your choice.","triggers":[{"combins":[{"block":0,"eventId":70,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["23",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:13"}}],"targets":"currentTab"},{"sequence":[{"action":"runScript","params":{"scriptId":"script:14"}}],"targets":"currentTab"}],"sctnId":"1","title":"ACTIVATE KNIGHT (random): 'feed' a randomly-chosen Knight.","triggers":[{"combins":[{"block":0,"eventId":70,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["12",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:15"}}],"targets":"currentTab"}],"sctnId":"1","title":"UPGRADE KNIGHT (choice): upgrade a Knight of your choice.","triggers":[{"combins":[{"block":0,"eventId":85,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["24",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:15"}}],"targets":"currentTab"},{"sequence":[{"action":"runScript","params":{"scriptId":"script:16"}}],"targets":"currentTab"}],"sctnId":"1","title":"UPGRADE KNIGHT (random): upgrade a randomly-chosen Knight.","triggers":[{"combins":[{"block":0,"eventId":85,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["13",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:17"}}],"targets":"currentTab"}],"sctnId":"1","title":"KNIGHT ACTION (choice): take a Knight Action of your choice using a Knight of your choice.","triggers":[{"combins":[{"block":0,"eventId":65,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["25",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:17"}}],"targets":"currentTab"},{"sequence":[{"action":"runScript","params":{"scriptId":"script:18"}}],"targets":"currentTab"}],"sctnId":"1","title":"KNIGHT ACTION (random): take a Knight Action of your choice using a randomly-chosen Knight.","triggers":[{"combins":[{"block":0,"eventId":65,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["40",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:61"}}],"targets":"currentTab"}],"sctnId":"1","title":"C&K INFO TOGGLE: toggle player information view (e.g. to see progress card VP, defender VP)","triggers":[{"combins":[{"block":0,"eventId":73,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["47",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:46"}}],"targets":"currentTab"}],"sctnId":"1","title":"Surprise! ✨ (requires Cities & Knights)","triggers":[{"combins":[{"block":0,"eventId":65,"preconds":[],"wildcard":2},{"block":0,"eventId":67,"preconds":[],"wildcard":2},{"block":0,"eventId":67,"preconds":[],"wildcard":2},{"block":0,"eventId":73,"preconds":[],"wildcard":2},{"block":0,"eventId":79,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["48",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:2"}}],"targets":"eventTabs"}],"sctnId":"2","title":"Enables ACCio automatically. (If this doesn't work, try using the manual command below.)","triggers":[{"combins":[{"block":1,"eventId":2054,"preconds":[],"wildcard":1}],"preconds":{"evtUrl":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["31",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:2"}}],"targets":"currentTab"}],"sctnId":"2","title":"Enables ACCio manually. (If this doesn't work automatically, try refreshing your browser window.)","triggers":[{"combins":[{"block":0,"eventId":65,"preconds":[{"keyEvt":17},{"keyEvt":18},{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["28",{"title":"Welcome to ACCio! Check out the 'Basics' section to start!","triggers":[{"combins":[]}]}],["39",{"title":"Revision #110 – https://gist.github.com/Silvyre/7e73756f108dc987a0d12d609e615371","triggers":[{"combins":[],"preconds":{}}]}],["3",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:50"}}],"targets":"currentTab"}],"sctnId":"5","title":"SELECT RIGHT: select an item (tile/corner/edge/avatar) to the right of the currently-selected one.","triggers":[{"combins":[{"block":0,"eventId":524,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["29",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:51"}}],"targets":"currentTab"}],"sctnId":"5","title":"SELECT LEFT: select an item to the left of the currently-selected one.","triggers":[{"combins":[{"block":0,"eventId":522,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["34",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:55"}}],"targets":"currentTab"}],"sctnId":"5","title":"SELECT UP: select an item above the currently-selected one.","triggers":[{"combins":[{"block":0,"eventId":523,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["35",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:56"}}],"targets":"currentTab"}],"sctnId":"5","title":"SELECT DOWN: select an item below the currently-selected one.","triggers":[{"combins":[{"block":0,"eventId":525,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["32",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:53"}}],"targets":"currentTab"}],"sctnId":"5","title":"SELECT NEXT CARD: select the next Development/Progress Card (e.g. in your hand or a pop-up)","triggers":[{"combins":[{"block":0,"eventId":524,"preconds":[{"keyEvt":17}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["33",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:54"}}],"targets":"currentTab"}],"sctnId":"5","title":"SELECT PREVIOUS CARD: select the previous Development/Progress Card.","triggers":[{"combins":[{"block":0,"eventId":522,"preconds":[{"keyEvt":17}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["30",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:52"}}],"targets":"currentTab"}],"sctnId":"5","title":"CONFIRM SELECTION: confirm your selection (of any of the above, cards to discard, etc.)","triggers":[{"combins":[{"block":0,"eventId":516,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["27",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:35"}}],"targets":"currentTab"}],"sctnId":"4","title":"SUBMIT OFFER: submit your current trade offer.","triggers":[{"combins":[{"block":0,"eventId":516,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["36",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:57"}}],"targets":"currentTab"}],"sctnId":"4","title":"\"OPEN\" RESOURCE TRADE: submits your offer multiple times, each time adding a different Resource.","triggers":[{"combins":[{"block":0,"eventId":79,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["37",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:58"}}],"targets":"currentTab"}],"sctnId":"4","title":"\"OPEN\" COMMODITY TRADE: as above, but also uses your Commodities to create offers.","triggers":[{"combins":[{"block":0,"eventId":79,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["26",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:37"}}],"targets":"currentTab"}],"sctnId":"4","title":"AGREE TO OFFER: agree to the topmost unaccepted trade being offered to you.","triggers":[{"combins":[{"block":0,"eventId":516,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["20",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:39"}}],"targets":"currentTab"}],"sctnId":"4","title":"COUNTER-OFFER: start a counter-offer on the bottom-most unaccepted trade being offered to you.","triggers":[{"combins":[{"block":0,"eventId":191,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["19",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:38"}}],"targets":"currentTab"}],"sctnId":"4","title":"REJECT FIRST OFFER: rejects/rescinds the topmost (oldest) unaccepted trade offer.","triggers":[{"combins":[{"block":0,"eventId":220,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["38",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:59"}}],"targets":"currentTab"}],"sctnId":"4","title":"CLOSE ALL OFFERS: reject/rescind all trade offers.","triggers":[{"combins":[{"block":0,"eventId":220,"preconds":[{"keyEvt":16}],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["18",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:36"}}],"targets":"currentTab"}],"sctnId":"4","title":"COMPLETE TRADE: complete the top-leftmost agreed-upon trade offer.","triggers":[{"combins":[{"block":0,"eventId":187,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["17",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:40"}}],"targets":"currentTab"}],"sctnId":"4","title":"RESET TRADE WINDOW: clear all cards from both sides of your trade window.","triggers":[{"combins":[{"block":0,"eventId":8,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["16",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:41"}}],"targets":"currentTab"}],"sctnId":"4","title":"CLEAR OFFERED: clear all cards from the left side of your trade window.","triggers":[{"combins":[{"block":0,"eventId":219,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}],["15",{"actions":[{"sequence":[{"action":"runScript","params":{"scriptId":"script:42"}}],"targets":"currentTab"}],"sctnId":"4","title":"CLEAR WANTED: clear all cards from the right side of your trade window.","triggers":[{"combins":[{"block":0,"eventId":221,"preconds":[],"wildcard":2}],"preconds":{"urlTests":[{"part":1,"type":"equals","value":"colonist.io"}]}}]}]],"userVars":{}}
@Silvyre
Copy link
Author

Silvyre commented Jan 23, 2022

Thanks for the tips, @AutoControl-app! ❀️

@CrookedJ
Copy link

This is awesome, I love it a ton.

One weird thing I've noticed is the selecting, e.g. when building a road. The direction you press doesn't correspond with what you see, it's following a different path. Haven't looked at it myself, but possibly something they did changing the layout/code since it was written?

@Silvyre
Copy link
Author

Silvyre commented May 24, 2022

Hey @CrookedJ, glad to hear you're enjoying ACCio!

The hex edge selection logic I implemented isn't very smart: it just cycles through the (unordered) list of highlighted edges without first attempting to find the edge that best corresponds to the arrow key pressed:

getHighlightInDirection = dir => {
  if (multiplePartTypesHighlighted()) {
    return getNextHighlightInArray(dir);
  }

  const hlPart = getHighlightedPart();

  if (hlPart == 'Corner') {
    ... // sometimes smart, sometimes not smart
  }
  else if (hlPart == 'Edge') {
    return getNextHighlightInArray(dir); // not smart!
  }
  ... 
}

A better edge selection algorithm would search through the list of highlighted edges and find the closest edge in the direction pressed.

@CrookedJ
Copy link

CrookedJ commented Jun 29, 2022

After this week's update, using the . hotkey to end turn also prompts for a username change.
image

EDIT:
So I looked some more and did some testing. End turn actually does 3 things,

  1. (script43 - cancel.js) cancel actions/close trade ui/close popups
  2. (script59 - tradeRejectAll.js) reject trade offers
  3. (script45 - endTurn.js) end turn

cancel.js is the issue (same one that runs when hitting ESC) - pressing ESC also pops the username change popup

Hope that helps, thanks

EDIT 2:
Shift+Enter also makes it popup

but it doesn't ALWAYS popup. πŸ€·β€β™‚οΈ

@Silvyre
Copy link
Author

Silvyre commented Jul 3, 2022

@CrookedJ I made a change to fix this in revision #111. If you find any pop-ups that you are no longer able to close using ACCio as a result of this change, please let me know! Thank you!

@CrookedJ
Copy link

CrookedJ commented Jul 3, 2022

Will do, cheers mate!

@CrookedJ
Copy link

CrookedJ commented Jul 3, 2022

Found a bug - End of game scoreboard doesn't show up

EDIT: Well it did on another game so not sure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment