⛓️ 블록체인/P2E-Gala

타운스타 자동을 팔기 - 오토셀 (auto-sell) 스크립트

백뚜 2022. 1. 4. 10:32
반응형

타운스타를 플레이하면서 물건이 10개씩 쌓일 때마다 팔 수 있습니다. 그렇게 돈을 벌 수 있죠.

근데 어느 정도 타운이 만들어진 후에는 이걸 계속 단순히 반복적으로 팔아줘야하죠. 그리고 기다려야하고요.

그래서 이걸 자동을 팔아주는 코드를 누가 만들었네요. 이걸 오토셀(auto-sell)이라고 부릅니다.

시작하기전 주의사항
- 오토셀 스크립트는 갈라사에서 추천하고 있는 것이 아닙니다. 저 또한 그렇고요. 몇번 쓰다가 지금은 갈라사에서 허용하지 않을까봐 사용하지 않는 중입니다.
- 오토셀 스크립트 사용시에 발생할 수 있는 문제는 본인이 책임지셔야한다는 점을 명심하시고 사용해주십시오.

 

<오토셀 다운로드 페이지 (안 들어가셔도 됩니다)>

모든 스크립트는 아래 사이트에서 제작된 것입니다.

https://gala-analytics.herokuapp.com/townstar

 

Gala Analytics

 

gala-analytics.herokuapp.com

 

아래의 스크립트는 크롬을 기준으로 설명드립니다. 

 

1. 크롬 확장프로그램: Tampermonkey 설치 (스크립트 실행을 위한 것)

https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo

 

2. 아이콘 보이도록 고정

3. 스크립트들 추가하기 

스크립트는 지금 글 맨 밑에 가시면 있습니다. 또는 위 링크에서 받으시면 됩니다.

 

4. 자신이 팔 물건과 관찰할 물건 추가하기

 

다시 한번 말씀드리지만, 이 스크립트를 써서 문제가 발생할 때, 아무도 책임을 안져주기 때문에, 사용하는 것을 추천드리지 않습니다. 항상 또 항상 조심합시다~

 

<오토셀v2 스크립트>

// ==UserScript==
// @name         Town Star Auto-Sell
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  Automatically sell crafted items.
// @author       Groove
// @match        https://townstar.sandbox-games.com/launch/
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
	// keepAmt is the amount that you do not want to sell
	// sellMin is the minimum amount needed before attempting to sell
	//    setting a sellMin of 100 will ensure that the item is only sold in batches of 100 (e.g. via Freight Ship)
    const craftedItems = [
        {item: 'Silica', keepAmt: 0, sellMin: 100},
        {item: 'Pinot_Noir_Grapes', keepAmt: 0, sellMin: 0},
        {item: 'Feed', keepAmt: 0, sellMin: 0},
        {item: 'Wheat', keepAmt: 0, sellMin: 0},
        {item: 'Flour', keepAmt: 0, sellMin: 0},
        {item: 'Salt', keepAmt: 0, sellMin: 0},
    ]

    new MutationObserver(function(mutations) {
        let airdropcollected = 0;
        if(document.getElementsByClassName('hud-jimmy-button')[0] && document.getElementsByClassName('hud-jimmy-button')[0].style.display != 'none'){
            document.getElementsByClassName('hud-jimmy-button')[0].click();
            document.getElementById('Deliver-Request').getElementsByClassName('yes')[0].click();
            document.getElementById('Deliver-Request').getElementsByClassName('close-button')[0].click();
        }
        if(document.getElementsByClassName('hud-airdrop-button')[0] && document.getElementsByClassName('hud-airdrop-button')[0].style.display != 'none'){
            if(airdropcollected == 0){
                airdropcollected = 1;
                document.getElementsByClassName('hud-airdrop-button')[0].click();
                document.getElementsByClassName('air-drop')[0].getElementsByClassName('yes')[0].click();
            }
        }
        if (document.getElementById("playnow-container") && document.getElementById("playnow-container").style.visibility !== "hidden") {
            if(typeof Game == 'undefined' || (Game && Game.gameData == null)) {
                window.location.reload();
            } else {
                document.getElementById("playButton").click();
                console.log(Date.now() + ' ---===ACTIVATING AUTO SELL===---');
                ActivateAutoSell();
            }
        }
    }).observe(document, {childList: true, subtree: true});

    function GetAvailableTradeObject(capacity) {
        return Object.values(Game.town.objectDict).filter(tradeObj => tradeObj.logicType === 'Trade')
            .find(tradeObj =>
                  Game.unitsData[tradeObj.objData.UnitType].Capacity == capacity
                  && !Game.town.tradesList.find(activeTrade => activeTrade.source.x == tradeObj.townX && activeTrade.source.z == tradeObj.townZ)
                 )
    }

    function CloseWindows(elements, checkParent) {
        for (let i=0, n=elements.length; i < n; i++) {
            let el = checkParent ? elements[i].closest('.container') : elements[i];
            let elVis = el.currentStyle ? el.currentStyle.visibility : getComputedStyle(el, null).visibility;
            let elDis = el.currentStyle ? el.currentStyle.display : getComputedStyle(el, null).display;
            if (!(elVis === 'hidden' || elDis === 'none')) {
                el.querySelector('.close-button') && el.querySelector('.close-button').click();
            }
        }
    }

    async function WaitForCompletion(selector) {
        while (document.querySelector(selector) !== null) {
            await new Promise( resolve => requestAnimationFrame(resolve) )
        }
        return document.querySelector(selector);
    }

    async function WaitForTradeLoad(targetTradeObj) {
        return await new Promise(resolve => {
            const waitForUpdate = setInterval(() => {
                let tradeUiObj = Game.app.root.findByName('TradeUi').script.trade.townObject;
                if (tradeUiObj && tradeUiObj.townX == targetTradeObj.townX && tradeUiObj.townZ == targetTradeObj.townZ && Game.app.root.findByName('TradeUi').script.trade.cityPaths[0].gasCost) {
                    resolve('Loaded');
                    clearInterval(waitForUpdate);
                };
            }, 500);
        });
    }

    async function WaitForElement(selector) {
        while (document.querySelector(selector) === null) {
            await new Promise( resolve => requestAnimationFrame(resolve) )
        }
        await new Promise(resolve => setTimeout(resolve, 1000));
        return document.querySelector(selector);
    }

    async function CheckCrafts() {
        let allTradeObjects = Object.values(Game.town.objectDict).filter(tradeObj => tradeObj.logicType === 'Trade');
        for (let i=0, n=allTradeObjects.length; i < n; i++) {
            if (allTradeObjects[i].logicObject.tapToCollectEntity.enabled) {
                allTradeObjects[i].logicObject.OnTapped();
            }
        }
        if (Game.town.GetStoredCrafts()['Gasoline'] >= 1) {
            for (let i=0, n=craftedItems.length; i < n; i++) {
                if (Game.town.GetStoredCrafts()[craftedItems[i].item] >= craftedItems[i].keepAmt + 10) {
                    let targetTradeObj;
                    if (Game.town.GetStoredCrafts()[craftedItems[i].item] >= 100 + craftedItems[i].keepAmt) {
                        targetTradeObj = GetAvailableTradeObject(100);
                    }
                    if (!targetTradeObj && Game.town.GetStoredCrafts()[craftedItems[i].item] >= 50 + craftedItems[i].keepAmt && craftedItems[i].sellMin <= 50){
                        targetTradeObj = GetAvailableTradeObject(50);
                    }
                    if (!targetTradeObj && Game.town.GetStoredCrafts()[craftedItems[i].item] >= 10 + craftedItems[i].keepAmt && craftedItems[i].sellMin <= 10){
                        targetTradeObj = GetAvailableTradeObject(10);
                    }
                    if (targetTradeObj){
                        CloseWindows(document.querySelectorAll('body > .container > .player-confirm .dialog-cell'), false);
                        CloseWindows(document.querySelectorAll('.container > div:not(.hud):not(.player-confirm)'), true);
                        Game.town.selectObject(targetTradeObj);
                        Game.app.fire('SellClicked', {x: targetTradeObj.townX, z: targetTradeObj.townZ});
                        await WaitForCompletion('.LoadingOrders');
                        document.querySelector('#trade-craft-target [data-name="' + craftedItems[i].item + '"]').click();
                        await WaitForTradeLoad(targetTradeObj);
                        if (Game.town.GetStoredCrafts()['Gasoline'] >= Game.app.root.findByName('TradeUi').script.trade.cityPaths[0].gasCost) {
                            document.querySelector('#destination-target .destination .sell-button').click();
                            let tradeTimeout = setTimeout(function(){
								document.querySelector('.trade-connection .no').click();
							},10000);
                            await WaitForCompletion('.trade-connection .compass');
							clearTimeout(tradeTimeout);
                        } else {
                            console.log('Whoops! You have run out of gas.');
                            document.querySelector('#autosell-status .bank').textContent = 'ALERT: Out of gas!'
                            document.querySelector('.container > .trade .close-button').click();
                        }
                    }
                }
            }
        } else {
            console.log('Whoops! You have run out of gas.');
            document.querySelector('#autosell-status .bank').textContent = 'ALERT: Out of gas!'
        }
        setTimeout(CheckCrafts, 5000);
    }

    async function ActivateAutoSell() {
        let autoSellStatus = document.createElement('div');
        autoSellStatus.id = 'autosell-status';
        autoSellStatus.style.cssText = 'pointer-events: all; position: absolute; left: 50%; transform: translate(-50%, 0);';
        autoSellStatus.addEventListener( 'click', function(){this.children[0].textContent = 'Auto-Sell Active';})
        let autoSellContent = document.createElement('div');
        autoSellContent.classList.add('bank');
        autoSellContent.style.cssText = 'background-color: #fde7e3; padding-left: 10px; padding-right: 10px';
        autoSellContent.textContent = 'Auto-Sell Active';
        autoSellStatus.appendChild(autoSellContent);
        await WaitForElement('.hud');
        document.querySelector('.hud').prepend(autoSellStatus);
        CheckCrafts();
    }

})();

 

<리더보드v2 스크립트>

// ==UserScript==
// @name         Enhanced Leaderboard
// @namespace    http://tampermonkey.net/
// @version      2
// @description  Click a row on the Leaderboard to jump directly to that town on the map.
// @author       Groove
// @match        https://townstar.sandbox-games.com/launch/
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    let loaded = 0;
    let leaderTracker = [];
    new MutationObserver(function(mutations) {
        if (document.querySelector('.leaderboard') && loaded == 0) {
            loaded = 1;
            LoadEnhancedLeaderboard();
            ActivateLeaderTracker();
        }
    }).observe(document, {childList: true, subtree: true});

    function LoadEnhancedLeaderboard() {
        document.querySelector('.leaderboard').addEventListener('click', e => {
            if (e.target.closest('.player')) {
                let targetTownName = e.target.closest('.player').querySelector('.name').innerHTML;
                let targetTown = Object.values(Game.world.towns).filter(function(el){return el.name == targetTownName})[0];
                let worldPos = Game.world.GetWorldPositionFromMapIndex(targetTown.x, targetTown.y);
                Game.app.root.findByName('CameraWorld').script.cameraController.SetPosition(worldPos.x, worldPos.z);
                document.querySelector('.leaderboard .close-button').click();
                if (HUD.instance && HUD.instance.activeView == 'Town') {Game.app.fire('SetWorldView')};
                Game.app.root.findByName('CameraWorld').script.cameraController.Tap({x: (window.innerWidth/2), y: (window.innerHeight/2)});
            }
        });
    }

    async function CheckLeaderboard() {
        API.scoreLeaderboard(0, 19).then(leaders=>{
            for (let i=0, n=leaders.length; i < n; i++) {
                let tracker = leaderTracker.find(leader => leader.userId == leaders[i].userId)
                if (tracker) {
                    let timeDiff = Date.now() - tracker.startTime;
                    tracker.pph = (leaders[i].score - tracker.startScore) / (timeDiff / 3600000);
                    tracker.rank = leaders[i].rank;
                    let lastHrDiff = Date.now() - tracker.lastHrTime;
                    if (lastHrDiff > 3600000) {
                        tracker.lastHrpph = (leaders[i].score - tracker.lastHrScore) / (lastHrDiff / 3600000);
                        tracker.lastHrTime = Date.now();
                        tracker.lastHrScore = leaders[i].score;
                    }
                } else {
                    leaderTracker.push({userId: leaders[i].userId, name: leaders[i].name, rank: leaders[i].rank, startTime: Date.now(), startScore: leaders[i].score, pph: 0, lastHrTime: Date.now(), lastHrScore: leaders[i].score, lastHrpph: 0});
                }
            }
            InsertTrackedLeaders()
            setTimeout(CheckLeaderboard, 60000);
        });
    }

    function InsertTrackedLeaders() {
        for (let i=0, n=leaderTracker.length; i < n; i++) {
            if (document.querySelector('.leaderboard-portrait-' + leaderTracker[i].userId)) {
                let trackedLeaderElem = document.querySelector('#tracked-leader-' + leaderTracker[i].userId);
                let trackedLeaderText;
                if (!trackedLeaderElem) {
                    trackedLeaderElem = document.createElement('div');
                    trackedLeaderElem.id = 'tracked-leader-' + leaderTracker[i].userId;
                    trackedLeaderText = document.createElement('div');
                    trackedLeaderText.classList.add('bank');
                    trackedLeaderText.style.fontSize = '18px';
                    trackedLeaderText.style.padding = '4px 8px';
                    trackedLeaderElem.appendChild(trackedLeaderText);
                    let targetLeader = document.querySelector('.leaderboard-portrait-' + leaderTracker[i].userId)
                    targetLeader.insertBefore(trackedLeaderElem, targetLeader.querySelector('.score'));
                } else {
                    trackedLeaderText = trackedLeaderElem.querySelector('div');
                }
                let timeDiff = Date.now() - leaderTracker[i].startTime;
                trackedLeaderText.innerHTML = leaderTracker[i].pph.toLocaleString(undefined, {maximumFractionDigits: 0}) + ' /Hour [' + (timeDiff / 3600000).toFixed(2) + 'hrs]<br>' + leaderTracker[i].lastHrpph.toLocaleString(undefined, {maximumFractionDigits: 0}) + ' /Hour [last hr]';
            }
        }
    }

    async function ActivateLeaderTracker() {
        CheckLeaderboard();
        Game.app.on("LeaderboardUI-Loaded", t=>{InsertTrackedLeaders()});
    }
})();

 

<생산성 모니터링 스크립트>

// ==UserScript==
// @name         Production Rate Monitor
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Monitor production rate of specified craft items.
// @author       Groove
// @match        https://townstar.sandbox-games.com/launch/
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    const trackedItems = [
        {item: 'Wheat', count: 0, first: 0, oneMin: 0, oneHour: 0},
        {item: 'Wood', count: 0, first: 0, oneMin: 0, oneHour: 0},
    ];
    let loaded = 0;

    new MutationObserver(function(mutations) {
        if (document.querySelector('.hud .right .hud-right') && loaded == 0) {
            loaded = 1;
            LoadProductionMonitor();
        }
    }).observe(document, {childList: true, subtree: true});

    function LoadProductionMonitor() {
        let trackedHud = document.createElement('div');
        trackedHud.id = 'tracked-items';
        let trackedItemHeader = document.createElement('div');
        trackedItemHeader.id = 'tracked-item-header';
        trackedItemHeader.classList.add('bank');
        trackedItemHeader.style = 'width: 75%;';
        trackedItemHeader.innerHTML = 'Craft:&nbsp;Count&nbsp;|&nbsp;/1Min&nbsp;|&nbsp;/1Hour';
        trackedHud.appendChild(trackedItemHeader);
        let hudRight = document.querySelector('.hud .right .hud-right');
        hudRight.insertBefore(trackedHud, hudRight.querySelector('.right-hud').nextSibling);

        for (let item of trackedItems) {
            let trackedItemElem = document.createElement('div');
            trackedItemElem.id = 'tracked-item-' + item.item;
            trackedItemElem.classList.add('bank', 'contextual');
            trackedItemElem.style = 'width: 75%;';
            trackedItemElem.innerHTML = item.item + ':&nbsp;Count&nbsp;|&nbsp;/1Min&nbsp;|&nbsp;/1Hour';
            trackedHud.appendChild(trackedItemElem);
        }

        class TrackUnitDeliverOutputTask extends UnitDeliverOutputTask {
            onArrive() {
                super.onArrive();
                let trackedItem = trackedItems.find(item => item.item.toUpperCase() == this.craft.toUpperCase())
                if (trackedItem) {
                    trackedItem.count++;
                    if (trackedItem.count == 1) {
                        trackedItem.first = Date.now();
                    } else {
                        let timeDiff = Date.now() - trackedItem.first;
                        trackedItem.oneMin = trackedItem.count / (timeDiff / 60000)
                        trackedItem.oneHour = trackedItem.count / (timeDiff / 3600000)
                    }
                    document.getElementById('tracked-item-' + trackedItem.item).innerHTML = trackedItem.item + ':&nbsp;<b>' + trackedItem.count + '</b>&nbsp;|&nbsp;<b>' + trackedItem.oneMin.toFixed(2) + '</b>&nbsp;|&nbsp;<b>' + trackedItem.oneHour.toFixed(2) + '</b>';
                }
            }
        }

        let origfindDeliverOutputTask = TS_UnitLogic.prototype.findDeliverOutputTask;
        TS_UnitLogic.prototype.findDeliverOutputTask = function(t) {
            let origReturn = origfindDeliverOutputTask.call(this, t);
            return origReturn ? new TrackUnitDeliverOutputTask(origReturn.unit,origReturn.targetObject,t) : null
        }
    }
})();
반응형