Skip to content

Instantly share code, notes, and snippets.

@guiferrpereira
Forked from MrCelticFox/README.md
Created June 17, 2021 09:22
Show Gist options
  • Save guiferrpereira/588874ac4a2e61004edd02acee185077 to your computer and use it in GitHub Desktop.
Save guiferrpereira/588874ac4a2e61004edd02acee185077 to your computer and use it in GitHub Desktop.
An updated and improved auto-sell script for TownStar

Improved TownStar Auto-Sell Script

Disclaimer

At the time of writing scripts are allowed to be used with TownStar, as long as they don't do anything that breaks the game, but double check what the rules say to be sure: https://support.gala.games/town-star-rules

Use at your own risk, I have tested this and am satisfied it is free of bugs, but I am not responsible for any loss incurred by others that arose from using this script.

Now for the fun stuff...

 

How to use

This script is designed to be used with Tampermonkey, if you haven't used this extension before then please first install it. Then you can just create a new script through Tampermonkey and paste the contents of updated_sell_script.js into it. Then open or refresh TownStar and it should load. If you open the developper tools you will see some info messages in the console.

This script supports both Trade Depots and Trade Piers. It does NOT currently support Freight Piers or Express Depots (though I might add it in future) If you want to use a Freight Pier you can always use the original script for that one item, or you can experiment with adding bits of your own code.

However, it does support any number of Trade Depots and Trade Piers (including a mix of both) and will use them all one after another in a loop! This is automatic and requires no configuration from the user.

Point to note: when you first load the game (or after a page refresh), you should manually open a trade terminal on each edge of your town, just to let the trades load for that side or it might cause the script to glith on the first trade (if all your depots are on one side then you only need to do one)

There are 3 things you need to configure:

  • sellTimer: the optimal value is given by calculating longest_journey_time/number_of_trade_terminals (and it's better to always round up a bit)
  • gasLimit: the minimum amount of gas you want to keep (in case you want some spare for manual sales). Must also be enough for at least one trade (so 0 is not ok!)
  • sellItemsAndLimits: the most important part, here you should add every item you want to be sold automatically and a threshold value. The threshold is the minimum amount you want to keep, so the script will only sell when you have threshold+10 of that item. See Examples section for more details.

Thats's it! Simply configure those variables and you should be good to go (remember to refresh the game to load any changes you made to the script).

 

Examples

To illustrate the script's full functionality, here are some examples.

Example 1

I'm running a wine build and also selling grapes for cash, I have two Trade Depots and travel time is 35secs at a cost of 1 fuel (lucky me!). I also sometimes have a surplus of Oak Wood but I want to keep between 10 and 20 of them. Everything else is assumed to be balanced for this example. Here is my config:

const sellTimer = 20; // 35/2 = 17.5, and round up to 20 just to be safe
const gasLimit = 1; // I don't want to keep any extra
const sellItemsAndLimits = [
    ['Wine', 0], // Don't keep any wine (it will sell when I have > 0+9 wine, so 10)
    ['Pinot_Noir_Grapes', 20], // I want to keep at least 20, so this will sell anything over 29
    ['Oak_Wood', 10] // I want to keep between 10 and 20, so anything over 19 will be sold
]; 

Example 2

I'm running a Pumpkin Pie build, I have 3 Trade Piers and 2 Trade Depots, my longest travel time is 3mins (so 180secs) and fuel cost is 2. I'm selling grapes for cash but I also sometimes have surplus of wood, gas, eggs, pumpkins, etc. I want to keep a few of each though so I can always make my pies. Here is my config:

const sellTimer = 40; // 180/5 = 36, going to round up to 40 to be safe
const gasLimit = 2; // I don't want to keep any extra but my limit is 2 fuel per trip
const sellItemsAndLimits = [
    ['Wood', 45], // sell when I have 55 or more
    ['Gasoline', 65], // sell when I have 75 or more
    ['Pinot_Noir_Grapes', 0], // sell as soon as I can
    ['Wheat', 20], // want to keep at least 20, sell when 30 or more
    ['Eggs', 15], // want to keep at least 15, sell when 25 or more
    ['Sugarcane', 20], // same as wheat, you get the idea
    ['Pumpkin', 20], // same as above
    ['Pumpkin_Pie', 0] // sell pies as soon as I have at least 10
]; 

Example 3

I have only 1 Trade Pier with a time of only 15secs and 1 gas cost. I do want to keep some extra gas for myself though, as I will manually use a Freight Pier sometimes which isn't handled by this script. The only things I want to sell automatically are blue steel and surplus cotton yarn. I also want to save some blue steel for the last day of the competition, so I will keep 2 stacks and sell the rest. Here is my config:

const sellTimer = 20; // 15/1 = 15, but going to round up anyway
const gasLimit = 10; // trip cost is 1, but I want to keep a few for manual sells
const sellItemsAndLimits = [
    ['Cotton_Yarn', 5], // keep at least 5, sell when I have 15 or more
    ['Blue_Steel', 20] // I want to keep 2 stacks of 10, so this will only sell when I have 30 or more, I will never drop under 20
]; 
// ==UserScript==
// @name Improved Town Star Auto-Sell
// @namespace http://tampermonkey.net/
// @version 0.1
// @description An improved version of the TownStar Auto-Sell script
// @author MrCelticFox
// @match https://townstar.sandbox-games.com/launch/
// @grant GM_setValue
// @grant GM_listValues
// @grant GM_getValue
// @grant GM_deleteValue
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const sellTimer = 300; // Seconds between selling (best setting is longest journey time divided by number of trade terminals)
const gasLimit = 16; // Minimum amount of gas to keep, script will not sell anything when gas falls below this value
const sellItemsAndLimits = [ // Put each item you want to sell here, and the limit (minimum amount that will NOT be sold)
['Wood', 65],
['Gasoline', 65],
['Pinot_Noir_Grapes', 0],
['Wheat', 20],
['Eggs', 15],
['Sugar', 15],
['Sugarcane', 20],
['Pumpkin', 20],
['Pumpkin_Pie', 0]
]; // All above are examples, you can put as many or as few as you want, and whatever limits you want
let sellItemIndex = 0;
// Updates the index for the items in a circular manner (goes back to the beginning when it hits the end)
function updateSellItemIndex() {
console.log("updating sellItem index..");
sellItemIndex += 1;
if (sellItemIndex >= sellItemsAndLimits.length) {
sellItemIndex = 0;
}
}
let availableDepots = []; // Leave empty, the script will auto-fill this with what's available in game
let depotIndex = 0;
// Updates the index for the depots and piers in a circular manner (goes back to the beginning when it hits the end)
function updateDepotIndex() {
console.log("updating depot index..");
depotIndex += 1;
if (depotIndex >= availableDepots.length) {
depotIndex = 0;
}
}
let sellingActive = 0;
/*
Handles basic game functions like automatically clicking 'play' when the page is refreshed
*/
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();
}
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") {
document.getElementById("playButton").click();
}
if(typeof Game != 'undefined' && Game.town != null) {
if(sellingActive == 0) {
console.log('Game loaded');
sellingActive = 1;
activateSelling();
//activateTestFunction();
}
}
}).observe(document, {attributes: true, childList: true , subtree: true});
/*
The main selling function
*/
function activateSelling() {
let start = GM_getValue("start", Date.now());
GM_setValue("start", start);
setTimeout(function(){
let tempSpawnCon = Trade.prototype.SpawnConnection;
Trade.prototype.SpawnConnection = function(r) {tempSpawnCon.call(this, r); console.log(r.craftType); GM_setValue(Math.round((Date.now() - start)/1000).toString(), r.craftType);}
},10000);
// load all the trade depots and trade piers into an array
availableDepots = Object.values(Game.town.objectDict).filter(o => (o.type === 'Trade_Pier' || o.type === 'Trade_Depot'));
window.mySellTimer = setInterval(function(){
let depotObj = availableDepots[depotIndex];
let depotKey = "[" + depotObj.townX + ", " + "0, " + depotObj.townZ + "]";
Game.town.objectDict[depotKey].logicObject.OnTapped(); // Collect reward from previous time if there is one
// Must have enough gas first
if (Game.town.GetStoredCrafts()["Gasoline"] > gasLimit) {
// Skip over any items we can't sell because they are below the limit
let tmpCounter = 0;
while(tmpCounter < sellItemsAndLimits.length) {
let tmpAmount = Game.town.GetStoredCrafts()[sellItemsAndLimits[sellItemIndex][0]];
if (typeof tmpAmount != 'undefined' && (tmpAmount > (sellItemsAndLimits[sellItemIndex][1] + 9)) ) {
break;
}
updateSellItemIndex();
tmpCounter++;
}
// Get item to sell and its limit from the array
let sellItem = sellItemsAndLimits[sellItemIndex][0];
let sellLimit = sellItemsAndLimits[sellItemIndex][1];
// Execute the trade (but double check because maybe we don't have enough of anything)
if (Game.town.GetStoredCrafts()[sellItem] > (sellLimit + 9)) {
console.log("SELLING " + sellItem + "!");
Game.app.fire("SellClicked", {x: depotObj.townX, z: depotObj.townZ});
setTimeout(function(){
let craftTarget = document.getElementById("trade-craft-target");
craftTarget.querySelectorAll('[data-name="' + sellItem + '"]')[0].click();
setTimeout(function(){
document.getElementById("destination-target").getElementsByClassName("destination")[0].getElementsByClassName("sell-button")[0].click();
},1000);
},3000);
updateDepotIndex();
updateSellItemIndex();
}
else {
console.log("Not enough items to sell");
}
}
else {
console.log("Not enough fuel");
}
},sellTimer*1000);
}
/*
For running tests while developing
*/
function activateTestFunction() {
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment