forked from alfficcadenti/splinterlands-bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
293 lines (260 loc) · 13.2 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
//'use strict';
require('dotenv').config()
const puppeteer = require('puppeteer');
const splinterlandsPage = require('./splinterlandsPage');
const user = require('./user');
const card = require('./cards');
const { clickOnElement, getElementText, getElementTextByXpath, teamActualSplinterToPlay } = require('./helper');
const quests = require('./quests');
const ask = require('./possibleTeams');
const chalk = require('chalk');
// LOAD MY CARDS
async function getCards() {
const myCards = await user.getPlayerCards(process.env.ACCOUNT.split('@')[0]) //split to prevent email use
return myCards;
}
async function getQuest() {
return quests.getPlayerQuest(process.env.ACCOUNT.split('@')[0])
.then(x=>x)
.catch(e=>console.log('No quest data, splinterlands API didnt respond, or you are wrongly using the email and password instead of username and posting key'))
}
async function closePopups(page) {
console.log('check if any modal needs to be closed...')
if (await clickOnElement(page, '.close', 4000) ) return;
await clickOnElement(page, '.modal-close-new', 1000, 2000);
await clickOnElement(page, '.modal-close', 4000, 2000);
}
async function startBotPlayMatch(page, myCards, quest) {
console.log( new Date().toLocaleString())
if(myCards) {
console.log(process.env.ACCOUNT, ' deck size: '+myCards.length)
} else {
console.log(process.env.ACCOUNT, ' playing only basic cards')
}
await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36');
await page.setViewport({
width: 1800,
height: 1500,
deviceScaleFactor: 1,
});
await page.goto('https://splinterlands.io/');
await page.waitForTimeout(8000);
let item = await page.waitForSelector('#log_in_button > button', {
visible: true,
})
.then(res => res)
.catch(()=> console.log('Already logged in'))
if (item != undefined)
{console.log('Login attempt...')
await splinterlandsPage.login(page).catch(e=>{
console.log(e);
throw new Error('Login Error');
});
}
await page.waitForTimeout(8000);
await closePopups(page);
await page.click('#menu_item_battle').then(()=>console.log('Entered...')).catch(e=>console.log('Battle Button not available'));
await closePopups(page);
await page.waitForTimeout(3000);
//check if season reward is available
if (process.env.CLAIM_SEASON_REWARD === 'true') {
try {
console.log('Season reward check: ');
await page.waitForSelector('#claim-btn', { visible:true, timeout: 3000 })
.then(async (button) => {
button.click();
console.log(`claiming the season reward. you can check them here https://peakmonsters.com/@${process.env.ACCOUNT}/explorer`);
await page.waitForTimeout(20000);
await page.reload();
})
.catch(()=>console.log(`no season reward to be claimed, but you can still check your data here https://peakmonsters.com/@${process.env.ACCOUNT}/explorer`));
await page.waitForTimeout(3000);
await page.reload();
}
catch (e) {
console.info('no season reward to be claimed')
}
}
//if quest done claim reward. default to true. to deactivate daily quest rewards claim, set CLAIM_DAILY_QUEST_REWARD false in the env file
console.log('Quest details: ', quest);
const isClaimDailyQuestMode = process.env.CLAIM_DAILY_QUEST_REWARD === 'false' ? false : true;
if (isClaimDailyQuestMode === true) {
try {
await page.waitForSelector('#quest_claim_btn', { timeout: 5000 })
.then(button => button.click());
} catch (e) {
console.info('no quest reward to be claimed waiting for the battle...')
}
}
await page.waitForTimeout(5000);
// LAUNCH the battle
try {
const ecr = await getElementTextByXpath(page, "//div[@class='dec-options'][1]/div[@class='value'][2]/div", 100);
if(ecr) {
console.log(chalk.bold.whiteBright.bgMagenta('Your current Energy Capture Rate is ' + ecr.split('.')[0] + "%"));
}
console.log('waiting for battle button...')
await page.waitForXPath("//button[contains(., 'BATTLE')]", { timeout: 20000 })
.then(button => {console.log('Battle button clicked'); button.click()})
.catch(e=>console.error('[ERROR] waiting for Battle button. is Splinterlands in maintenance?'));
await page.waitForTimeout(5000);
console.log('waiting for an opponent...')
await page.waitForSelector('.btn--create-team', { timeout: 50000 })
.then(()=>console.log('start the match'))
.catch(async (e)=> {
console.error('[Error while waiting for battle]');
console.error('Refreshing the page and retrying to retrieve a battle');
await page.waitForTimeout(5000);
await page.reload();
await page.waitForTimeout(5000);
await page.waitForXPath("//button[contains(., 'BATTLE')]", { timeout: 20000 })
.then(button => {console.log('Battle button clicked'); button.click()})
.catch(e=>console.error('[ERROR] waiting for Battle button. is Splinterlands in maintenance?'));
await page.waitForSelector('.btn--create-team', { timeout: 50000 })
.then(()=>console.log('start the match'))
.catch(async ()=>{
console.log('second attempt failed reloading from homepage...');
await page.goto('https://splinterlands.io/');
await page.waitForTimeout(5000);
await page.waitForXPath("//button[contains(., 'BATTLE')]", { timeout: 20000 })
.then(button => button.click())
.catch(e=>console.error('[ERROR] waiting for Battle button second time'));
await page.waitForTimeout(5000);
await page.waitForSelector('.btn--create-team', { timeout: 50000 })
.then(()=>console.log('start the match'))
.catch((e)=>{
console.log('third attempt failed');
throw new Error(e);})
})
})
} catch(e) {
console.error('[Battle cannot start]:', e)
throw new Error('The Battle cannot start');
}
await page.waitForTimeout(10000);
let [mana, rules, splinters] = await Promise.all([
splinterlandsPage.checkMatchMana(page).then((mana) => mana).catch(() => 'no mana'),
splinterlandsPage.checkMatchRules(page).then((rulesArray) => rulesArray).catch(() => 'no rules'),
splinterlandsPage.checkMatchActiveSplinters(page).then((splinters) => splinters).catch(() => 'no splinters')
]);
const matchDetails = {
mana: mana,
rules: rules,
splinters: splinters,
myCards: myCards
}
await page.waitForTimeout(2000);
const possibleTeams = await ask.possibleTeams(matchDetails).catch(e=>console.log('Error from possible team API call: ',e));
if (possibleTeams && possibleTeams.length) {
console.log('Possible Teams based on your cards: ', possibleTeams.length, '\n', possibleTeams);
} else {
console.log('Error:', matchDetails, possibleTeams)
throw new Error('NO TEAMS available to be played');
}
//TEAM SELECTION
const teamToPlay = await ask.teamSelection(possibleTeams, matchDetails, quest);
if (teamToPlay) {
page.click('.btn--create-team')[0];
} else {
throw new Error('Team Selection error');
}
await page.waitForTimeout(5000);
try {
await page.waitForXPath(`//div[@card_detail_id="${teamToPlay.summoner}"]`, { timeout: 10000 })
.then(summonerButton => summonerButton.click())
.catch(async ()=>{
console.log(teamToPlay.summoner,'divId not found, reload and try again')
page.reload();
await page.waitForTimeout(2000);
page.waitForXPath(`//div[@card_detail_id="${teamToPlay.summoner}"]`, { timeout: 10000 }).then(summonerButton => summonerButton.click())
});
if (card.color(teamToPlay.cards[0]) === 'Gold') {
console.log('Dragon play TEAMCOLOR', teamActualSplinterToPlay(teamToPlay.cards.slice(0, 6)))
await page.waitForXPath(`//div[@data-original-title="${teamActualSplinterToPlay(teamToPlay.cards.slice(0, 6))}"]`, { timeout: 8000 })
.then(selector => selector.click())
}
await page.waitForTimeout(5000);
for (i = 1; i <= 6; i++) {
console.log('play: ', teamToPlay.cards[i].toString())
await teamToPlay.cards[i] ? page.waitForXPath(`//div[@card_detail_id="${teamToPlay.cards[i].toString()}"]`, { timeout: 10000 })
.then(selector => selector.click()) : console.log('nocard ', i);
await page.waitForTimeout(1000);
}
await page.waitForTimeout(5000);
try {
await page.click('.btn-green')[0]; //start fight
} catch {
console.log('Start Fight didnt work, waiting 5 sec and retry');
await page.waitForTimeout(5000);
await page.click('.btn-green')[0]; //start fight
}
await page.waitForTimeout(5000);
await page.waitForSelector('#btnRumble', { timeout: 90000 }).then(()=>console.log('btnRumble visible')).catch(()=>console.log('btnRumble not visible'));
await page.waitForTimeout(5000);
await page.$eval('#btnRumble', elem => elem.click()).then(()=>console.log('btnRumble clicked')).catch(()=>console.log('btnRumble didnt click')); //start rumble
await page.waitForSelector('#btnSkip', { timeout: 10000 }).then(()=>console.log('btnSkip visible')).catch(()=>console.log('btnSkip not visible'));
await page.$eval('#btnSkip', elem => elem.click()).then(()=>console.log('btnSkip clicked')).catch(()=>console.log('btnSkip not visible')); //skip rumble
await page.waitForTimeout(5000);
try {
const winner = await getElementText(page, 'section.player.winner .bio__name__display', 15000);
if (winner.trim() == process.env.ACCOUNT.split('@')[0]) {
const decWon = await getElementText(page, '.player.winner span.dec-reward span', 1000);
console.log(chalk.green('You won! Reward: ' + decWon + ' DEC'));
}
else {
console.log(chalk.red('You lost'));
}
} catch {
console.log('Could not find winner - draw?');
}
await clickOnElement(page, '.btn--done', 20000, 10000);
} catch (e) {
throw new Error(e);
}
}
// 30 MINUTES INTERVAL BETWEEN EACH MATCH (if not specified in the .env file)
const sleepingTimeInMinutes = process.env.MINUTES_BATTLES_INTERVAL || 30;
const sleepingTime = sleepingTimeInMinutes * 60000;
const isHeadlessMode = process.env.HEADLESS === 'false' ? false : true;
(async () => {
while (true) {
console.log(chalk.bold.redBright.bgBlack('Dont pay scammers!'));
console.log(chalk.bold.whiteBright.bgBlack('If you need support for the bot, join the telegram group https://t.me/splinterlandsbot and discord https://discord.gg/bR6cZDsFSX'));
console.log(chalk.bold.greenBright.bgBlack('If you interested in a higher winning rate with the private API, contact the owner via discord or telegram'));
try {
console.log('START ', process.env.ACCOUNT, new Date().toLocaleString())
const browser = await puppeteer.launch({
headless: isHeadlessMode,
args: ['--no-sandbox']
}); // default is true
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(500000);
await page.on('dialog', async dialog => {
await dialog.accept();
});
page.goto('https://splinterlands.io/');
console.log('getting user cards collection from splinterlands API...')
const myCards = await getCards()
.then((x)=>{console.log('cards retrieved'); return x})
.catch(()=>console.log('cards collection api didnt respond. Did you use username? avoid email!'));
console.log('getting user quest info from splinterlands API...')
const quest = await getQuest();
if(!quest) {
console.log('Error for quest details. Splinterlands API didnt work or you used incorrect username, remove @ and dont use email')
}
await startBotPlayMatch(page, myCards, quest)
.then(() => {
console.log('Closing battle', new Date().toLocaleString());
})
.catch((e) => {
console.log(e)
})
await page.waitForTimeout(5000);
await browser.close();
} catch (e) {
console.log('Routine error at: ', new Date().toLocaleString(), e)
}
await console.log(process.env.ACCOUNT,'waiting for the next battle in', sleepingTime / 1000 / 60 , ' minutes at ', new Date(Date.now() +sleepingTime).toLocaleString() )
await new Promise(r => setTimeout(r, sleepingTime));
}
})();