yolkbot 0.1.0-alpha.6 → 0.1.0-alpha.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/browser.js +6 -6
- package/package.json +15 -5
- package/src/api.js +97 -23
- package/src/bot/GamePlayer.js +3 -3
- package/src/bot.js +851 -484
- package/src/constants/index.js +23 -1
- package/src/constants/items.js +372 -173
- package/src/constants/maps.js +51 -12
- package/src/dispatches/BootPlayerDispatch.js +1 -1
- package/src/dispatches/ChatDispatch.js +1 -1
- package/src/dispatches/GameOptionsDispatch.js +1 -1
- package/src/dispatches/GoToAmmoDispatch.js +44 -0
- package/src/dispatches/GoToCoopDispatch.js +44 -0
- package/src/dispatches/GoToGrenadeDispatch.js +44 -0
- package/src/dispatches/GoToPlayerDispatch.js +5 -1
- package/src/dispatches/GoToSpatulaDispatch.js +5 -1
- package/src/dispatches/MeleeDispatch.js +1 -1
- package/src/dispatches/PauseDispatch.js +1 -1
- package/src/dispatches/ReloadDispatch.js +14 -2
- package/src/dispatches/ReportPlayerDispatch.js +1 -1
- package/src/dispatches/SaveLoadoutDispatch.js +11 -34
- package/src/dispatches/SpawnDispatch.js +1 -1
- package/src/dispatches/SwapWeaponDispatch.js +1 -1
- package/src/dispatches/SwitchTeamDispatch.js +1 -1
- package/src/dispatches/ThrowGrenadeDispatch.js +1 -1
- package/src/dispatches/index.js +9 -0
- package/src/matchmaker.js +11 -2
- package/src/pathing/mapnode.js +83 -250
- package/src/socket.js +1 -1
- package/src/types/api.d.ts +2 -16
- package/src/types/bot/GamePlayer.d.ts +26 -22
- package/src/types/bot.d.ts +118 -30
- package/src/types/constants/guns.d.ts +240 -0
- package/src/types/constants/index.d.ts +100 -0
- package/src/types/constants/items.d.ts +21 -0
- package/src/types/constants/maps.d.ts +15 -0
- package/src/types/dispatches/BootPlayerDispatch.d.ts +4 -2
- package/src/types/dispatches/ChatDispatch.d.ts +1 -1
- package/src/types/dispatches/FireDispatch.d.ts +2 -0
- package/src/types/dispatches/GameOptionsDispatch.d.ts +1 -1
- package/src/types/dispatches/GoToAmmoDispatch.d.ts +8 -0
- package/src/types/dispatches/GoToCoopDispatch.d.ts +8 -0
- package/src/types/dispatches/GoToGrenadeDispatch.d.ts +8 -0
- package/src/types/dispatches/GoToPlayerDispatch.d.ts +2 -1
- package/src/types/dispatches/GoToSpatulaDispatch.d.ts +1 -1
- package/src/types/dispatches/LookAtPosDispatch.d.ts +2 -0
- package/src/types/dispatches/MeleeDispatch.d.ts +2 -0
- package/src/types/dispatches/MovementDispatch.d.ts +2 -0
- package/src/types/dispatches/PauseDispatch.d.ts +2 -0
- package/src/types/dispatches/ReloadDispatch.d.ts +2 -0
- package/src/types/dispatches/ReportPlayerDispatch.d.ts +10 -1
- package/src/types/dispatches/SaveLoadoutDispatch.d.ts +2 -0
- package/src/types/dispatches/SpawnDispatch.d.ts +2 -0
- package/src/types/dispatches/SwapWeaponDispatch.d.ts +2 -0
- package/src/types/dispatches/SwitchTeamDispatch.d.ts +2 -0
- package/src/types/dispatches/ThrowGrenadeDispatch.d.ts +3 -0
- package/src/types/dispatches/index.d.ts +45 -1
- package/src/types/matchmaker.d.ts +19 -14
- package/src/types/socket.d.ts +7 -0
package/src/bot.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loginAnonymously, loginWithCredentials } from '#api';
|
|
1
|
+
import { createAccount, loginAnonymously, loginWithCredentials, loginWithRefreshToken, queryServices } from '#api';
|
|
2
2
|
|
|
3
3
|
import CommIn from './comm/CommIn.js';
|
|
4
4
|
import CommOut from './comm/CommOut.js';
|
|
@@ -9,6 +9,7 @@ import Matchmaker from './matchmaker.js';
|
|
|
9
9
|
import yolkws from './socket.js';
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
+
ChiknWinnerDailyLimit,
|
|
12
13
|
CollectTypes,
|
|
13
14
|
CoopStates,
|
|
14
15
|
findItemById,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
GameOptionFlags,
|
|
18
19
|
GunList,
|
|
19
20
|
IsBrowser,
|
|
21
|
+
ItemTypes,
|
|
20
22
|
Movements,
|
|
21
23
|
PlayTypes,
|
|
22
24
|
ShellStreaks
|
|
@@ -32,30 +34,31 @@ import { Maps } from './constants/maps.js';
|
|
|
32
34
|
const CoopStagesById = Object.fromEntries(Object.entries(CoopStates).map(([key, value]) => [value, key]));
|
|
33
35
|
const GameModesById = Object.fromEntries(Object.entries(GameModes).map(([key, value]) => [value, key]));
|
|
34
36
|
|
|
37
|
+
const intents = {
|
|
38
|
+
CHALLENGES: 1,
|
|
39
|
+
STATS: 2,
|
|
40
|
+
PATHFINDING: 3,
|
|
41
|
+
BUFFERS: 4,
|
|
42
|
+
PING: 5,
|
|
43
|
+
COSMETIC_DATA: 6,
|
|
44
|
+
PLAYER_HEALTH: 7
|
|
45
|
+
}
|
|
46
|
+
|
|
35
47
|
export class Bot {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// params.updateInterval - the auto update interval
|
|
40
|
-
// params.doPing - whether to auto ping (for bot.<ping>)
|
|
41
|
-
// params.pingInterval - the ping interval
|
|
42
|
-
// params.doPathing - whether to run pathfinding logic
|
|
43
|
-
// params.instance - a custom shell URL to run requests through
|
|
48
|
+
static Intents = intents;
|
|
49
|
+
Intents = intents;
|
|
50
|
+
|
|
44
51
|
constructor(params = {}) {
|
|
45
52
|
if (params.proxy && IsBrowser)
|
|
46
53
|
throw new Error('proxies do not work and hence are not supported in the browser');
|
|
47
54
|
|
|
55
|
+
this.intents = params.intents || [];
|
|
56
|
+
|
|
57
|
+
this.instance = params.instance || 'shellshock.io';
|
|
48
58
|
this.proxy = params.proxy || '';
|
|
49
|
-
this.name = params.name || Math.random().toString(36).substring(8);
|
|
50
59
|
|
|
51
|
-
this.autoPing = params.doPing || true;
|
|
52
60
|
this.autoUpdate = params.doUpdate || true;
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
this.pingInterval = params.pingInterval || 1000;
|
|
56
|
-
this.updateInterval = params.updateInterval || 5;
|
|
57
|
-
|
|
58
|
-
this.instance = params.instance || 'shellshock.io';
|
|
61
|
+
this.updateInterval = params.updateInterval || 16.5;
|
|
59
62
|
|
|
60
63
|
this._hooks = {};
|
|
61
64
|
this._globalHooks = [];
|
|
@@ -63,10 +66,10 @@ export class Bot {
|
|
|
63
66
|
|
|
64
67
|
// private information NOT FOR OTHER PLAYERS!!
|
|
65
68
|
this.state = {
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
// kept for specifying socket open sequence
|
|
70
|
+
name: '',
|
|
68
71
|
|
|
69
|
-
//
|
|
72
|
+
// tracking for dispatch checks
|
|
70
73
|
reloading: false,
|
|
71
74
|
swappingGun: false,
|
|
72
75
|
usingMelee: false,
|
|
@@ -81,6 +84,7 @@ export class Bot {
|
|
|
81
84
|
this.game = {
|
|
82
85
|
raw: {}, // matchmaker response
|
|
83
86
|
code: '',
|
|
87
|
+
socket: null,
|
|
84
88
|
|
|
85
89
|
// data given on sign in
|
|
86
90
|
gameModeId: 0, // assume ffa
|
|
@@ -98,8 +102,10 @@ export class Bot {
|
|
|
98
102
|
},
|
|
99
103
|
availability: 'both',
|
|
100
104
|
numPlayers: '18',
|
|
105
|
+
|
|
101
106
|
raw: {},
|
|
102
|
-
nodes: {}
|
|
107
|
+
nodes: {},
|
|
108
|
+
zones: []
|
|
103
109
|
},
|
|
104
110
|
playerLimit: 0,
|
|
105
111
|
isGameOwner: false,
|
|
@@ -135,7 +141,8 @@ export class Bot {
|
|
|
135
141
|
|
|
136
142
|
// data from kotc
|
|
137
143
|
stage: CoopStates.capturing,
|
|
138
|
-
|
|
144
|
+
zoneNumber: 0,
|
|
145
|
+
activeZone: [],
|
|
139
146
|
capturing: 0,
|
|
140
147
|
captureProgress: 0,
|
|
141
148
|
numCapturing: 0,
|
|
@@ -145,10 +152,23 @@ export class Bot {
|
|
|
145
152
|
|
|
146
153
|
this.account = {
|
|
147
154
|
// used for auth
|
|
155
|
+
id: 0,
|
|
148
156
|
firebaseId: '',
|
|
149
157
|
sessionId: '',
|
|
150
158
|
session: '',
|
|
151
159
|
|
|
160
|
+
// raw login params
|
|
161
|
+
email: '',
|
|
162
|
+
password: '',
|
|
163
|
+
|
|
164
|
+
// chikn winner related info
|
|
165
|
+
cw: {
|
|
166
|
+
atLimit: false,
|
|
167
|
+
limit: 0,
|
|
168
|
+
secondsUntilPlay: 0, // short cooldown, in seconds
|
|
169
|
+
canPlayAgain: Date.now()
|
|
170
|
+
},
|
|
171
|
+
|
|
152
172
|
// used for skin changing
|
|
153
173
|
loadout: {
|
|
154
174
|
hatId: null,
|
|
@@ -184,21 +204,17 @@ export class Bot {
|
|
|
184
204
|
this._dispatches = [];
|
|
185
205
|
this._packetQueue = [];
|
|
186
206
|
|
|
187
|
-
this.
|
|
207
|
+
this.matchmaker = null;
|
|
188
208
|
|
|
189
209
|
this.ping = 0;
|
|
190
210
|
this.lastPingTime = -1;
|
|
191
211
|
|
|
192
212
|
this.lastDeathTime = -1;
|
|
193
213
|
this.lastChatTime = -1;
|
|
194
|
-
|
|
195
214
|
this.lastUpdateTime = -1;
|
|
196
|
-
this.nUpdates = 0;
|
|
197
215
|
|
|
198
216
|
this.controlKeys = 0;
|
|
199
217
|
|
|
200
|
-
this.initTime = Date.now();
|
|
201
|
-
|
|
202
218
|
this.pathing = {
|
|
203
219
|
nodeList: null,
|
|
204
220
|
followingPath: false,
|
|
@@ -206,70 +222,67 @@ export class Bot {
|
|
|
206
222
|
activeNode: null,
|
|
207
223
|
activeNodeIdx: 0
|
|
208
224
|
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async login(email, pass) {
|
|
212
|
-
// const time = Date.now();
|
|
213
|
-
|
|
214
|
-
this.email = email;
|
|
215
|
-
this.pass = pass;
|
|
216
225
|
|
|
217
|
-
|
|
226
|
+
if (this.intents.includes(this.Intents.PLAYER_HEALTH)) this.healthIntervalId = setInterval(() => {
|
|
227
|
+
if (!this.players) return;
|
|
218
228
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
229
|
+
for (const player of Object.values(this.players)) {
|
|
230
|
+
if (player.playing && player.hp > 0) {
|
|
231
|
+
const regenSpeed = 0.1 * (this.game.isPrivate ? this.game.options.healthRegen : 1);
|
|
223
232
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
233
|
+
if (player.streakRewards.includes(ShellStreaks.OverHeal)) {
|
|
234
|
+
player.hp = Math.max(100, player.hp - regenSpeed);
|
|
235
|
+
} else {
|
|
236
|
+
player.hp = Math.min(100, player.hp + regenSpeed);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}, 33);
|
|
241
|
+
}
|
|
228
242
|
|
|
229
|
-
|
|
243
|
+
dispatch(disp) {
|
|
244
|
+
this._dispatches.push(disp);
|
|
245
|
+
}
|
|
230
246
|
|
|
231
|
-
|
|
247
|
+
async createAccount(email, pass) {
|
|
248
|
+
this.account.email = email;
|
|
249
|
+
this.account.password = pass;
|
|
232
250
|
|
|
233
|
-
|
|
234
|
-
this
|
|
235
|
-
|
|
236
|
-
this.account.firebaseId = loginData.firebaseId;
|
|
237
|
-
this.account.loadout = loginData.loadout;
|
|
238
|
-
this.account.ownedItemIds = loginData.ownedItemIds;
|
|
239
|
-
this.account.sessionId = loginData.sessionId;
|
|
240
|
-
this.account.vip = loginData.upgradeProductId && !loginData.upgradeIsExpired;
|
|
251
|
+
const loginData = await createAccount(email, pass, this.proxy, this.instance);
|
|
252
|
+
return this.#processLoginData(loginData);
|
|
253
|
+
}
|
|
241
254
|
|
|
242
|
-
|
|
255
|
+
async login(email, pass) {
|
|
256
|
+
this.account.email = email;
|
|
257
|
+
this.account.password = pass;
|
|
243
258
|
|
|
244
|
-
|
|
259
|
+
const loginData = await loginWithCredentials(email, pass, this.proxy, this.instance);
|
|
260
|
+
return this.#processLoginData(loginData);
|
|
245
261
|
}
|
|
246
262
|
|
|
247
|
-
|
|
248
|
-
this.
|
|
263
|
+
async loginWithRefreshToken(refreshToken) {
|
|
264
|
+
const loginData = await loginWithRefreshToken(refreshToken, this.proxy, this.instance);
|
|
265
|
+
return this.#processLoginData(loginData);
|
|
249
266
|
}
|
|
250
267
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (disp.check(this)) {
|
|
255
|
-
disp.execute(this);
|
|
256
|
-
this._dispatches.splice(i, 1);
|
|
257
|
-
return; // only 1 dispatch per update
|
|
258
|
-
} else {
|
|
259
|
-
// console.log("Dispatch failed", this.state.joinedGame, this.lastChatTime)
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
268
|
+
async loginAnonymously() {
|
|
269
|
+
delete this.account.email;
|
|
270
|
+
delete this.account.password;
|
|
263
271
|
|
|
264
|
-
async #anonLogin() {
|
|
265
272
|
const loginData = await loginAnonymously(this.proxy, this.instance);
|
|
273
|
+
return this.#processLoginData(loginData);
|
|
274
|
+
}
|
|
266
275
|
|
|
276
|
+
#processLoginData(loginData) {
|
|
267
277
|
if (typeof loginData == 'string') {
|
|
268
|
-
this
|
|
278
|
+
this.emit('authFail', loginData);
|
|
269
279
|
return false;
|
|
270
280
|
}
|
|
271
281
|
|
|
272
|
-
|
|
282
|
+
if (loginData.banRemaining) {
|
|
283
|
+
this.emit('banned', loginData.banRemaining);
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
273
286
|
|
|
274
287
|
this.account.rawLoginData = loginData;
|
|
275
288
|
|
|
@@ -277,19 +290,20 @@ export class Bot {
|
|
|
277
290
|
this.account.eggBalance = loginData.currentBalance;
|
|
278
291
|
this.account.emailVerified = loginData.emailVerified;
|
|
279
292
|
this.account.firebaseId = loginData.firebaseId;
|
|
293
|
+
this.account.id = loginData.id;
|
|
280
294
|
this.account.loadout = loginData.loadout;
|
|
281
295
|
this.account.ownedItemIds = loginData.ownedItemIds;
|
|
282
296
|
this.account.session = loginData.session;
|
|
283
297
|
this.account.sessionId = loginData.sessionId;
|
|
284
|
-
this.account.vip =
|
|
298
|
+
this.account.vip = loginData.upgradeProductId && !loginData.upgradeIsExpired;
|
|
285
299
|
|
|
286
300
|
return this.account;
|
|
287
301
|
}
|
|
288
302
|
|
|
289
303
|
async initMatchmaker() {
|
|
290
|
-
if (
|
|
304
|
+
if (this.account.id == 0) {
|
|
291
305
|
// console.log('Not logged in, attempting to create anonymous user...');
|
|
292
|
-
const anonLogin = await this
|
|
306
|
+
const anonLogin = await this.loginAnonymously();
|
|
293
307
|
if (!anonLogin) return false;
|
|
294
308
|
}
|
|
295
309
|
|
|
@@ -301,7 +315,7 @@ export class Bot {
|
|
|
301
315
|
instance: this.instance
|
|
302
316
|
});
|
|
303
317
|
|
|
304
|
-
this.matchmaker.on('authFail', (data) => this
|
|
318
|
+
this.matchmaker.on('authFail', (data) => this.emit('authFail', data));
|
|
305
319
|
|
|
306
320
|
await this.matchmaker.getRegions();
|
|
307
321
|
}
|
|
@@ -312,34 +326,33 @@ export class Bot {
|
|
|
312
326
|
async #joinGameWithCode(code) {
|
|
313
327
|
if (!await this.initMatchmaker()) return false;
|
|
314
328
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
delete this.game.raw.command; // pissed me off
|
|
329
|
+
return await new Promise((resolve) => {
|
|
330
|
+
const listener = (mes) => {
|
|
331
|
+
if (mes.command == 'gameFound') {
|
|
332
|
+
this.matchmaker.off('msg', listener);
|
|
320
333
|
|
|
321
|
-
|
|
322
|
-
|
|
334
|
+
this.game.raw = mes;
|
|
335
|
+
this.game.code = code;
|
|
323
336
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
this.matchmaker.on('msg', listener);
|
|
337
|
+
resolve();
|
|
338
|
+
}
|
|
329
339
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
observe: false,
|
|
334
|
-
sessionId: this.account.sessionId
|
|
335
|
-
})
|
|
340
|
+
if (mes.error && mes.error == 'gameNotFound')
|
|
341
|
+
throw new Error(`Game ${code} not found (likely expired).`)
|
|
342
|
+
};
|
|
336
343
|
|
|
337
|
-
|
|
344
|
+
this.matchmaker.on('msg', listener);
|
|
338
345
|
|
|
339
|
-
|
|
346
|
+
this.matchmaker.send({
|
|
347
|
+
command: 'joinGame',
|
|
348
|
+
id: code,
|
|
349
|
+
observe: false,
|
|
350
|
+
sessionId: this.account.sessionId
|
|
351
|
+
})
|
|
352
|
+
});
|
|
340
353
|
}
|
|
341
354
|
|
|
342
|
-
async #onGameMesssage(msg) {
|
|
355
|
+
async #onGameMesssage(msg) {
|
|
343
356
|
CommIn.init(msg.data);
|
|
344
357
|
|
|
345
358
|
let out;
|
|
@@ -350,7 +363,7 @@ export class Bot {
|
|
|
350
363
|
out = CommOut.getBuffer();
|
|
351
364
|
out.packInt8(CommCode.joinGame);
|
|
352
365
|
|
|
353
|
-
out.packString(this.name); // name
|
|
366
|
+
out.packString(this.state.name); // name
|
|
354
367
|
out.packString(this.game.raw.uuid); // game id
|
|
355
368
|
|
|
356
369
|
out.packInt8(0); // hidebadge
|
|
@@ -360,10 +373,10 @@ export class Bot {
|
|
|
360
373
|
out.packString(this.account.firebaseId); // firebase id
|
|
361
374
|
out.packString(this.account.sessionId); // session id
|
|
362
375
|
|
|
363
|
-
out.send(this.
|
|
376
|
+
out.send(this.game.socket);
|
|
364
377
|
break;
|
|
365
378
|
|
|
366
|
-
case CommCode.gameJoined:
|
|
379
|
+
case CommCode.gameJoined: {
|
|
367
380
|
this.me.id = CommIn.unPackInt8U();
|
|
368
381
|
// console.log("My id is:", this.me.id);
|
|
369
382
|
this.me.team = CommIn.unPackInt8U();
|
|
@@ -373,9 +386,10 @@ export class Bot {
|
|
|
373
386
|
// console.log("Gametype:", this.game.gameMode, this.game.gameModeId);
|
|
374
387
|
this.game.mapIdx = CommIn.unPackInt8U();
|
|
375
388
|
this.game.map = Maps[this.game.mapIdx];
|
|
376
|
-
if (
|
|
389
|
+
if (this.intents.includes(this.Intents.PATHFINDING)) {
|
|
377
390
|
this.game.map.raw = await this.#fetchMap(this.game.map.filename, this.game.map.hash);
|
|
378
391
|
this.pathing.nodeList = new NodeList(this.game.map.raw);
|
|
392
|
+
if (this.game.gameModeId === GameModes.kotc) this.#initKotcZones();
|
|
379
393
|
}
|
|
380
394
|
// console.log("Map:", this.game.map);
|
|
381
395
|
this.game.playerLimit = CommIn.unPackInt8U();
|
|
@@ -389,34 +403,34 @@ export class Bot {
|
|
|
389
403
|
this.state.joinedGame = true;
|
|
390
404
|
this.lastDeathTime = Date.now();
|
|
391
405
|
|
|
406
|
+
const out = CommOut.getBuffer();
|
|
407
|
+
out.packInt8(CommCode.clientReady);
|
|
408
|
+
out.send(this.game.socket);
|
|
409
|
+
|
|
410
|
+
this.game.socket.onmessage = (msg) => this._packetQueue.push(msg.data);
|
|
411
|
+
|
|
412
|
+
if (this.autoUpdate)
|
|
413
|
+
setInterval(() => this.update(), this.updateInterval);
|
|
414
|
+
|
|
415
|
+
if (this.intents.includes(this.Intents.PING)) {
|
|
416
|
+
const out = CommOut.getBuffer();
|
|
417
|
+
out.packInt8(CommCode.ping);
|
|
418
|
+
out.send(this.game.socket);
|
|
419
|
+
this.lastPingTime = Date.now();
|
|
420
|
+
}
|
|
392
421
|
break;
|
|
422
|
+
}
|
|
393
423
|
|
|
394
424
|
case CommCode.eventModifier:
|
|
395
425
|
// console.log("Echoed eventModifier"); // why the fuck do you need to do this
|
|
396
426
|
out = CommOut.getBuffer();
|
|
397
427
|
out.packInt8(CommCode.eventModifier);
|
|
398
|
-
out.send(this.
|
|
428
|
+
out.send(this.game.socket);
|
|
399
429
|
break;
|
|
400
430
|
|
|
401
|
-
case CommCode.requestGameOptions:
|
|
402
|
-
|
|
403
|
-
out.packInt8(CommCode.gameOptions);
|
|
404
|
-
out.packInt8(this.game.options.gravity * 4);
|
|
405
|
-
out.packInt8(this.game.options.damage * 4);
|
|
406
|
-
out.packInt8(this.game.options.healthRegen * 4);
|
|
407
|
-
|
|
408
|
-
const flags =
|
|
409
|
-
(this.game.options.locked ? 1 : 0) |
|
|
410
|
-
(this.game.options.noTeamChange ? 2 : 0) |
|
|
411
|
-
(this.game.options.noTeamShuffle ? 4 : 0);
|
|
412
|
-
|
|
413
|
-
out.packInt8(flags);
|
|
414
|
-
|
|
415
|
-
this.game.options.weaponsDisabled.forEach((v) => {
|
|
416
|
-
out.packInt8(v ? 1 : 0);
|
|
417
|
-
});
|
|
431
|
+
case CommCode.requestGameOptions:
|
|
432
|
+
this.#processGameRequestOptionsPacket();
|
|
418
433
|
break;
|
|
419
|
-
}
|
|
420
434
|
|
|
421
435
|
default:
|
|
422
436
|
try {
|
|
@@ -449,52 +463,50 @@ export class Bot {
|
|
|
449
463
|
|
|
450
464
|
if (mapIdx == -1) throw new Error('invalid map, see the Maps constant for a list')
|
|
451
465
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
delete this.game.raw.command;
|
|
457
|
-
|
|
458
|
-
this.gameFound = true;
|
|
459
|
-
}
|
|
460
|
-
};
|
|
466
|
+
await new Promise((resolve) => {
|
|
467
|
+
const listener = (msg) => {
|
|
468
|
+
if (msg.command == 'gameFound') {
|
|
469
|
+
this.matchmaker.off('msg', listener);
|
|
461
470
|
|
|
462
|
-
|
|
471
|
+
this.game.raw = msg;
|
|
472
|
+
this.game.code = this.game.raw.id;
|
|
463
473
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
playType: PlayTypes.createPrivate,
|
|
468
|
-
gameType: GameModes[opts.mode],
|
|
469
|
-
sessionId: this.account.sessionId,
|
|
470
|
-
noobLobby: false,
|
|
471
|
-
map: mapIdx
|
|
472
|
-
});
|
|
474
|
+
resolve();
|
|
475
|
+
}
|
|
476
|
+
};
|
|
473
477
|
|
|
474
|
-
|
|
478
|
+
this.matchmaker.on('msg', listener);
|
|
475
479
|
|
|
476
|
-
|
|
480
|
+
this.matchmaker.send({
|
|
481
|
+
command: 'findGame',
|
|
482
|
+
region: opts.region,
|
|
483
|
+
playType: PlayTypes.createPrivate,
|
|
484
|
+
gameType: GameModes[opts.mode],
|
|
485
|
+
sessionId: this.account.sessionId,
|
|
486
|
+
noobLobby: false,
|
|
487
|
+
map: mapIdx
|
|
488
|
+
});
|
|
489
|
+
});
|
|
477
490
|
|
|
478
491
|
return this.game.raw;
|
|
479
492
|
}
|
|
480
493
|
|
|
481
|
-
async join(data) {
|
|
494
|
+
async join(name, data) {
|
|
495
|
+
this.state.name = name || 'yolkbot';
|
|
496
|
+
|
|
482
497
|
if (typeof data == 'string') {
|
|
483
498
|
if (data.includes('#')) data = data.split('#')[1]; // stupid shell kids put in full links
|
|
484
499
|
// this is a string code that we can pass and get the needed info from
|
|
485
500
|
await this.#joinGameWithCode(data);
|
|
486
501
|
} else if (typeof data == 'object') {
|
|
487
|
-
if (
|
|
502
|
+
if (this.account.id == 0) {
|
|
488
503
|
// console.log('passed an object but you still need to be logged in!!')
|
|
489
|
-
await this
|
|
504
|
+
await this.loginAnonymously();
|
|
490
505
|
}
|
|
491
506
|
|
|
492
507
|
// this is a game object that we can pass and get the needed info from
|
|
493
508
|
this.game.raw = data;
|
|
494
509
|
this.game.code = this.game.raw.id;
|
|
495
|
-
delete this.game.raw.command;
|
|
496
|
-
|
|
497
|
-
this.gameFound = true;
|
|
498
510
|
}
|
|
499
511
|
|
|
500
512
|
if (!this.game.raw.id || !this.game.raw.subdomain)
|
|
@@ -502,115 +514,115 @@ export class Bot {
|
|
|
502
514
|
|
|
503
515
|
// console.log(`Joining ${this.game.raw.id} using proxy ${this.proxy || 'none'}`);
|
|
504
516
|
|
|
505
|
-
|
|
517
|
+
const attempt = async () => {
|
|
518
|
+
try {
|
|
519
|
+
this.game.socket = new yolkws(`wss://${this.game.raw.subdomain}.${this.instance}/game/${this.game.raw.id}`, this.proxy);
|
|
520
|
+
} catch {
|
|
521
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
522
|
+
await attempt();
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
await attempt();
|
|
506
527
|
|
|
507
|
-
this.
|
|
528
|
+
this.game.socket.binaryType = 'arraybuffer';
|
|
508
529
|
|
|
509
|
-
this.
|
|
530
|
+
this.game.socket.onopen = () => {
|
|
510
531
|
// console.log('Successfully connected to game server.');
|
|
511
532
|
}
|
|
512
533
|
|
|
513
|
-
this.
|
|
534
|
+
this.game.socket.onmessage = this.#onGameMesssage.bind(this);
|
|
514
535
|
|
|
515
|
-
this.
|
|
536
|
+
this.game.socket.onclose = (e) => {
|
|
516
537
|
// console.log('Game socket closed:', e.code, Object.entries(CloseCode).filter(([, v]) => v == e.code));
|
|
517
|
-
this
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
while (!this.state.joinedGame) await new Promise(r => setTimeout(r, 5));
|
|
521
|
-
|
|
522
|
-
const out = CommOut.getBuffer();
|
|
523
|
-
out.packInt8(CommCode.clientReady);
|
|
524
|
-
out.send(this.gameSocket);
|
|
525
|
-
|
|
526
|
-
this.gameSocket.onmessage = (msg) => this._packetQueue.push(msg.data);
|
|
527
|
-
|
|
528
|
-
// console.log(`Successfully joined ${this.game.code}. Startup to join time: ${Date.now() - this.initTime} ms`);
|
|
529
|
-
|
|
530
|
-
if (this.autoUpdate)
|
|
531
|
-
setInterval(() => this.update(), this.updateInterval);
|
|
532
|
-
|
|
533
|
-
if (this.autoPing) {
|
|
534
|
-
const out = CommOut.getBuffer();
|
|
535
|
-
out.packInt8(CommCode.ping);
|
|
536
|
-
out.send(this.gameSocket);
|
|
537
|
-
this.lastPingTime = Date.now();
|
|
538
|
+
this.emit('close', e.code);
|
|
538
539
|
}
|
|
539
540
|
}
|
|
540
541
|
|
|
541
|
-
|
|
542
|
-
|
|
542
|
+
#processPathfinding() {
|
|
543
|
+
const myPositionStr = Object.entries(this.me.position).map(entry => Math.floor(entry[1])).join(',');
|
|
543
544
|
|
|
544
|
-
this.
|
|
545
|
+
if (myPositionStr == this.pathing.activePath[this.pathing.activePath.length - 1].positionStr()) {
|
|
546
|
+
// console.log('Completed path to', this.pathing.activePath[this.pathing.activePath.length - 1].position);
|
|
547
|
+
this.pathing.followingPath = false;
|
|
548
|
+
this.pathing.activePath = null;
|
|
549
|
+
this.pathing.activeNode = null;
|
|
550
|
+
this.pathing.activeNodeIdx = 0;
|
|
545
551
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
if (this.pathing.followingPath && !this.disablePathing) {
|
|
554
|
-
const myPositionStr = Object.entries(this.me.position).map(entry => Math.floor(entry[1])).join(',');
|
|
555
|
-
|
|
556
|
-
if (myPositionStr == this.pathing.activePath[this.pathing.activePath.length - 1].positionStr()) {
|
|
557
|
-
// console.log('Completed path to', this.pathing.activePath[this.pathing.activePath.length - 1].position);
|
|
558
|
-
this.pathing.followingPath = false;
|
|
559
|
-
this.pathing.activePath = null;
|
|
560
|
-
this.pathing.activeNode = null;
|
|
561
|
-
this.pathing.activeNodeIdx = 0;
|
|
562
|
-
|
|
563
|
-
this.dispatch(new MovementDispatch(0));
|
|
552
|
+
this.dispatch(new MovementDispatch(0));
|
|
553
|
+
} else {
|
|
554
|
+
let positionTarget;
|
|
555
|
+
if (this.pathing.activeNodeIdx < this.pathing.activePath.length - 1) {
|
|
556
|
+
positionTarget = this.pathing.activePath[this.pathing.activeNodeIdx + 1].flatCenter();
|
|
557
|
+
this.dispatch(new LookAtPosDispatch(positionTarget));
|
|
564
558
|
} else {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
this.dispatch(new LookAtPosDispatch(positionTarget));
|
|
569
|
-
} else {
|
|
570
|
-
positionTarget = this.pathing.activePath[this.pathing.activeNodeIdx].flatCenter();
|
|
571
|
-
this.dispatch(new LookAtPosDispatch(positionTarget));
|
|
572
|
-
}
|
|
559
|
+
positionTarget = this.pathing.activePath[this.pathing.activeNodeIdx].flatCenter();
|
|
560
|
+
this.dispatch(new LookAtPosDispatch(positionTarget));
|
|
561
|
+
}
|
|
573
562
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
} else {
|
|
581
|
-
// console.log('Close to node that\'s before, idx:',
|
|
582
|
-
// this.pathing.activePath.indexOf(node), 'current:', this.pathing.activeNodeIdx);
|
|
583
|
-
}
|
|
563
|
+
for (const node of this.pathing.activePath) {
|
|
564
|
+
if (node.flatRadialDistance(this.me.position) < 0.1 && node.position.y == Math.floor(this.me.position.y)) {
|
|
565
|
+
if (this.pathing.activePath.indexOf(node) >= this.pathing.activeNodeIdx) {
|
|
566
|
+
this.pathing.activeNodeIdx = this.pathing.activePath.indexOf(node) + 1;
|
|
567
|
+
this.pathing.activeNode = this.pathing.activePath[this.pathing.activeNodeIdx];
|
|
568
|
+
break;
|
|
584
569
|
} else {
|
|
585
|
-
// console.log('
|
|
570
|
+
// console.log('Close to node that\'s before, idx:',
|
|
571
|
+
// this.pathing.activePath.indexOf(node), 'current:', this.pathing.activeNodeIdx);
|
|
586
572
|
}
|
|
587
|
-
|
|
573
|
+
} else {
|
|
574
|
+
// console.log('Node at', node.position, 'is', node.flatRadialDistance(this.me.position), 'away.')
|
|
588
575
|
}
|
|
576
|
+
// console.log('activeNode is ', this.pathing.activeNode.flatRadialDistance(this.me.position), 'away');
|
|
577
|
+
}
|
|
589
578
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
}
|
|
579
|
+
if (!(this.controlKeys & Movements.FORWARD)) {
|
|
580
|
+
this.dispatch(new MovementDispatch(Movements.FORWARD));
|
|
593
581
|
}
|
|
582
|
+
}
|
|
594
583
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
584
|
+
/*let onPath = false;
|
|
585
|
+
for (const node of this.pathing.activePath) {
|
|
586
|
+
if (node.positionStr() == myPositionStr) {
|
|
587
|
+
onPath = true;
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
if (!onPath) {
|
|
592
|
+
console.log('Got off-path somehow');
|
|
593
|
+
this.dispatch(new PathfindDispatch(this.pathing.activePath[this.pathing.activePath.length - 1]));
|
|
594
|
+
this.pathing.followingPath = false;
|
|
595
|
+
this.pathing.activePath = null;
|
|
596
|
+
this.pathing.activeNode = null;
|
|
597
|
+
this.pathing.activeNodeIdx = 0;
|
|
598
|
+
}*/
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
update() {
|
|
602
|
+
if (!this.state.joinedGame) throw new Error('Not playing, can\'t update. ');
|
|
603
|
+
|
|
604
|
+
// process pathfinding
|
|
605
|
+
if (this.pathing.followingPath && this.intents.includes(this.Intents.PATHFINDING)) this.#processPathfinding();
|
|
606
|
+
|
|
607
|
+
// process incoming packets
|
|
608
|
+
while (this._packetQueue.length > 0) this.#handlePacket(this._packetQueue.shift());
|
|
609
|
+
|
|
610
|
+
// process dispatches
|
|
611
|
+
if (this._dispatches.length > 0) {
|
|
612
|
+
for (let i = 0; i < this._dispatches.length; i++) {
|
|
613
|
+
const disp = this._dispatches[i];
|
|
614
|
+
if (disp.check(this)) {
|
|
615
|
+
disp.execute(this);
|
|
616
|
+
this._dispatches.splice(i, 1);
|
|
617
|
+
break; // only 1 dispatch per update
|
|
600
618
|
}
|
|
601
619
|
}
|
|
602
|
-
if (!onPath) {
|
|
603
|
-
console.log('Got off-path somehow');
|
|
604
|
-
this.dispatch(new PathfindDispatch(this.pathing.activePath[this.pathing.activePath.length - 1]));
|
|
605
|
-
this.pathing.followingPath = false;
|
|
606
|
-
this.pathing.activePath = null;
|
|
607
|
-
this.pathing.activeNode = null;
|
|
608
|
-
this.pathing.activeNodeIdx = 0;
|
|
609
|
-
}*/
|
|
610
620
|
}
|
|
611
621
|
|
|
612
|
-
|
|
613
|
-
|
|
622
|
+
// process syncMe
|
|
623
|
+
const now = Date.now();
|
|
624
|
+
if (now - this.lastUpdateTime >= 50) {
|
|
625
|
+
this.emit('tick');
|
|
614
626
|
|
|
615
627
|
// Send out update packet
|
|
616
628
|
const out = CommOut.getBuffer();
|
|
@@ -624,14 +636,16 @@ export class Bot {
|
|
|
624
636
|
out.packRad(this.me.view.pitch); // pitch
|
|
625
637
|
out.packInt8(100); // fixes commcode issues, does nothing
|
|
626
638
|
}
|
|
627
|
-
out.send(this.
|
|
639
|
+
out.send(this.game.socket);
|
|
628
640
|
|
|
629
|
-
this.lastUpdateTime =
|
|
641
|
+
this.lastUpdateTime = now;
|
|
630
642
|
this.state.shotsFired = 0;
|
|
631
643
|
}
|
|
632
644
|
|
|
633
|
-
|
|
634
|
-
|
|
645
|
+
while (this._liveCallbacks.length > 0) {
|
|
646
|
+
const cb = this._liveCallbacks.shift();
|
|
647
|
+
cb();
|
|
648
|
+
}
|
|
635
649
|
}
|
|
636
650
|
|
|
637
651
|
on(event, cb) {
|
|
@@ -646,7 +660,7 @@ export class Bot {
|
|
|
646
660
|
// these are auth-related codes (liveCallbacks doesn't run during auth)
|
|
647
661
|
#mustBeInstant = ['authFail', 'banned'];
|
|
648
662
|
|
|
649
|
-
|
|
663
|
+
emit(event, ...args) {
|
|
650
664
|
if (this._hooks[event]) {
|
|
651
665
|
for (const cb of this._hooks[event]) {
|
|
652
666
|
if (this.#mustBeInstant.includes(event)) cb(...args);
|
|
@@ -664,23 +678,25 @@ export class Bot {
|
|
|
664
678
|
if (!IsBrowser) {
|
|
665
679
|
const { existsSync, mkdirSync, readFileSync, writeFileSync } = await import('node:fs');
|
|
666
680
|
const { join } = await import('node:path');
|
|
681
|
+
const { homedir } = await import('node:os');
|
|
667
682
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
683
|
+
const yolkbotCache = join(homedir(), '.yolkbot');
|
|
684
|
+
const mapCache = join(yolkbotCache, 'maps');
|
|
685
|
+
|
|
686
|
+
if (!existsSync(yolkbotCache)) mkdirSync(yolkbotCache);
|
|
687
|
+
if (!existsSync(mapCache)) mkdirSync(mapCache);
|
|
688
|
+
|
|
689
|
+
const mapFile = join(mapCache, `${name}-${hash}.json`);
|
|
671
690
|
|
|
672
|
-
|
|
691
|
+
if (existsSync(mapFile))
|
|
692
|
+
return JSON.parse(readFileSync(mapFile, 'utf-8'));
|
|
693
|
+
|
|
694
|
+
console.log('map not in cache, IMPORT!!', name, hash);
|
|
673
695
|
|
|
674
696
|
const data = await (await fetch(`https://${this.instance}/maps/${name}.json?${hash}`)).json();
|
|
675
697
|
|
|
676
|
-
|
|
677
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
698
|
+
writeFileSync(mapFile, JSON.stringify(data, null, 4), { flag: 'w+' });
|
|
678
699
|
|
|
679
|
-
writeFileSync(
|
|
680
|
-
join(dir, `${name}-${hash}.json`),
|
|
681
|
-
JSON.stringify(data, null, 4),
|
|
682
|
-
{ flag: 'w+' }
|
|
683
|
-
);
|
|
684
700
|
return data;
|
|
685
701
|
} else {
|
|
686
702
|
const data = await (await fetch(`https://${this.instance}/maps/${name}.json?${hash}`)).json();
|
|
@@ -688,6 +704,64 @@ export class Bot {
|
|
|
688
704
|
}
|
|
689
705
|
}
|
|
690
706
|
|
|
707
|
+
#initKotcZones() {
|
|
708
|
+
const meshData = this.game.map.raw.data['DYNAMIC.capture-zone.none'];
|
|
709
|
+
if (!meshData) return delete this.game.map.zones;
|
|
710
|
+
|
|
711
|
+
let numCaptureZones = 0;
|
|
712
|
+
const mapData = {};
|
|
713
|
+
const zones = [];
|
|
714
|
+
|
|
715
|
+
for (const cell of meshData) {
|
|
716
|
+
if (!mapData[cell.x]) mapData[cell.x] = {};
|
|
717
|
+
if (!mapData[cell.x][cell.y]) mapData[cell.x][cell.y] = {};
|
|
718
|
+
mapData[cell.x][cell.y][cell.z] = { zone: null };
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
const offsets = [
|
|
722
|
+
{ x: -1, z: 0 },
|
|
723
|
+
{ x: 1, z: 0 },
|
|
724
|
+
{ x: 0, z: -1 },
|
|
725
|
+
{ x: 0, z: 1 }
|
|
726
|
+
];
|
|
727
|
+
|
|
728
|
+
function getMapCellAt(x, y, z) {
|
|
729
|
+
return mapData[x] && mapData[x][y] && mapData[x][y][z] ? mapData[x][y][z] : null;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
for (const cellA of meshData) {
|
|
733
|
+
if (!mapData[cellA.x][cellA.y][cellA.z].zone) {
|
|
734
|
+
cellA.zone = ++numCaptureZones;
|
|
735
|
+
mapData[cellA.x][cellA.y][cellA.z].zone = cellA.zone;
|
|
736
|
+
|
|
737
|
+
const currentZone = [cellA];
|
|
738
|
+
let hits;
|
|
739
|
+
|
|
740
|
+
do {
|
|
741
|
+
hits = 0;
|
|
742
|
+
for (const cellB of meshData) {
|
|
743
|
+
if (!mapData[cellB.x][cellB.y][cellB.z].zone) {
|
|
744
|
+
for (const o of offsets) {
|
|
745
|
+
const cell = getMapCellAt(cellB.x + o.x, cellB.y, cellB.z + o.z);
|
|
746
|
+
if (cell && cell.zone == cellA.zone) {
|
|
747
|
+
hits++;
|
|
748
|
+
cellB.zone = cellA.zone;
|
|
749
|
+
mapData[cellB.x][cellB.y][cellB.z].zone = cellA.zone;
|
|
750
|
+
currentZone.push(cellB);
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
} while (hits > 0);
|
|
757
|
+
|
|
758
|
+
zones.push(currentZone);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
this.game.map.zones = zones;
|
|
763
|
+
}
|
|
764
|
+
|
|
691
765
|
#processChatPacket() {
|
|
692
766
|
const id = CommIn.unPackInt8U();
|
|
693
767
|
const msgFlags = CommIn.unPackInt8U();
|
|
@@ -695,7 +769,7 @@ export class Bot {
|
|
|
695
769
|
const player = this.players[Object.keys(this.players).find(p => this.players[p].id == id)];
|
|
696
770
|
// console.log(`Player ${player.name}: ${text} (flags: ${msgFlags})`);
|
|
697
771
|
// console.log(`Their position: ${player.position.x}, ${player.position.y}, ${player.position.z}`);
|
|
698
|
-
this
|
|
772
|
+
this.emit('chat', player, text, msgFlags);
|
|
699
773
|
}
|
|
700
774
|
|
|
701
775
|
#processAddPlayerPacket() {
|
|
@@ -704,6 +778,7 @@ export class Bot {
|
|
|
704
778
|
const name = CommIn.unPackString();
|
|
705
779
|
const safename = CommIn.unPackString(); // ??? (a)
|
|
706
780
|
const charClass = CommIn.unPackInt8U();
|
|
781
|
+
const findCosmetics = this.intents.includes(this.Intents.COSMETIC_DATA);
|
|
707
782
|
const playerData = {
|
|
708
783
|
id_: id_,
|
|
709
784
|
uniqueId_: uniqueId,
|
|
@@ -712,14 +787,14 @@ export class Bot {
|
|
|
712
787
|
charClass_: charClass,
|
|
713
788
|
team_: CommIn.unPackInt8U(),
|
|
714
789
|
primaryWeaponItem_: findItemById(CommIn.unPackInt16U()),
|
|
715
|
-
secondaryWeaponItem_: findItemById(CommIn.unPackInt16U())
|
|
790
|
+
secondaryWeaponItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
716
791
|
shellColor_: CommIn.unPackInt8U(),
|
|
717
|
-
hatItem_: findItemById(CommIn.unPackInt16U()),
|
|
718
|
-
stampItem_: findItemById(CommIn.unPackInt16U()),
|
|
792
|
+
hatItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
793
|
+
stampItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
719
794
|
unknownInt8: CommIn.unPackInt8(), // c
|
|
720
795
|
otherUnknownInt8: CommIn.unPackInt8(),
|
|
721
|
-
grenadeItem_: findItemById(CommIn.unPackInt16U()),
|
|
722
|
-
meleeItem_: findItemById(CommIn.unPackInt16U()),
|
|
796
|
+
grenadeItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
797
|
+
meleeItem_: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
|
|
723
798
|
x_: CommIn.unPackFloat(),
|
|
724
799
|
y_: CommIn.unPackFloat(),
|
|
725
800
|
z_: CommIn.unPackFloat(),
|
|
@@ -752,36 +827,14 @@ export class Bot {
|
|
|
752
827
|
playerData.gameData_.private = CommIn.unPackInt8U();
|
|
753
828
|
playerData.gameData_.gameType = CommIn.unPackInt8U();
|
|
754
829
|
|
|
755
|
-
if (!this.players[playerData.id_])
|
|
830
|
+
if (!this.players[playerData.id_])
|
|
756
831
|
this.players[playerData.id_] = new GamePlayer(playerData.id_, playerData.team_, playerData);
|
|
757
832
|
|
|
758
|
-
const player = this.players[playerData.id_];
|
|
759
|
-
|
|
760
|
-
if (player.playing) {
|
|
761
|
-
player.healthInterval = setInterval(() => {
|
|
762
|
-
if (player.hp < 1) return;
|
|
763
|
-
|
|
764
|
-
const regenSpeed = 0.1 * (this.game.isPrivate ? this.game.options.healthRegen : 1);
|
|
765
|
-
|
|
766
|
-
if (player.streakRewards.includes(ShellStreaks.OverHeal)) {
|
|
767
|
-
player.hp = Math.max(100, player.hp - regenSpeed);
|
|
768
|
-
} else {
|
|
769
|
-
player.hp = Math.min(100, player.hp + regenSpeed);
|
|
770
|
-
}
|
|
771
|
-
}, 33);
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
|
|
775
833
|
if (this.me.id == playerData.id_) {
|
|
776
834
|
this.me = this.players[playerData.id_];
|
|
777
835
|
}
|
|
778
836
|
|
|
779
|
-
this
|
|
780
|
-
|
|
781
|
-
const unp = CommIn.unPackInt8U();
|
|
782
|
-
if (unp == CommCode.addPlayer) { // there is another player stacked
|
|
783
|
-
this.#processAddPlayerPacket();
|
|
784
|
-
}
|
|
837
|
+
this.emit('playerJoin', this.players[playerData.id_]);
|
|
785
838
|
}
|
|
786
839
|
|
|
787
840
|
#processRespawnPacket() {
|
|
@@ -808,29 +861,13 @@ export class Bot {
|
|
|
808
861
|
player.grenades = grenades;
|
|
809
862
|
player.position = { x: x, y: y, z: z };
|
|
810
863
|
// console.log(`Player ${player.name} respawned at ${x}, ${y}, ${z}`);
|
|
811
|
-
this
|
|
812
|
-
|
|
813
|
-
if (player.healthInterval) {
|
|
814
|
-
clearInterval(player.healthInterval);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
player.healthInterval = setInterval(() => {
|
|
818
|
-
if (player.hp < 1) return;
|
|
819
|
-
|
|
820
|
-
const regenSpeed = 0.1 * (this.game.isPrivate ? this.game.options[GameOptionFlags.healthRegen] : 1);
|
|
821
|
-
|
|
822
|
-
if (player.streakRewards.includes(ShellStreaks.OverHeal)) {
|
|
823
|
-
player.hp = Math.max(100, player.hp - regenSpeed);
|
|
824
|
-
} else {
|
|
825
|
-
player.hp = Math.min(100, player.hp + regenSpeed);
|
|
826
|
-
}
|
|
827
|
-
}, 33);
|
|
864
|
+
this.emit('playerRespawn', player);
|
|
828
865
|
} else {
|
|
829
866
|
// console.log(`Player ${id} not found. (me: ${this.me.id}) (respawn)`);
|
|
830
867
|
}
|
|
831
868
|
}
|
|
832
869
|
|
|
833
|
-
#
|
|
870
|
+
#processSyncThemPacket() {
|
|
834
871
|
const id = CommIn.unPackInt8U();
|
|
835
872
|
const x = CommIn.unPackFloat();
|
|
836
873
|
const y = CommIn.unPackFloat();
|
|
@@ -838,37 +875,53 @@ export class Bot {
|
|
|
838
875
|
const climbing = CommIn.unPackInt8U();
|
|
839
876
|
|
|
840
877
|
const player = this.players[id];
|
|
841
|
-
if (!player
|
|
878
|
+
if (!player) return;
|
|
842
879
|
|
|
843
|
-
if (player.
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
880
|
+
if (player.position.x !== x) player.position.x = x;
|
|
881
|
+
if (player.position.z !== z) player.position.z = z;
|
|
882
|
+
|
|
883
|
+
if (!player.jumping || Math.abs(player.position.y - y) > 0.5 && player.position.y !== y)
|
|
884
|
+
player.position.y = y;
|
|
885
|
+
|
|
886
|
+
if (player.climbing !== climbing) player.climbing = climbing;
|
|
887
|
+
|
|
888
|
+
if (this.intents.includes(this.Intents.BUFFERS)) {
|
|
889
|
+
if (!player.buffer) return;
|
|
890
|
+
|
|
891
|
+
if (player.id == this.me.id) {
|
|
892
|
+
for (let i2 = 0; i2 < 3 /* FramesBetweenSyncs */; i2++) {
|
|
893
|
+
CommIn.unPackInt8U();
|
|
894
|
+
CommIn.unPackRadU();
|
|
895
|
+
CommIn.unPackRad();
|
|
896
|
+
CommIn.unPackInt8U();
|
|
897
|
+
}
|
|
898
|
+
return;
|
|
848
899
|
}
|
|
849
|
-
}
|
|
850
900
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
yaw = CommIn.unPackRadU();
|
|
855
|
-
if (!isNaN(yaw)) { player.buffer[i2].yaw_ = yaw }
|
|
856
|
-
pitch = CommIn.unPackRad();
|
|
857
|
-
if (!isNaN(pitch)) { player.buffer[i2].pitch_ = pitch }
|
|
858
|
-
}
|
|
901
|
+
let yaw, pitch;
|
|
902
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
903
|
+
player.buffer[i2].controlKeys = CommIn.unPackInt8U();
|
|
859
904
|
|
|
860
|
-
|
|
905
|
+
yaw = CommIn.unPackRadU();
|
|
906
|
+
if (!isNaN(yaw)) player.buffer[i2].yaw_ = yaw
|
|
861
907
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
908
|
+
pitch = CommIn.unPackRad();
|
|
909
|
+
if (!isNaN(pitch)) player.buffer[i2].pitch_ = pitch
|
|
910
|
+
|
|
911
|
+
CommIn.unPackInt8U();
|
|
912
|
+
}
|
|
865
913
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
914
|
+
player.buffer[0].x = x;
|
|
915
|
+
player.buffer[0].y = y;
|
|
916
|
+
player.buffer[0].z = z;
|
|
917
|
+
} else {
|
|
918
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
919
|
+
CommIn.unPackInt8U();
|
|
920
|
+
CommIn.unPackRadU();
|
|
921
|
+
CommIn.unPackRad();
|
|
922
|
+
CommIn.unPackInt8U();
|
|
923
|
+
}
|
|
924
|
+
}
|
|
872
925
|
}
|
|
873
926
|
|
|
874
927
|
#processPausePacket() {
|
|
@@ -876,7 +929,7 @@ export class Bot {
|
|
|
876
929
|
const player = this.players[id];
|
|
877
930
|
if (player) {
|
|
878
931
|
player.playing = false;
|
|
879
|
-
this
|
|
932
|
+
this.emit('playerPause', player);
|
|
880
933
|
}
|
|
881
934
|
}
|
|
882
935
|
|
|
@@ -887,23 +940,21 @@ export class Bot {
|
|
|
887
940
|
const player = this.players[id];
|
|
888
941
|
if (player) {
|
|
889
942
|
player.activeGun = newWeaponId;
|
|
890
|
-
this
|
|
943
|
+
this.emit('playerSwapWeapon', player, newWeaponId);
|
|
891
944
|
}
|
|
892
945
|
}
|
|
893
946
|
|
|
894
947
|
#processDeathPacket() {
|
|
895
948
|
const killedId = CommIn.unPackInt8U();
|
|
896
949
|
const byId = CommIn.unPackInt8U();
|
|
897
|
-
|
|
950
|
+
|
|
951
|
+
CommIn.unPackInt8U();
|
|
952
|
+
CommIn.unPackInt8U();
|
|
953
|
+
CommIn.unPackInt8U();
|
|
898
954
|
|
|
899
955
|
const killed = this.players[killedId];
|
|
900
956
|
const killer = this.players[byId];
|
|
901
957
|
|
|
902
|
-
/*
|
|
903
|
-
const killerLastDmg = CommIn.unPackInt8U();
|
|
904
|
-
const killedLastDmg = CommIn.unPackInt8U();
|
|
905
|
-
*/
|
|
906
|
-
|
|
907
958
|
if (killed) {
|
|
908
959
|
killed.playing = false;
|
|
909
960
|
killed.kills = 0;
|
|
@@ -914,18 +965,21 @@ export class Bot {
|
|
|
914
965
|
if (killer) { killer.kills++; }
|
|
915
966
|
// console.log(`Player ${killer.name} is on a streak of ${killer.kills} kills.`);
|
|
916
967
|
|
|
917
|
-
this
|
|
968
|
+
this.emit('playerDeath', killed, killer); // killed, killer
|
|
918
969
|
}
|
|
919
970
|
|
|
920
971
|
#processFirePacket() {
|
|
921
972
|
const id = CommIn.unPackInt8U();
|
|
922
973
|
|
|
974
|
+
for (let i = 0; i < 6; i++)
|
|
975
|
+
CommIn.unPackFloat();
|
|
976
|
+
|
|
923
977
|
const player = this.players[id];
|
|
924
978
|
const playerWeapon = player.weapons[player.activeGun];
|
|
925
979
|
|
|
926
980
|
if (playerWeapon && playerWeapon.ammo) {
|
|
927
981
|
playerWeapon.ammo.rounds--;
|
|
928
|
-
this
|
|
982
|
+
this.emit('playerFire', player, playerWeapon);
|
|
929
983
|
}
|
|
930
984
|
}
|
|
931
985
|
|
|
@@ -938,7 +992,7 @@ export class Bot {
|
|
|
938
992
|
|
|
939
993
|
this.game.collectables[type].push({ id, x, y, z });
|
|
940
994
|
|
|
941
|
-
this
|
|
995
|
+
this.emit('spawnItem', type, id, { x, y, z });
|
|
942
996
|
}
|
|
943
997
|
|
|
944
998
|
#processCollectPacket() {
|
|
@@ -955,13 +1009,15 @@ export class Bot {
|
|
|
955
1009
|
const playerWeapon = player.weapons[applyToWeaponIdx];
|
|
956
1010
|
if (playerWeapon && playerWeapon.ammo) {
|
|
957
1011
|
playerWeapon.ammo.store = Math.min(playerWeapon.ammo.storeMax, playerWeapon.ammo.store + playerWeapon.ammo.pickup);
|
|
958
|
-
this
|
|
1012
|
+
this.emit('collectAmmo', player, playerWeapon);
|
|
959
1013
|
}
|
|
960
1014
|
}
|
|
961
1015
|
|
|
962
1016
|
if (type == CollectTypes.GRENADE) {
|
|
963
|
-
player.grenades
|
|
964
|
-
|
|
1017
|
+
player.grenades++;
|
|
1018
|
+
if (player.grenades > 3) player.grenades = 3
|
|
1019
|
+
|
|
1020
|
+
this.emit('collectGrenade', player);
|
|
965
1021
|
}
|
|
966
1022
|
}
|
|
967
1023
|
|
|
@@ -975,16 +1031,19 @@ export class Bot {
|
|
|
975
1031
|
const oldHP = player.hp;
|
|
976
1032
|
player.hp = hp;
|
|
977
1033
|
|
|
978
|
-
this
|
|
1034
|
+
this.emit('playerDamaged', player, oldHP, player.hp);
|
|
979
1035
|
}
|
|
980
1036
|
|
|
981
1037
|
#processHitMePacket() {
|
|
982
1038
|
const hp = CommIn.unPackInt8U();
|
|
983
|
-
const oldHp = this.me.hp;
|
|
984
1039
|
|
|
1040
|
+
CommIn.unPackFloat();
|
|
1041
|
+
CommIn.unPackFloat();
|
|
1042
|
+
|
|
1043
|
+
const oldHp = this.me.hp;
|
|
985
1044
|
this.me.hp = hp;
|
|
986
1045
|
|
|
987
|
-
this
|
|
1046
|
+
this.emit('selfDamaged', oldHp, this.me.hp);
|
|
988
1047
|
}
|
|
989
1048
|
|
|
990
1049
|
#processSyncMePacket() {
|
|
@@ -1001,6 +1060,10 @@ export class Bot {
|
|
|
1001
1060
|
const newY = CommIn.unPackFloat();
|
|
1002
1061
|
const newZ = CommIn.unPackFloat();
|
|
1003
1062
|
|
|
1063
|
+
CommIn.unPackInt8U();
|
|
1064
|
+
CommIn.unPackInt8U();
|
|
1065
|
+
CommIn.unPackInt8U();
|
|
1066
|
+
|
|
1004
1067
|
const oldX = player.position.x;
|
|
1005
1068
|
const oldY = player.position.y;
|
|
1006
1069
|
const oldZ = player.position.z;
|
|
@@ -1010,14 +1073,14 @@ export class Bot {
|
|
|
1010
1073
|
player.position.z = newZ;
|
|
1011
1074
|
|
|
1012
1075
|
if (oldX != newX || oldY != newY || oldZ != newZ) {
|
|
1013
|
-
this
|
|
1076
|
+
this.emit('selfMoved', player, { x: oldX, y: oldY, z: oldZ }, { x: newX, y: newY, z: newZ });
|
|
1014
1077
|
}
|
|
1015
1078
|
}
|
|
1016
1079
|
|
|
1017
1080
|
#processEventModifierPacket() {
|
|
1018
1081
|
const out = CommOut.getBuffer();
|
|
1019
1082
|
out.packInt8(CommCode.eventModifier);
|
|
1020
|
-
out.send(this.
|
|
1083
|
+
out.send(this.game.socket);
|
|
1021
1084
|
}
|
|
1022
1085
|
|
|
1023
1086
|
#processRemovePlayerPacket() {
|
|
@@ -1026,7 +1089,7 @@ export class Bot {
|
|
|
1026
1089
|
|
|
1027
1090
|
delete this.players[id.toString()];
|
|
1028
1091
|
|
|
1029
|
-
this
|
|
1092
|
+
this.emit('playerLeave', removedPlayer);
|
|
1030
1093
|
}
|
|
1031
1094
|
|
|
1032
1095
|
#processGameStatePacket() {
|
|
@@ -1049,10 +1112,10 @@ export class Bot {
|
|
|
1049
1112
|
controlledByTeam: controlledByTeam
|
|
1050
1113
|
};
|
|
1051
1114
|
|
|
1052
|
-
this
|
|
1115
|
+
this.emit('gameStateChange', this.game);
|
|
1053
1116
|
} else if (this.game.gameModeId == GameModes.kotc) {
|
|
1054
1117
|
this.game.stage = CommIn.unPackInt8U(); // constants.CoopStates
|
|
1055
|
-
this.game.
|
|
1118
|
+
this.game.zoneNumber = CommIn.unPackInt8U(); // a number to represent which 'active zone' kotc is using
|
|
1056
1119
|
this.game.capturing = CommIn.unPackInt8U(); // the team capturing, named "teams" in shell src
|
|
1057
1120
|
this.game.captureProgress = CommIn.unPackInt16U(); // progress of the coop capture
|
|
1058
1121
|
this.game.numCapturing = CommIn.unPackInt8U(); // number of players capturing - number/1000
|
|
@@ -1062,8 +1125,12 @@ export class Bot {
|
|
|
1062
1125
|
// not in shell, for utility purposes =D
|
|
1063
1126
|
this.game.stageName = CoopStagesById[this.game.stage]; // name of the stage ('start' / 'capturing' / 'etc')
|
|
1064
1127
|
this.game.capturePercent = this.game.captureProgress / 1000; // progress of the capture as a percentage
|
|
1128
|
+
this.game.activeZone = this.game.map.zones ? this.game.map.zones[this.game.zoneNumber - 1] : null;
|
|
1065
1129
|
|
|
1066
|
-
this
|
|
1130
|
+
this.emit('gameStateChange', this.game);
|
|
1131
|
+
} else if (this.game.gameModeId == GameModes.team) {
|
|
1132
|
+
this.game.teamScore[1] = CommIn.unPackInt16U();
|
|
1133
|
+
this.game.teamScore[2] = CommIn.unPackInt16U();
|
|
1067
1134
|
}
|
|
1068
1135
|
|
|
1069
1136
|
if (this.game.gameModeId !== GameModes.spatula) {
|
|
@@ -1072,13 +1139,16 @@ export class Bot {
|
|
|
1072
1139
|
|
|
1073
1140
|
if (this.game.gameModeId !== GameModes.kotc) {
|
|
1074
1141
|
delete this.game.stage;
|
|
1075
|
-
delete this.game.
|
|
1142
|
+
delete this.game.zoneNumber;
|
|
1076
1143
|
delete this.game.capturing;
|
|
1077
1144
|
delete this.game.captureProgress;
|
|
1078
|
-
delete this.game.numCapturing
|
|
1145
|
+
delete this.game.numCapturing;
|
|
1146
|
+
delete this.game.stageName;
|
|
1147
|
+
delete this.game.numCapturing;
|
|
1148
|
+
delete this.game.activeZone;
|
|
1079
1149
|
}
|
|
1080
1150
|
|
|
1081
|
-
if (this.game.gameModeId
|
|
1151
|
+
if (this.game.gameModeId == GameModes.ffa) {
|
|
1082
1152
|
delete this.game.teamScore;
|
|
1083
1153
|
}
|
|
1084
1154
|
}
|
|
@@ -1129,7 +1199,7 @@ export class Bot {
|
|
|
1129
1199
|
break;
|
|
1130
1200
|
}
|
|
1131
1201
|
|
|
1132
|
-
this
|
|
1202
|
+
this.emit('playerBeginStreak', player, ksType);
|
|
1133
1203
|
}
|
|
1134
1204
|
|
|
1135
1205
|
#processEndStreakPacket() {
|
|
@@ -1148,21 +1218,24 @@ export class Bot {
|
|
|
1148
1218
|
player.streakRewards = player.streakRewards.filter((r) => r != ksType);
|
|
1149
1219
|
}
|
|
1150
1220
|
|
|
1151
|
-
this
|
|
1221
|
+
this.emit('playerEndStreak', ksType, player);
|
|
1152
1222
|
}
|
|
1153
1223
|
|
|
1154
1224
|
#processHitShieldPacket() {
|
|
1155
1225
|
const hb = CommIn.unPackInt8U();
|
|
1156
1226
|
const hp = CommIn.unPackInt8U();
|
|
1157
1227
|
|
|
1228
|
+
CommIn.unPackFloat();
|
|
1229
|
+
CommIn.unPackFloat();
|
|
1230
|
+
|
|
1158
1231
|
this.me.hpShield = hb;
|
|
1159
1232
|
this.me.hp = hp;
|
|
1160
1233
|
|
|
1161
1234
|
if (this.me.hpShield <= 0) {
|
|
1162
1235
|
this.me.streakRewards = this.me.streakRewards.filter((r) => r != ShellStreaks.HardBoiled);
|
|
1163
|
-
this
|
|
1236
|
+
this.emit('selfShieldLost');
|
|
1164
1237
|
} else {
|
|
1165
|
-
this
|
|
1238
|
+
this.emit('selfShieldHit', this.me.hpShield);
|
|
1166
1239
|
}
|
|
1167
1240
|
}
|
|
1168
1241
|
|
|
@@ -1191,7 +1264,7 @@ export class Bot {
|
|
|
1191
1264
|
this.game.options.weaponsDisabled = Array.from({ length: 7 }, () => CommIn.unPackInt8U() === 1);
|
|
1192
1265
|
this.game.options.mustUseSecondary = this.game.options.weaponsDisabled.every((v) => v);
|
|
1193
1266
|
|
|
1194
|
-
this
|
|
1267
|
+
this.emit('gameOptionsChange', oldOptions, this.game.options);
|
|
1195
1268
|
return false;
|
|
1196
1269
|
}
|
|
1197
1270
|
|
|
@@ -1200,7 +1273,7 @@ export class Bot {
|
|
|
1200
1273
|
|
|
1201
1274
|
if (action == GameActions.pause) {
|
|
1202
1275
|
// console.log('settings changed, gameOwner changed game settings, force paused');
|
|
1203
|
-
this
|
|
1276
|
+
this.emit('gameForcePause');
|
|
1204
1277
|
setTimeout(() => this.me.playing = false, 3000);
|
|
1205
1278
|
}
|
|
1206
1279
|
|
|
@@ -1208,35 +1281,43 @@ export class Bot {
|
|
|
1208
1281
|
// console.log('owner reset game');
|
|
1209
1282
|
|
|
1210
1283
|
this.me.kills = 0;
|
|
1211
|
-
this.game.teamScore = [0, 0, 0];
|
|
1212
1284
|
|
|
1213
|
-
this.game.
|
|
1214
|
-
this.game.spatula.controlledByTeam = 0;
|
|
1215
|
-
this.game.spatula.coords = { x: 0, y: 0, z: 0 };
|
|
1285
|
+
if (this.game.gameModeId !== GameModes.ffa) this.game.teamScore = [0, 0, 0];
|
|
1216
1286
|
|
|
1217
|
-
this.game.
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
this.game.
|
|
1287
|
+
if (this.game.gameModeId === GameModes.spatula) {
|
|
1288
|
+
this.game.spatula.controlledBy = 0;
|
|
1289
|
+
this.game.spatula.controlledByTeam = 0;
|
|
1290
|
+
this.game.spatula.coords = { x: 0, y: 0, z: 0 };
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
if (this.game.gameModeId === GameModes.kotc) {
|
|
1294
|
+
this.game.stage = CoopStates.capturing;
|
|
1295
|
+
this.game.zoneNumber = 0;
|
|
1296
|
+
this.game.activeZone = null;
|
|
1297
|
+
this.game.capturing = 0;
|
|
1298
|
+
this.game.captureProgress = 0;
|
|
1299
|
+
this.game.numCapturing = 0;
|
|
1300
|
+
this.game.stageName = CoopStagesById[CoopStates.capturing];
|
|
1301
|
+
this.game.capturePercent = 0.0;
|
|
1302
|
+
}
|
|
1224
1303
|
|
|
1225
|
-
this
|
|
1304
|
+
this.emit('gameReset');
|
|
1226
1305
|
}
|
|
1227
1306
|
}
|
|
1228
1307
|
|
|
1229
1308
|
#processPingPacket() {
|
|
1309
|
+
if (!this.intents.includes(this.Intents.PING)) return;
|
|
1310
|
+
|
|
1230
1311
|
const oldPing = this.ping;
|
|
1231
1312
|
|
|
1232
1313
|
this.ping = Date.now() - this.lastPingTime;
|
|
1233
1314
|
|
|
1234
|
-
this
|
|
1315
|
+
this.emit('pingUpdate', oldPing, this.ping);
|
|
1235
1316
|
|
|
1236
1317
|
setTimeout(() => {
|
|
1237
1318
|
const out = CommOut.getBuffer();
|
|
1238
1319
|
out.packInt8(CommCode.ping);
|
|
1239
|
-
out.send(this.
|
|
1320
|
+
out.send(this.game.socket);
|
|
1240
1321
|
this.lastPingTime = Date.now();
|
|
1241
1322
|
}, this.pingInterval);
|
|
1242
1323
|
}
|
|
@@ -1253,7 +1334,7 @@ export class Bot {
|
|
|
1253
1334
|
player.team = toTeam;
|
|
1254
1335
|
player.kills = 0;
|
|
1255
1336
|
|
|
1256
|
-
this
|
|
1337
|
+
this.emit('playerSwitchTeam', player, oldTeam, toTeam);
|
|
1257
1338
|
}
|
|
1258
1339
|
|
|
1259
1340
|
#processChangeCharacterPacket() {
|
|
@@ -1268,12 +1349,18 @@ export class Bot {
|
|
|
1268
1349
|
const grenadeIdx = CommIn.unPackInt16U();
|
|
1269
1350
|
const meleeIdx = CommIn.unPackInt16U();
|
|
1270
1351
|
|
|
1352
|
+
CommIn.unPackInt8();
|
|
1353
|
+
CommIn.unPackInt8();
|
|
1354
|
+
|
|
1355
|
+
const findCosmetics = this.intents.includes(this.Intents.COSMETIC_DATA);
|
|
1356
|
+
|
|
1271
1357
|
const primaryWeaponItem = findItemById(primaryWeaponIdx);
|
|
1272
|
-
|
|
1273
|
-
const
|
|
1274
|
-
const
|
|
1275
|
-
const
|
|
1276
|
-
const
|
|
1358
|
+
|
|
1359
|
+
const secondaryWeaponItem = findCosmetics ? findItemById(secondaryWeaponIdx) : secondaryWeaponIdx;
|
|
1360
|
+
const hatItem = findCosmetics ? findItemById(hatIdx) : hatIdx;
|
|
1361
|
+
const stampItem = findCosmetics ? findItemById(stampIdx) : stampIdx;
|
|
1362
|
+
const grenadeItem = findCosmetics ? findItemById(grenadeIdx) : grenadeIdx;
|
|
1363
|
+
const meleeItem = findCosmetics ? findItemById(meleeIdx) : meleeIdx;
|
|
1277
1364
|
|
|
1278
1365
|
const player = this.players[id];
|
|
1279
1366
|
if (player) {
|
|
@@ -1291,8 +1378,8 @@ export class Bot {
|
|
|
1291
1378
|
player.selectedGun = weaponIndex;
|
|
1292
1379
|
player.weapons[0] = new GunList[weaponIndex]();
|
|
1293
1380
|
|
|
1294
|
-
if (oldWeaponIdx !== player.selectedGun) this
|
|
1295
|
-
if (oldCharacter !== player.character) this
|
|
1381
|
+
if (oldWeaponIdx !== player.selectedGun) this.emit('playerChangeGun', player, oldWeaponIdx, player.selectedGun);
|
|
1382
|
+
if (oldCharacter !== player.character) this.emit('playerChangeCharacter', player, oldCharacter, player.character);
|
|
1296
1383
|
}
|
|
1297
1384
|
}
|
|
1298
1385
|
|
|
@@ -1301,27 +1388,23 @@ export class Bot {
|
|
|
1301
1388
|
const oldBalance = this.account.eggBalance;
|
|
1302
1389
|
|
|
1303
1390
|
this.account.eggBalance = newBalance;
|
|
1304
|
-
this
|
|
1391
|
+
this.emit('balanceUpdate', newBalance - oldBalance, newBalance);
|
|
1305
1392
|
}
|
|
1306
1393
|
|
|
1307
1394
|
#processRespawnDeniedPacket() {
|
|
1308
1395
|
this.me.playing = false;
|
|
1309
|
-
this
|
|
1396
|
+
this.emit('selfRespawnFail');
|
|
1310
1397
|
}
|
|
1311
1398
|
|
|
1312
1399
|
#processMeleePacket() {
|
|
1313
1400
|
const id = CommIn.unPackInt8U();
|
|
1314
1401
|
const player = this.players[id];
|
|
1315
1402
|
|
|
1316
|
-
if (player) this
|
|
1403
|
+
if (player) this.emit('playerMelee', player);
|
|
1317
1404
|
}
|
|
1318
1405
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
if (!iUnderstandThisIsForInternalUseOnlyAndIShouldNotBeCallingThis)
|
|
1322
|
-
throw new Error('processReloadPacket is exposed for internal use only. do not call it.');
|
|
1323
|
-
|
|
1324
|
-
const id = customPlayer || CommIn.unPackInt8U();
|
|
1406
|
+
#processReloadPacket() {
|
|
1407
|
+
const id = CommIn.unPackInt8U();
|
|
1325
1408
|
const player = this.players[id];
|
|
1326
1409
|
|
|
1327
1410
|
if (!player) return;
|
|
@@ -1338,142 +1421,426 @@ export class Bot {
|
|
|
1338
1421
|
playerActiveWeapon.ammo.store -= newRounds;
|
|
1339
1422
|
}
|
|
1340
1423
|
|
|
1341
|
-
this
|
|
1424
|
+
this.emit('playerReload', player, playerActiveWeapon);
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
#processGameRequestOptionsPacket() {
|
|
1428
|
+
const out = CommOut.getBuffer();
|
|
1429
|
+
out.packInt8(CommCode.gameOptions);
|
|
1430
|
+
out.packInt8(this.game.options.gravity * 4);
|
|
1431
|
+
out.packInt8(this.game.options.damage * 4);
|
|
1432
|
+
out.packInt8(this.game.options.healthRegen * 4);
|
|
1433
|
+
|
|
1434
|
+
const flags =
|
|
1435
|
+
(this.game.options.locked ? 1 : 0) |
|
|
1436
|
+
(this.game.options.noTeamChange ? 2 : 0) |
|
|
1437
|
+
(this.game.options.noTeamShuffle ? 4 : 0);
|
|
1438
|
+
|
|
1439
|
+
out.packInt8(flags);
|
|
1440
|
+
|
|
1441
|
+
this.game.options.weaponsDisabled.forEach((v) => {
|
|
1442
|
+
out.packInt8(v ? 1 : 0);
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
#processExplodePacket() {
|
|
1447
|
+
const itemType = CommIn.unPackInt8U();
|
|
1448
|
+
let item = CommIn.unPackInt16U();
|
|
1449
|
+
const x = CommIn.unPackFloat();
|
|
1450
|
+
const y = CommIn.unPackFloat();
|
|
1451
|
+
const z = CommIn.unPackFloat();
|
|
1452
|
+
const damage = CommIn.unPackInt8U();
|
|
1453
|
+
const radius = CommIn.unPackFloat();
|
|
1454
|
+
|
|
1455
|
+
if (this.intents.includes(this.Intents.COSMETIC_DATA))
|
|
1456
|
+
item = findItemById(item);
|
|
1457
|
+
|
|
1458
|
+
if (itemType == ItemTypes.Grenade) this.emit('grenadeExploded', item, { x, y, z }, damage, radius);
|
|
1459
|
+
else this.emit('rocketHit', { x, y, z }, damage, radius);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
#processThrowGrenadePacket() {
|
|
1463
|
+
const id = CommIn.unPackInt8U();
|
|
1464
|
+
const x = CommIn.unPackFloat();
|
|
1465
|
+
const y = CommIn.unPackFloat();
|
|
1466
|
+
const z = CommIn.unPackFloat();
|
|
1467
|
+
const dx = CommIn.unPackFloat();
|
|
1468
|
+
const dy = CommIn.unPackFloat();
|
|
1469
|
+
const dz = CommIn.unPackFloat();
|
|
1470
|
+
|
|
1471
|
+
const player = this.players[id];
|
|
1472
|
+
|
|
1473
|
+
if (player) {
|
|
1474
|
+
player.grenades--;
|
|
1475
|
+
this.emit('playerThrowGrenade', player, { x, y, z }, { x: dx, y: dy, z: dz });
|
|
1476
|
+
}
|
|
1342
1477
|
}
|
|
1343
1478
|
|
|
1344
1479
|
#handlePacket(packet) {
|
|
1345
1480
|
CommIn.init(packet);
|
|
1346
|
-
this.#emit('packet', packet);
|
|
1347
|
-
const cmd = CommIn.unPackInt8U();
|
|
1348
|
-
switch (cmd) {
|
|
1349
|
-
case CommCode.chat:
|
|
1350
|
-
this.#processChatPacket(packet);
|
|
1351
|
-
break;
|
|
1352
1481
|
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
break;
|
|
1482
|
+
let lastCommand = 0;
|
|
1483
|
+
let abort = false;
|
|
1356
1484
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
break;
|
|
1485
|
+
while (CommIn.isMoreDataAvailable() && !abort) {
|
|
1486
|
+
const cmd = CommIn.unPackInt8U();
|
|
1360
1487
|
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1488
|
+
switch (cmd) {
|
|
1489
|
+
case CommCode.syncThem:
|
|
1490
|
+
this.#processSyncThemPacket(packet);
|
|
1491
|
+
break;
|
|
1364
1492
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1493
|
+
case CommCode.fire:
|
|
1494
|
+
this.#processFirePacket(packet);
|
|
1495
|
+
break;
|
|
1368
1496
|
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1497
|
+
case CommCode.hitThem:
|
|
1498
|
+
this.#processHitThemPacket(packet);
|
|
1499
|
+
break;
|
|
1372
1500
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1501
|
+
case CommCode.syncMe:
|
|
1502
|
+
this.#processSyncMePacket(packet);
|
|
1503
|
+
break;
|
|
1376
1504
|
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1505
|
+
case CommCode.hitMe:
|
|
1506
|
+
this.#processHitMePacket(packet);
|
|
1507
|
+
break;
|
|
1380
1508
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1509
|
+
case CommCode.swapWeapon:
|
|
1510
|
+
this.#processSwapWeaponPacket(packet);
|
|
1511
|
+
break;
|
|
1384
1512
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1513
|
+
case CommCode.collectItem:
|
|
1514
|
+
this.#processCollectPacket(packet);
|
|
1515
|
+
break;
|
|
1388
1516
|
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1517
|
+
case CommCode.respawn:
|
|
1518
|
+
this.#processRespawnPacket(packet);
|
|
1519
|
+
break;
|
|
1392
1520
|
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1521
|
+
case CommCode.die:
|
|
1522
|
+
this.#processDeathPacket(packet);
|
|
1523
|
+
break;
|
|
1396
1524
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1525
|
+
case CommCode.pause:
|
|
1526
|
+
this.#processPausePacket(packet);
|
|
1527
|
+
break;
|
|
1400
1528
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1529
|
+
case CommCode.chat:
|
|
1530
|
+
this.#processChatPacket(packet);
|
|
1531
|
+
break;
|
|
1404
1532
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1533
|
+
case CommCode.addPlayer:
|
|
1534
|
+
this.#processAddPlayerPacket(packet);
|
|
1535
|
+
break;
|
|
1408
1536
|
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1537
|
+
case CommCode.removePlayer:
|
|
1538
|
+
this.#processRemovePlayerPacket(packet);
|
|
1539
|
+
break;
|
|
1412
1540
|
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1541
|
+
case CommCode.eventModifier:
|
|
1542
|
+
this.#processEventModifierPacket(packet);
|
|
1543
|
+
break;
|
|
1416
1544
|
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1545
|
+
case CommCode.metaGameState:
|
|
1546
|
+
this.#processGameStatePacket(packet);
|
|
1547
|
+
break;
|
|
1420
1548
|
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1549
|
+
case CommCode.beginShellStreak:
|
|
1550
|
+
this.#processBeginStreakPacket(packet);
|
|
1551
|
+
break;
|
|
1424
1552
|
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1553
|
+
case CommCode.endShellStreak:
|
|
1554
|
+
this.#processEndStreakPacket(packet);
|
|
1555
|
+
break;
|
|
1428
1556
|
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1557
|
+
case CommCode.hitMeHardBoiled:
|
|
1558
|
+
this.#processHitShieldPacket(packet);
|
|
1559
|
+
break;
|
|
1432
1560
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1561
|
+
case CommCode.gameOptions:
|
|
1562
|
+
this.#processGameOptionsPacket(packet);
|
|
1563
|
+
break;
|
|
1436
1564
|
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1565
|
+
case CommCode.ping:
|
|
1566
|
+
this.#processPingPacket(packet);
|
|
1567
|
+
break;
|
|
1440
1568
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1569
|
+
case CommCode.switchTeam:
|
|
1570
|
+
this.#processSwitchTeamPacket(packet);
|
|
1571
|
+
break;
|
|
1444
1572
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1573
|
+
case CommCode.changeCharacter:
|
|
1574
|
+
this.#processChangeCharacterPacket(packet);
|
|
1575
|
+
break;
|
|
1448
1576
|
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1577
|
+
case CommCode.reload:
|
|
1578
|
+
this.#processReloadPacket();
|
|
1579
|
+
break;
|
|
1452
1580
|
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1581
|
+
case CommCode.explode:
|
|
1582
|
+
this.#processExplodePacket();
|
|
1583
|
+
break;
|
|
1456
1584
|
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1585
|
+
case CommCode.throwGrenade:
|
|
1586
|
+
this.#processThrowGrenadePacket();
|
|
1587
|
+
break;
|
|
1588
|
+
|
|
1589
|
+
case CommCode.spawnItem:
|
|
1590
|
+
this.#processSpawnItemPacket();
|
|
1591
|
+
break;
|
|
1592
|
+
|
|
1593
|
+
case CommCode.melee:
|
|
1594
|
+
this.#processMeleePacket();
|
|
1595
|
+
break;
|
|
1596
|
+
|
|
1597
|
+
case CommCode.updateBalance:
|
|
1598
|
+
this.#processUpdateBalancePacket(packet);
|
|
1599
|
+
break;
|
|
1600
|
+
|
|
1601
|
+
case CommCode.gameAction:
|
|
1602
|
+
this.#processGameActionPacket(packet);
|
|
1603
|
+
break;
|
|
1604
|
+
|
|
1605
|
+
case CommCode.requestGameOptions:
|
|
1606
|
+
this.#processGameRequestOptionsPacket();
|
|
1607
|
+
break;
|
|
1608
|
+
|
|
1609
|
+
case CommCode.respawnDenied:
|
|
1610
|
+
this.#processRespawnDeniedPacket(packet);
|
|
1611
|
+
break;
|
|
1460
1612
|
|
|
1461
|
-
case CommCode.clientReady:
|
|
1462
|
-
case CommCode.expireUpgrade:
|
|
1463
|
-
case CommCode.musicInfo:
|
|
1464
|
-
case CommCode.challengeCompleted:
|
|
1465
1613
|
// we do not plan to implement these
|
|
1466
1614
|
// for more info, see comm/codes.js
|
|
1467
|
-
|
|
1615
|
+
case CommCode.clientReady:
|
|
1616
|
+
case CommCode.expireUpgrade:
|
|
1617
|
+
break;
|
|
1468
1618
|
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
break;
|
|
1619
|
+
case CommCode.musicInfo:
|
|
1620
|
+
CommIn.unPackLongString();
|
|
1621
|
+
break;
|
|
1473
1622
|
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1623
|
+
case CommCode.challengeCompleted:
|
|
1624
|
+
CommIn.unPackInt8U();
|
|
1625
|
+
CommIn.unPackInt8U();
|
|
1626
|
+
break;
|
|
1627
|
+
|
|
1628
|
+
default:
|
|
1629
|
+
console.error(`handlePacket: I got but did not handle a: ${Object.keys(CommCode).find(k => CommCode[k] === cmd)}`);
|
|
1630
|
+
if (lastCommand) console.error(`handlePacket: It may be a result of the ${lastCommand} command.`);
|
|
1631
|
+
abort = true
|
|
1632
|
+
break;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
lastCommand = Object.keys(CommCode).find(k => CommCode[k] === cmd);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
async checkChiknWinner() {
|
|
1640
|
+
const response = await queryServices({
|
|
1641
|
+
cmd: 'chicknWinnerReady',
|
|
1642
|
+
id: this.account.id,
|
|
1643
|
+
sessionId: this.account.sessionId
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
this.account.cw.limit = response.limit;
|
|
1647
|
+
this.account.cw.atLimit = response.limit > 3;
|
|
1648
|
+
|
|
1649
|
+
// if there is a "span", that means that it's under the daily limit and you can play again soon
|
|
1650
|
+
// if there is a "period", that means that the account is done for the day and must wait a long time
|
|
1651
|
+
this.account.cw.secondsUntilPlay = response.span || response.period || 0;
|
|
1652
|
+
this.account.cw.canPlayAgain = Date.now() + (this.account.cw.secondsUntilPlay * 1000);
|
|
1653
|
+
|
|
1654
|
+
return this.account.cw;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
async playChiknWinner() {
|
|
1658
|
+
if (this.account.cw.atLimit || this.account.cw.limit > ChiknWinnerDailyLimit) return 'hit_daily_limit';
|
|
1659
|
+
if (this.account.cw.canPlayAgain > Date.now()) return 'on_cooldown';
|
|
1660
|
+
|
|
1661
|
+
const response = await queryServices({
|
|
1662
|
+
cmd: 'incentivizedVideoReward',
|
|
1663
|
+
firebaseId: this.account.firebaseId,
|
|
1664
|
+
id: this.account.id,
|
|
1665
|
+
sessionId: this.account.sessionId,
|
|
1666
|
+
token: null
|
|
1667
|
+
}, this.proxy, this.instance);
|
|
1668
|
+
|
|
1669
|
+
if (response.error) {
|
|
1670
|
+
if (response.error == 'RATELIMITED') {
|
|
1671
|
+
await this.checkChiknWinner();
|
|
1672
|
+
return 'on_cooldown';
|
|
1673
|
+
} else if (response.error == 'SESSION_EXPIRED') {
|
|
1674
|
+
return 'session_expired';
|
|
1675
|
+
} else {
|
|
1676
|
+
console.error('Unknown Chikn Winner response', response);
|
|
1677
|
+
return 'unknown_error';
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
if (response.reward) {
|
|
1682
|
+
this.account.eggBalance += response.reward.eggsGiven;
|
|
1683
|
+
response.reward.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
|
|
1684
|
+
|
|
1685
|
+
await this.checkChiknWinner();
|
|
1686
|
+
|
|
1687
|
+
return response.reward;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
console.error('Unknown Chikn Winner response', response);
|
|
1691
|
+
return 'unknown_error';
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
async resetChiknWinner() {
|
|
1695
|
+
if (this.account.eggBalance < 200) return 'not_enough_eggs';
|
|
1696
|
+
if (!this.account.cw.atLimit) return 'not_at_limit';
|
|
1697
|
+
|
|
1698
|
+
const response = await queryServices({
|
|
1699
|
+
cmd: 'chwReset',
|
|
1700
|
+
sessionId: this.account.sessionId
|
|
1701
|
+
});
|
|
1702
|
+
|
|
1703
|
+
if (response.result !== 'SUCCESS') {
|
|
1704
|
+
console.error('Unknown Chikn Winner reset response', response);
|
|
1705
|
+
return 'unknown_error';
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
this.account.eggBalance -= 200;
|
|
1709
|
+
await this.checkChiknWinner();
|
|
1710
|
+
|
|
1711
|
+
return this.account.cw;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
canSee(target) {
|
|
1715
|
+
if (!this.intents.includes(this.Intents.PATHFINDING)) throw new Error('You must have the PATHFINDING intent to use this method.');
|
|
1716
|
+
return this.pathing.nodeList.hasLineOfSight(this.me.position, target.position);
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
getBestTarget() {
|
|
1720
|
+
const options = Object.values(this.players)
|
|
1721
|
+
.filter((player) => player)
|
|
1722
|
+
.filter((player) => player !== this.me)
|
|
1723
|
+
.filter((player) => player.playing)
|
|
1724
|
+
.filter((player) => player.hp > 0)
|
|
1725
|
+
.filter((player) => player.name !== this.me.name)
|
|
1726
|
+
.filter((player) => this.me.team === 0 || player.team !== this.me.team)
|
|
1727
|
+
.filter((player) => this.canSee(player));
|
|
1728
|
+
|
|
1729
|
+
let minDistance = 200;
|
|
1730
|
+
let targetPlayer = null;
|
|
1731
|
+
|
|
1732
|
+
for (const player of options) {
|
|
1733
|
+
const dx = player.position.x - this.me.position.x;
|
|
1734
|
+
const dy = player.position.y - this.me.position.y;
|
|
1735
|
+
const dz = player.position.z - this.me.position.z;
|
|
1736
|
+
|
|
1737
|
+
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
1738
|
+
|
|
1739
|
+
if (distance < minDistance) {
|
|
1740
|
+
minDistance = distance;
|
|
1741
|
+
targetPlayer = player;
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
return targetPlayer;
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
async refreshBalance() {
|
|
1749
|
+
const result = await queryServices({
|
|
1750
|
+
cmd: 'checkBalance',
|
|
1751
|
+
firebaseId: this.account.firebaseId,
|
|
1752
|
+
sessionId: this.account.sessionId
|
|
1753
|
+
}, this.proxy, this.instance);
|
|
1754
|
+
|
|
1755
|
+
this.account.eggBalance = result.currentBalance;
|
|
1756
|
+
|
|
1757
|
+
return result.currentBalance;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
async redeemCode(code) {
|
|
1761
|
+
const result = await queryServices({
|
|
1762
|
+
cmd: 'redeem',
|
|
1763
|
+
firebaseId: this.account.firebaseId,
|
|
1764
|
+
sessionId: this.account.sessionId,
|
|
1765
|
+
id: this.account.id,
|
|
1766
|
+
code
|
|
1767
|
+
}, this.proxy, this.instance);
|
|
1768
|
+
|
|
1769
|
+
if (result.result === 'SUCCESS') {
|
|
1770
|
+
this.account.eggBalance = result.eggs_given;
|
|
1771
|
+
result.item_ids.forEach((id) => this.account.ownedItemIds.push(id));
|
|
1772
|
+
|
|
1773
|
+
return {
|
|
1774
|
+
result,
|
|
1775
|
+
eggsGiven: result.eggs_given,
|
|
1776
|
+
itemIds: result.item_ids
|
|
1777
|
+
};
|
|
1778
|
+
} else return result;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
async claimURLReward(reward) {
|
|
1782
|
+
const result = await queryServices({
|
|
1783
|
+
cmd: 'urlRewardParams',
|
|
1784
|
+
firebaseId: this.account.firebaseId,
|
|
1785
|
+
sessionId: this.account.sessionId,
|
|
1786
|
+
reward
|
|
1787
|
+
}, this.proxy, this.instance);
|
|
1788
|
+
|
|
1789
|
+
if (result.result === 'SUCCESS') {
|
|
1790
|
+
this.account.eggBalance += result.eggsGiven;
|
|
1791
|
+
result.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
return result;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
async claimSocialReward(rewardTag) {
|
|
1798
|
+
const result = await queryServices({
|
|
1799
|
+
cmd: 'reward',
|
|
1800
|
+
firebaseId: this.account.firebaseId,
|
|
1801
|
+
sessionId: this.account.sessionId,
|
|
1802
|
+
rewardTag
|
|
1803
|
+
}, this.proxy, this.instance);
|
|
1804
|
+
|
|
1805
|
+
if (result.result === 'SUCCESS') {
|
|
1806
|
+
this.account.eggBalance += result.eggsGiven;
|
|
1807
|
+
result.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
return result;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
async buyItem(itemId) {
|
|
1814
|
+
const result = await queryServices({
|
|
1815
|
+
cmd: 'buy',
|
|
1816
|
+
firebaseId: this.account.firebaseId,
|
|
1817
|
+
sessionId: this.account.sessionId,
|
|
1818
|
+
itemId,
|
|
1819
|
+
save: true
|
|
1820
|
+
}, this.proxy, this.instance);
|
|
1821
|
+
|
|
1822
|
+
if (result.result === 'SUCCESS') {
|
|
1823
|
+
this.account.eggBalance = result.currentBalance;
|
|
1824
|
+
this.account.ownedItemIds.push(result.itemId);
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
return result;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
quit(noCleanup = false) {
|
|
1831
|
+
if (this.intents.includes(this.Intents.PLAYER_HEALTH))
|
|
1832
|
+
clearInterval(this.healthIntervalId);
|
|
1833
|
+
|
|
1834
|
+
clearInterval(this.updateInterval);
|
|
1835
|
+
|
|
1836
|
+
this.game.socket.close();
|
|
1837
|
+
this.matchmaker.close();
|
|
1838
|
+
|
|
1839
|
+
if (!noCleanup) {
|
|
1840
|
+
delete this.account;
|
|
1841
|
+
delete this.game;
|
|
1842
|
+
delete this.me;
|
|
1843
|
+
delete this.players;
|
|
1477
1844
|
}
|
|
1478
1845
|
}
|
|
1479
1846
|
}
|