Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

salien-script-js

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

salien-script-js - npm Package Compare versions

Comparing version 0.0.12 to 0.0.13

bin/cli.js

19

package.json
{
"name": "salien-script-js",
"version": "0.0.12",
"description": "An easy to install, run and update Node.js script for the Steam salien mini-game.",
"version": "0.0.13",
"description": "A easy to install, run and update Node.js script for the Steam salien mini-game.",
"keywords": [

@@ -33,7 +33,7 @@ "salien",

"files": [
"src",
"cli.js"
"bin",
"src"
],
"bin": {
"salien-script-js": "./cli.js"
"salien-script-js": "./bin/cli.js"
},

@@ -48,3 +48,5 @@ "main": "src/index.js",

"prepublishOnly": "npm run lint",
"prettier": "prettier --write \"src/**/*.js\""
"prettier": "prettier --write \"src/**/*.js\"",
"test": "jest",
"test/coverage": "jest --coverage"
},

@@ -55,7 +57,8 @@ "dependencies": {

"delay": "^3.0.0",
"fetch-retry": "^1.2.1",
"meow": "^5.0.0",
"node-fetch": "^2.1.2",
"update-check": "^1.5.2"
},
"devDependencies": {
"coveralls": "^3.0.1",
"eslint": "^5.0.0",

@@ -65,3 +68,5 @@ "eslint-config-airbnb-base": "^13.0.0",

"eslint-plugin-import": "^2.12.0",
"eslint-plugin-jest": "^21.17.0",
"eslint-plugin-prettier": "^2.6.0",
"jest": "^23.1.0",
"prettier": "^1.13.5"

@@ -68,0 +73,0 @@ },

# salien-script-js
👽 An easy to install, run and update Node.js script for the Steam salien mini-game.
👽 A easy to install, run and update Node.js script for the Steam salien mini-game.

@@ -9,2 +9,3 @@ > A Node.js implementation of https://github.com/SteamDatabase/SalienCheat by [xPaw](https://github.com/xPaw) with additional features!

[![CI Status](https://img.shields.io/travis/South-Paw/salien-script-js.svg)](https://travis-ci.org/South-Paw/salien-script-js)
[![Coveralls Status](https://img.shields.io/coveralls/github/South-Paw/salien-script-js.svg)](https://coveralls.io/github/South-Paw/salien-script-js)
[![Dependencies](https://david-dm.org/South-Paw/salien-script-js.svg)](https://david-dm.org/South-Paw/salien-script-js)

@@ -17,11 +18,20 @@ [![Dev Dependencies](https://david-dm.org/South-Paw/salien-script-js/dev-status.svg)](https://david-dm.org/South-Paw/salien-script-js?type=dev)

* 🎉 Easy to install, run and update
* ✉️ Update checker and log notifications
* 🎉 [Easy to install, run and update](#️-how-to-use-this)
* ✉️ [Update checker and log notifications](#-how-to-update-the-script)
* 👽 Same logic as the [PHP version](https://github.com/SteamDatabase/SalienCheat) (we almost have parity)
* 👌 Pick your own steam group
* 👥 Works well with multiple tokens/scripts
* 👀 Name your running scripts
* 🐳 Docker support
* ☁️ Heroku support
* 👌 [Pick your own steam group](#-represent-your-steam-group-optional)
* 👥 [Works well with multiple tokens/scripts](#-multiple-tokensscripts)
* 👀 [Name your running scripts](#-multiple-tokensscripts)
* ☁️ [Heroku support](#advanced-️-deploying-to-heroku)
* 🐳 [Docker support](#advanced--running-as-a-docker-container)
* 📦 [npm package export](#advanced--usage-as-an-npm-package)
> Note: We'll try our best to keep this version up to date with the PHP and other versions! Suggestions welcome.

@@ -40,3 +50,3 @@

> ### If you appreciate the script, please leave a star ⭐ on the project!
> ### Remeber to drop us a ⭐ star on the project if you appreciate this script!

@@ -69,20 +79,23 @@ ## 😍 How to update the script

* [/r/saliens](https://steamcommunity.com/groups/summersaliens) id: `103582791462557324`
* [SteamDB](https://steamcommunity.com/groups/steamdb) id: `103582791434298690`
* [100Pals](https://steamcommunity.com/groups/100pals) id: `103582791454524084`
* [SteamDB](https://steamcommunity.com/groups/steamdb) id: `103582791434298690`
### 🌌 Select a planet (Optional)
### 👥 Multiple tokens/scripts
If you would like to override planet selection in favor of a particular one, provide the `--planet` CLI option with the planet ID.
Simply open another PowerShell window and run `salien-script-js --token yyyyyyyy --name "name of this script"` where `yyyyyyyy` is your other accounts token and `name of this script` if what you'd like to see in the log outputs.
```sh-session
salien-script-js --token xxxxxxxx --planet 15
```
---
### 👥 Multiple tokens/scripts
### Advanced: CLI Arguments
Simply open another PowerShell window and run `salien-script-js --token yyyyyyyy --name "name of this script"` where `yyyyyyyy` is your other accounts token and `name of this script` if what you'd like to see in the log outputs.
```
Usage:
salien-script-js [options]
---
Options:
--token, -t Your Saliens game token.
--group, -g (Optional) The ID of a steam group you'd like to represent.
--name, -n (Optional) The name to display on this instance of the script.
--logRequests, -l (Optional) Set to true if you'd like to show Steam API requests in the logs.
```

@@ -92,3 +105,3 @@ ## Advanced: 📦 Usage as an npm package

```js
const SalienScript = require('salien-script-js');
const { SalienScript } = require('salien-script-js');

@@ -127,6 +140,9 @@ const config = {

1. Click the button above.
2. Set SALIEN_CONFIG (`token1:group1:name1;token2:group2:name2...`).
![Heroku-Config](https://i.imgur.com/07KcyVC.png)
2. Set SALIEN_CONFIG_V2 ([see note below](#heroku-configuration)).
3. That's all!
To check if it works, visit logs at https://dashboard.heroku.com/apps/[YOUR_APP_NAME]/logs
If you see "Application Error" when going to the webpage of your app, it's okay - the script will still run anyway.
### Deploying with Heroku CLI

@@ -138,3 +154,3 @@

$ heroku create [APP_NAME]
$ heroku config:set "SALIEN_CONFIG=token1:group1:name1;token2:group2:name2..."
$ heroku config:set "SALIEN_CONFIG_V2=[APP_CONFIG]"
$ git push heroku master

@@ -144,4 +160,81 @@ $ heroku ps:scale web=0 salien=1

And to check if it works:
```bash
$ heroku logs --tail
```
### Heroku configuration
`SALIEN_CONFIG_V2` is just an array of config that will be passed to `SalienScript` constructor.
If you only have one account, then your config will look like this:
```JSON
[
{
"token": "12345"
}
]
```
The only mandatory key for each account is `token` and you can add extra keys to this config such as `clan`, `name` or `selectedPlanetId`:
```JSON
[
{
"token": "12345",
"clan": "67890",
"name": "first_acc",
"selectedPlanetId": "28"
}
]
```
If you had two accounts for example;
* one named `first_acc` with a token of `123` and a group of `98712`
* one named `second_acc` with a token of `456` and a group of `67890`
then you would make your config look like this:
```JSON
[
{
"token": "123",
"clan": "98712",
"name": "first_acc"
},
{
"token": "456",
"clan": "67890",
"name": "second_acc"
}
]
```
### Updating
#### Easy
The easiest way to update script on heroku is to just delete your old app and create new.
You can also link your Heroku app to your Dropbox account. To do that, [download this repository](https://github.com/South-Paw/salien-script-js/archive/master.zip) as a zip archive, and unpack it to the folder created on your Dropbox.
For more info on this, visit: https://devcenter.heroku.com/articles/dropbox-sync
#### Medium
1. Fork this repo on github.
2. In your heroku app control panel, at Deploy tab, connect your app to a forked repository and enable automatic deploys.
3. When update comes, merge changes into your repo on github:
1. Create new pull request.
2. Select your repo's master branch as base fork, and South-Paw/salien-script-js master branch as head fork.
3. Click on a big green button "Merge pull request".
For more info on connecting github account, visit: https://devcenter.heroku.com/articles/github-integration
For more info on syncing fork using web interface, check this tutorial: https://www.sitepoint.com/quick-tip-sync-your-fork-with-the-original-without-the-cli/
#### Hard
If you created your app using web-console, you need to clone heroku repo first

@@ -148,0 +241,0 @@

@@ -28,298 +28,95 @@ /**

const chalk = require('chalk');
const dateFormat = require('dateformat');
const delay = require('delay');
const fetch = require('fetch-retry');
const checkForUpdate = require('update-check');
const {
getPlayerInfo,
getPlanets,
getPlanet,
representClan,
leaveGame,
joinPlanet,
joinZone,
reportScore,
} = require('./api/index');
const { getZoneDifficultyName, getScoreForZone, getAllPlanetStates, getBestPlanetAndZone } = require('./game/index');
const { SalienScriptRestart } = require('./exceptions');
const { getPercentage, updateCheck, utilLogger } = require('./util');
const pkg = require('../package.json');
const logger = (name, ...messages) => {
let message = chalk.white(dateFormat(new Date(), '[HH:MM:ss]'));
if (name) {
message += ` (${name})`;
}
// eslint-disable-next-line no-console
console.log(message, ...messages);
};
// eslint-disable-next-line no-console
const debug = message => console.log(`${JSON.stringify(message, 0, 2)}`);
const getPercentage = number => Number(number * 100).toFixed(2);
const getDifficultyName = zone => {
const boss = zone.type === 4 ? 'BOSS - ' : '';
switch (zone.difficulty) {
case 3:
return `${boss}Hard`;
case 2:
return `${boss}Medium`;
case 1:
return `${boss}Low`;
default:
return `${boss}${zone.difficulty}`;
}
};
const getScoreForZone = zone => {
let score;
switch (zone.difficulty) {
case 1:
score = 5;
break;
case 2:
score = 10;
break;
case 3:
score = 20;
break;
default:
score = 5;
break;
}
return score * 120;
};
const formatPlanetName = name =>
name
.replace('#TerritoryControl_Planet', '')
.split('_')
.join(' ');
const updateCheck = async name => {
let hasUpdate = null;
try {
hasUpdate = await checkForUpdate(pkg, { interval: 120000 });
} catch (err) {
logger(name, ` ${chalk.bgRed(' UpdateCheck ')}`, chalk.red(`Failed to check for updates: ${err}`));
}
if (await hasUpdate) {
logger(
name,
` ${chalk.bgMagenta(' UpdateCheck ')}`,
`The latest version is ${chalk.bgCyan(hasUpdate.latest)}. Please update!`,
);
logger(
name,
` ${chalk.bgMagenta(' UpdateCheck ')}`,
`To update, stop this script and run: ${chalk.bgCyan('npm i -g salien-script-js')}`,
);
// eslint-disable-next-line
console.log('');
}
};
class SalienScriptException {
constructor(message) {
this.name = 'SalienScriptException';
this.message = message;
}
}
class SalienScriptRestart {
constructor(message) {
this.name = 'SalienScriptRestart';
this.message = message;
}
}
class SalienScript {
constructor({ token, clan, selectedPlanetId, name = null }) {
constructor({ token, clan, name = null, logRequests = false }) {
// user defined variables
this.token = token;
this.clan = clan;
this.selectedPlanetId = selectedPlanetId;
this.clanId = clan;
this.name = name;
this.isSilentRequest = !logRequests;
this.maxRetries = 3;
// script variables
this.startTime = null;
this.knownPlanets = new Map();
this.currentPlanetAndZone = null;
this.steamThinksPlanet = null;
this.skippedPlanets = [];
// script variables that don't get reset
this.clanCheckDone = false;
// script defaults
this.gameWaitTimeSec = 110;
this.defaultDelayMs = 5000;
this.defaultDelaySec = this.defaultDelayMs / 1000;
this.cutoff = 0.99;
}
resetScript() {
this.startTime = null;
this.waitTime = 110;
this.hasJoinedClan = false;
this.isUpdateChecked = false;
this.currentPlanetId = null;
this.steamPlanetId = null;
this.knownPlanets = new Map();
this.knownPlanetIds = [];
this.currentPlanetAndZone = null;
this.steamThinksPlanet = null;
this.skippedPlanets = [];
}
async RequestAPI(method, params, maxRetries, additionalOptions = {}) {
let url = `https://community.steam-api.com/${method}/v0001`;
if (params) {
url += '/?';
params.forEach(param => {
url += `${param}&`;
});
url = url.substring(0, url.length - 1);
}
const options = {
retries: 3,
retryDelay: 1000,
headers: {
Accept: '*/*',
Origin: 'https://steamcommunity.com',
Referer: 'https://steamcommunity.com/saliengame/play/',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
},
...additionalOptions,
};
let request;
let response;
let retries = 0;
while (!response && retries < maxRetries) {
try {
logger(this.name, chalk.blue(` Sending ${method}...`));
request = await fetch(url, options);
response = await request.json();
} catch (e) {
// TODO there is some error handling/messaging we could implement here
// see: https://github.com/SteamDatabase/SalienCheat/blob/ac3a28aeb0446ff80cf6a6e1370fd5ef42e75aa2/cheat.php#L533
logger(this.name, ` ${chalk.bgRed(`${e.name}:`)} ${chalk.red(`For ${method}`)}`);
debug(e);
retries += 1;
if (retries < maxRetries) {
logger(this.name, chalk.yellow(` Retrying ${method} in ${this.defaultDelaySec} seconds...`));
} else {
throw new SalienScriptException(`Failed ${method} after ${retries} retries`);
}
await delay(this.defaultDelayMs);
}
}
return response.response;
logger(message, error) {
utilLogger(this.name, { message, error });
}
async ApiGetPlanets() {
const response = await this.RequestAPI(
'ITerritoryControlMinigameService/GetPlanets',
['active_only=1'],
this.maxRetries,
);
return response.planets;
async apiGetPlayerInfo() {
return getPlayerInfo(this.token, (m, e) => this.logger(m, e), this.isSilentRequest);
}
async ApiGetPlanet(planetId) {
const response = await this.RequestAPI(
'ITerritoryControlMinigameService/GetPlanet',
[`id=${planetId}`, 'language=english'],
this.maxRetries,
);
return response.planets[0];
async apiGetPlanets() {
return getPlanets((m, e) => this.logger(m, e), this.isSilentRequest);
}
async ApiGetPlayerInfo() {
const response = await this.RequestAPI(
'ITerritoryControlMinigameService/GetPlayerInfo',
[`access_token=${this.token}`],
this.maxRetries,
{ method: 'POST' },
);
return response;
async apiGetPlanet(planetId) {
return getPlanet(planetId, (m, e) => this.logger(m, e), this.isSilentRequest);
}
async ApiRepresentClan(clanId) {
const response = await this.RequestAPI(
'ITerritoryControlMinigameService/RepresentClan',
[`access_token=${this.token}`, `clanid=${clanId}`],
this.maxRetries,
{ method: 'POST' },
);
return response;
async apiRepresentClan(clanId) {
return representClan(this.token, clanId, (m, e) => this.logger(m, e), this.isSilentRequest);
}
async ApiLeaveGame(gameId) {
const response = await this.RequestAPI(
'IMiniGameService/LeaveGame',
[`access_token=${this.token}`, `gameid=${gameId}`],
this.maxRetries,
{ method: 'POST' },
);
return response;
async apiLeaveGame(gameId) {
return leaveGame(this.token, gameId, (m, e) => this.logger(m, e), this.isSilentRequest);
}
async ApiJoinPlanet(planetId) {
const response = await this.RequestAPI(
'ITerritoryControlMinigameService/JoinPlanet',
[`access_token=${this.token}`, `id=${planetId}`],
this.maxRetries,
{ method: 'POST' },
);
return response;
async apiJoinPlanet(planetId) {
return joinPlanet(this.token, planetId, (m, e) => this.logger(m, e), this.isSilentRequest);
}
async ApiJoinZone(zoneId) {
const response = await this.RequestAPI(
'ITerritoryControlMinigameService/JoinZone',
[`access_token=${this.token}`, `zone_position=${zoneId}`],
this.maxRetries,
{ method: 'POST' },
);
return response;
async apiJoinZone(zoneId) {
return joinZone(this.token, zoneId, (m, e) => this.logger(m, e), this.isSilentRequest);
}
async ApiReportScore(score) {
const response = await this.RequestAPI(
'ITerritoryControlMinigameService/ReportScore',
[`access_token=${this.token}`, `score=${score}`, `language=english`],
this.maxRetries,
{ method: 'POST' },
);
return response;
async apiReportScore(score) {
return reportScore(this.token, score, (m, e) => this.logger(m, e), this.isSilentRequest);
}
async leaveCurrentGame(leaveCurrentPlanet = 0) {
let playerInfo;
async leaveCurrentGame(requestedPlanetId = 0) {
const playerInfo = await this.apiGetPlayerInfo();
while (!playerInfo) {
playerInfo = await this.ApiGetPlayerInfo();
}
if (playerInfo.active_zone_game) {
await this.ApiLeaveGame(playerInfo.active_zone_game);
await this.apiLeaveGame(playerInfo.active_zone_game);
}
if (this.clan && !this.hasJoinedClan && playerInfo.clan_info && playerInfo.clan_info.accountid !== this.clan) {
logger(this.name, ` Attempting to join groupId: ${chalk.yellow(this.clan)}`);
await this.ApiRepresentClan(this.clan);
let clanCheckInfo = null;
while (!clanCheckInfo) {
clanCheckInfo = await this.ApiGetPlayerInfo();
}
if (clanCheckInfo.clan_info) {
logger(this.name, ` ${chalk.bgCyan(` Joined group: ${clanCheckInfo.clan_info.name} `)}`);
logger(
this.name,
` ${chalk.yellow("If the name above isn't expected, check if you're actually a member of that group")}`,
);
}
this.hasJoinedClan = true;
}
if (!playerInfo.active_planet) {

@@ -331,9 +128,9 @@ return 0;

if (leaveCurrentPlanet > 0 && leaveCurrentPlanet !== activePlanet) {
logger(
this.name,
`>> Leaving planet ${chalk.yellow(activePlanet)}, because we want to be on ${chalk.yellow(leaveCurrentPlanet)}`,
);
if (requestedPlanetId > 0 && requestedPlanetId !== activePlanet) {
let message = `>> Leaving planet ${chalk.yellow(activePlanet)}, because`;
message += ` we want to be on ${chalk.yellow(requestedPlanetId)}`;
await this.ApiLeaveGame(activePlanet);
this.logger(message);
await this.apiLeaveGame(activePlanet);
}

@@ -344,353 +141,63 @@

async getFirstAvailableZone(planetId) {
let planet;
async doClanSetup() {
let playerInfo = await this.apiGetPlayerInfo();
while (!planet) {
planet = await this.ApiGetPlanet(planetId);
}
if (this.clanId && !this.clanCheckDone && playerInfo.clan_info) {
this.logger(`Attempting to join group id: ${chalk.yellow(this.clanId)}`);
if (!planet.zones) {
return null;
}
await this.apiRepresentClan(this.clanId);
const planetName = planet.state.name;
const planetCaptured = planet.state.capture_progress;
const planetPlayers = planet.state.current_players;
const { zones } = planet;
playerInfo = await this.apiGetPlayerInfo();
const cleanZones = [];
if (playerInfo.clan_info) {
this.logger(chalk.bgCyan(` Joined group: ${playerInfo.clan_info.name} `));
this.logger(chalk.yellow("If the name above isn't expected, check if you're actually a member of that group"));
let hardZones = 0;
let mediumZones = 0;
let easyZones = 0;
let unknownZones = 0;
let toReturn = null;
zones.forEach(zone => {
if (zone.captured) {
return;
this.clanCheckDone = true;
}
if (zone.type !== 3) {
logger(this.name, chalk.red(`!! Unknown zone type: ${zone.type}`));
}
// If a zone is close to completion, skip it because Valve does not reward points and replies with 42 NoMatch
if (zone.capture_progress && zone.capture_progress > 0.97) {
return;
}
switch (zone.difficulty) {
case 3:
hardZones += 1;
break;
case 2:
mediumZones += 1;
break;
case 1:
easyZones += 1;
break;
default:
unknownZones += 1;
break;
}
// Always join boss zone
if (zone.type === 4) {
toReturn = {
hardZones,
mediumZones,
easyZones,
unknownZones,
planetPlayers,
planetCaptured,
planetName,
...zone,
};
return;
}
cleanZones.push(zone);
});
if (toReturn) {
return toReturn;
console.log(''); // eslint-disable-line no-console
}
if (cleanZones.length < 0) {
return false;
}
cleanZones.sort((a, b) => {
if (b.difficulty === a.difficulty) {
return b.zone_position - a.zone_position;
}
return b.difficulty - a.difficulty;
});
return {
hardZones,
mediumZones,
easyZones,
unknownZones,
planetPlayers,
planetCaptured,
planetName,
...cleanZones[0],
};
}
async isThereAnyNewPlanets(knownPlanetIds) {
logger(this.name, ' Checking for any new planets...');
async doGameSetup() {
const planets = await this.apiGetPlanets();
let planets;
this.knownPlanets = await getAllPlanetStates(
planets,
this.cutoff,
(m, e) => this.logger(m, e),
this.isSilentRequest,
);
while (!planets) {
planets = await this.ApiGetPlanets();
}
this.currentPlanetAndZone = await getBestPlanetAndZone(this.knownPlanets, (m, e) => this.logger(m, e));
if (!planets) {
return false;
}
const zoneCapturePercent = getPercentage(this.currentPlanetAndZone.bestZone.capture_progress);
let hasNewPlanet = false;
let zoneMsg = `>> Selected Next Zone ${chalk.green(this.currentPlanetAndZone.bestZone.zone_position)}`;
zoneMsg += ` on Planet ${chalk.green(this.currentPlanetAndZone.id)}`;
zoneMsg += ` (Captured: ${chalk.yellow(`${zoneCapturePercent}%`.padStart(6))}`;
zoneMsg += ` - Difficulty: ${chalk.yellow(getZoneDifficultyName(this.currentPlanetAndZone.bestZone))})`;
await planets.forEach(planet => {
if (!knownPlanetIds.includes(planet.id)) {
hasNewPlanet = true;
}
});
this.logger(zoneMsg);
return hasNewPlanet;
console.log(''); // eslint-disable-line no-console
}
async setupGame() {
const planets = await this.ApiGetPlanets();
async doGameLoop() {
while (this.currentPlanetAndZone.id !== this.steamThinksPlanet) {
this.steamThinksPlanet = await this.leaveCurrentGame(this.currentPlanetAndZone.id);
if (!planets) {
throw new SalienScriptException("Didn't find any planets.");
}
if (this.currentPlanetAndZone.id !== this.steamThinksPlanet) {
await this.apiJoinPlanet(this.currentPlanetAndZone.id);
logger(this.name, ' Getting first available planet...');
try {
// Patch the apiGetPlanets response with zones from apiGetPlanet
const mappedPlanets = await Promise.all(
planets.map(async planet => {
const object = Object.assign({}, planet);
const currentPlanet = await this.ApiGetPlanet(planet.id);
object.zones = currentPlanet.zones;
return object;
}),
);
mappedPlanets.forEach(planet => {
let hardZones = 0;
let mediumZones = 0;
let easyZones = 0;
let unknownZones = 0;
let hasBossZone = false;
// Filter out captured zones + determine zone types
planet.zones.forEach(zone => {
if ((zone.capture_progress && zone.capture_progress > 0.97) || zone.captured) {
return;
}
if (zone.type === 4) {
hasBossZone = true;
} else if (zone.type !== 3) {
logger(this.name, chalk.red(`!! Unknown zone type: ${zone.type}`));
}
switch (zone.difficulty) {
case 3:
hardZones += 1;
break;
case 2:
mediumZones += 1;
break;
case 1:
easyZones += 1;
break;
default:
unknownZones += 1;
break;
}
});
this.knownPlanetIds.push(planet.id);
this.knownPlanets.set(planet.id, {
hardZones,
mediumZones,
easyZones,
unknownZones,
hasBossZone,
...planet,
});
const capturedPercent = getPercentage(planet.state.capture_progress).toString();
const planetName = formatPlanetName(planet.state.name);
let logMsg = `>> Planet: ${chalk.green(planet.id)}`;
logMsg += ` - Hard: ${chalk.yellow(hardZones)} - Medium: ${chalk.yellow(mediumZones)}`;
logMsg += ` - Easy: ${chalk.yellow(easyZones)} - Captured: ${chalk.yellow(capturedPercent)}%`;
logMsg += ` - Players: ${chalk.yellow(planet.state.current_players.toLocaleString())}`;
logMsg += ` (${chalk.green(planetName)})`;
logger(this.name, logMsg);
if (unknownZones) {
logger(this.name, `>> Unknown zones found: ${chalk.yellow(unknownZones)}`);
}
});
this.knownPlanetIds.forEach(id => {
const planet = this.knownPlanets.get(id);
if (planet.hasBossZone) {
this.currentPlanetId = planet.id;
throw new SalienScriptException('Boss zone found!');
}
});
} catch (e) {
if (e.name === 'SalienScriptException' && e.message === 'Boss zone found!') {
logger(
this.name,
chalk.green(`>> Planet ${chalk.yellow(this.currentPlanetId)} has a boss zone, selecting this planet`),
);
} else {
debug(e);
throw new SalienScriptException(e.message);
this.steamThinksPlanet = await this.leaveCurrentGame();
}
}
// FIXME this logic might be able to be cleaned up
const priority = ['hardZones', 'mediumZones', 'easyZones'];
const zone = await this.apiJoinZone(this.currentPlanetAndZone.bestZone.zone_position);
if (!this.currentPlanetId) {
const sortedPlanetIds = this.knownPlanetIds.sort((a, b) => {
const planetA = this.knownPlanets.get(a);
const planetB = this.knownPlanets.get(b);
for (let i = 0; i < priority.length; i += 1) {
const key = priority[i];
if (planetA[key] !== planetB[key]) {
return planetA[key] - planetB[key];
}
}
return Number(planetA.id) - Number(planetB.id);
});
// Attempt to get selected planet from provided planet id
const selectedPlanet = this.knownPlanets.get(this.selectedPlanetId);
// If the selected planet is not valid, handle it
if (!selectedPlanet || this.skippedPlanets.includes(this.selectedPlanetId)) {
// Only log if a planet was selected
if (this.selectedPlanetId) {
logger(
this.name,
`>> Selected planet ${chalk.yellow(
this.selectedPlanetId,
)} not available. Selecting next available planet...`,
);
}
for (let i = 0; i < priority.length; i += 1) {
sortedPlanetIds.forEach(planetId => {
const planet = this.knownPlanets.get(planetId);
if (this.skippedPlanets.includes(planetId) || !planet[priority[i]]) {
return;
}
if (!planet.state.captured && !this.currentPlanetId) {
const planetName = formatPlanetName(planet.state.name);
logger(this.name, `>> Selected planet ${chalk.green(planetId)} (${chalk.green(planetName)})`);
this.currentPlanetId = planetId;
}
});
}
} else if (!selectedPlanet.state.captured && !this.currentPlanetId) {
const planetName = formatPlanetName(selectedPlanet.state.name);
logger(this.name, `>> Selected planet ${chalk.green(this.selectedPlanetId)} (${chalk.green(planetName)})`);
this.currentPlanetId = this.selectedPlanetId;
}
if (!this.currentPlanetId) {
// If there are no planets with hard or medium zones, just return first one
this.currentPlanetId = planets[0].id;
}
}
while (this.currentPlanetId !== this.steamPlanetId) {
// Leave current game before trying to switch planets (it will report InvalidState otherwise)
this.steamPlanetId = await this.leaveCurrentGame(this.currentPlanetId);
if (this.currentPlanetId !== this.steamPlanetId) {
await this.ApiJoinPlanet(this.currentPlanetId);
this.steamPlanetId = await this.leaveCurrentGame();
}
}
}
async gameLoop() {
console.log(''); // eslint-disable-line no-console
await updateCheck(this.name);
// Scan planets every 10 minutes
if (new Date().getTime() - this.startTime > 600000) {
throw new SalienScriptRestart('!! Re-scanning for new planets');
}
let zone;
while (!zone) {
zone = await this.getFirstAvailableZone(this.currentPlanetId);
}
if (zone === false) {
this.skippedPlanets.push(this.currentPlanetId);
throw new SalienScriptRestart('!! There are no zones to join in this planet');
}
const { hardZones, mediumZones, easyZones, planetCaptured, planetPlayers } = zone;
if (!hardZones) {
if (!mediumZones && new Date().getTime() - this.startTime > this.waitTime * 1000) {
throw new SalienScriptRestart('!! No hard or medium zones on this planet');
}
const hasNewPlanet = await this.isThereAnyNewPlanets(this.knownPlanetIds);
if (hasNewPlanet) {
throw new SalienScriptRestart('!! Detected a new planet');
}
}
const planetName = formatPlanetName(zone.planetName);
const position = zone.zone_position;
zone = null;
while (!zone) {
zone = await this.ApiJoinZone(position);
}
// rescan if we failed to join
if (!zone.zone_info) {
throw new SalienScriptRestart('!! Failed to join a zone');
throw new SalienScriptRestart('!! Failed to join a zone', zone);
}

@@ -700,63 +207,64 @@

const capturedPercent = getPercentage(planetCaptured).toString();
const zoneCapturePercent = getPercentage(zoneInfo.capture_progress);
let planetLogMsg = `>> Planet ${chalk.green(this.currentPlanetId)} - Captured: ${chalk.yellow(capturedPercent)}%`;
planetLogMsg += ` - Hard: ${chalk.yellow(hardZones)} - Medium: ${chalk.yellow(mediumZones)}`;
planetLogMsg += ` - Easy: ${chalk.yellow(easyZones)}`;
planetLogMsg += ` - Players: ${chalk.yellow(planetPlayers.toLocaleString())} (${chalk.green(planetName)})`;
let joinMsg = `>> Joined Zone ${chalk.green(zoneInfo.zone_position)}`;
joinMsg += ` on Planet ${chalk.green(this.currentPlanetAndZone.id)}`;
joinMsg += ` (Captured: ${chalk.yellow(`${zoneCapturePercent}%`.padStart(6))}`;
joinMsg += ` - Difficulty: ${chalk.yellow(getZoneDifficultyName(this.currentPlanetAndZone.bestZone))})`;
logger(this.name, planetLogMsg);
this.logger(joinMsg);
const capturedProgress = !zoneInfo.capture_progress ? 0 : getPercentage(zoneInfo.capture_progress).toString();
if (zoneInfo.top_clans) {
this.logger(`-- Top Clans:${zoneInfo.top_clans.map(({ name }) => ` ${name}`)}`);
}
let zoneLogMsg = `>> Zone ${chalk.green(zoneInfo.zone_position)} - Captured: ${chalk.yellow(capturedProgress)}%`;
zoneLogMsg += ` - Difficulty: ${chalk.yellow(getDifficultyName(zoneInfo))}`;
console.log(''); // eslint-disable-line no-console
this.logger(`${chalk.bgMagenta(` Waiting ${this.gameWaitTimeSec} seconds for round to finish... `)}`);
logger(this.name, zoneLogMsg);
// 10 seconds before the score is reported, get the next planet and zone we should focus on.
setTimeout(async () => {
await this.doGameSetup();
}, (this.gameWaitTimeSec - 10) * 1000);
if (zoneInfo.top_clans) {
logger(this.name, `-- Top Clans:${zoneInfo.top_clans.map(({ name }) => ` ${name}`)}`);
}
await delay(this.gameWaitTimeSec * 1000);
logger(this.name, ` ${chalk.bgMagenta(` Waiting ${this.waitTime} seconds for round to finish... `)}`);
const score = await this.apiReportScore(getScoreForZone(zoneInfo));
await delay(this.waitTime * 1000);
// cause the game's api returns some numbers as strings and others as numbers
const oldScore = Number(score.old_score);
const newScore = Number(score.new_score);
const nextLevelScore = Number(score.next_level_score);
const newLevel = Number(score.new_level);
const report = await this.ApiReportScore(getScoreForZone(zoneInfo));
if (newScore) {
const earnedXp = newScore - oldScore;
const nextLevelPercent = getPercentage(newScore / nextLevelScore);
if (report.new_score) {
const earnedXp = report.new_score - report.old_score;
const nextLevelPercent = getPercentage(report.new_score / report.next_level_score);
console.log(''); // eslint-disable-line no-console
let currentLevelMsg = `>> XP Earned: ${chalk.green(earnedXp.toLocaleString())}`;
currentLevelMsg += ` (${chalk.yellow(report.old_score.toLocaleString())} XP`;
currentLevelMsg += ` => ${chalk.green(report.new_score.toLocaleString())} XP)`;
currentLevelMsg += ` - Current Level: ${chalk.green(report.new_level)} (${nextLevelPercent}% to next)`;
let currentLevelMsg = `>> Score: ${chalk.cyan(Number(newScore).toLocaleString())}`;
currentLevelMsg += ` (${chalk.green(`+${earnedXp.toLocaleString()}`)})`;
currentLevelMsg += ` - Current Level: ${chalk.green(newLevel)} (${nextLevelPercent}%)`;
logger(this.name, currentLevelMsg);
this.logger(currentLevelMsg);
const remainingXp = report.next_level_score - report.new_score;
const remainingXp = nextLevelScore - newScore;
const timeRemaining =
((report.next_level_score - report.new_score) / getScoreForZone(zoneInfo)) * (this.waitTime / 60);
const timeRemaining = ((nextLevelScore - newScore) / getScoreForZone(zoneInfo)) * (this.gameWaitTimeSec / 60);
const hoursRemaining = Math.floor(timeRemaining / 60);
const minutesRemaining = Math.round(timeRemaining % 60);
const levelEta = `${hoursRemaining}h ${minutesRemaining}m`;
const levelEta = `${hoursRemaining}h ${hoursRemaining === 0 && minutesRemaining === 0 ? 2 : minutesRemaining}m`;
let nextLevelMsg = `>> Next Level: ${chalk.yellow(report.next_level_score.toLocaleString())} XP`;
nextLevelMsg += ` - Remaining: ${chalk.yellow(remainingXp.toLocaleString())} XP - ETA: ${chalk.green(levelEta)}`;
let nextLevelMsg = `>> Next Level: ${chalk.yellow(nextLevelScore.toLocaleString())} XP`;
nextLevelMsg += ` - Remaining: ${chalk.yellow(remainingXp.toLocaleString())} XP`;
nextLevelMsg += ` - ETA: ${chalk.green(levelEta)}\n`;
logger(this.name, nextLevelMsg);
this.logger(nextLevelMsg);
}
// Some users get stuck in games after calling ReportScore, so we manually leave to fix this
let leftGame;
const leavingGame = await this.leaveCurrentGame(this.currentPlanetAndZone.id);
while (!leftGame) {
leftGame = await this.leaveCurrentGame(this.currentPlanetId);
if (leavingGame !== this.currentPlanetAndZone.id) {
throw new SalienScriptRestart(`!! Wrong current Planet ${chalk.yellow(leavingGame)}`);
}
if (leftGame !== this.currentPlanetId) {
throw new SalienScriptRestart('!! Wrong current planet');
}
}

@@ -767,30 +275,25 @@

// Reset all variables to default values every time init() is called
this.currentPlanetId = null;
this.knownPlanetIds = [];
this.knownPlanets = new Map();
this.skippedPlanets = [];
console.log(''); // eslint-disable-line no-console
this.logger(chalk.bgGreen(` Started SalienScript | Version: ${pkg.version} `));
this.logger(chalk.bgCyan(' Thanks for choosing https://github.com/South-Paw/salien-script-js '));
this.logger(chalk.bgCyan(' Remeber to drop us a ⭐ star on the project if you appreciate this script! '));
console.log(''); // eslint-disable-line no-console
this.resetScript();
try {
logger(this.name, ` ${chalk.bgGreen(` Started SalienScript | Version: ${pkg.version} `)}`);
logger(
this.name,
` ${chalk.bgCyan(` If you appreciate the script, please remember to leave a ⭐ star ⭐ on the project! `)}`,
);
await this.doClanSetup();
await this.setupGame();
await this.doGameSetup();
// eslint-disable-next-line no-constant-condition
while (true) {
await this.gameLoop();
await updateCheck(this.name);
await this.doGameLoop();
}
} catch (e) {
logger(this.name, ` ${chalk.bgRed(`${e.name}:`)} ${chalk.red(e.message)}`);
this.logger(`${chalk.bgRed(`${e.name}:`)} ${chalk.red(e.message)}`, e.name !== 'SalienScriptRestart' ? e : null);
this.logger(`${chalk.bgMagenta(` Script will restart in ${this.defaultDelaySec} seconds... `)}\n\n`);
if (e.name !== 'SalienScriptRestart') {
debug(e);
}
logger(this.name, ` ${chalk.bgMagenta(` Script will restart in ${this.defaultDelaySec} seconds... `)}\n\n`);
await delay(this.defaultDelayMs);

@@ -797,0 +300,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc