yolkbot 0.1.3 → 0.1.4-alpha.1

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