clashofclans.js 3.6.2-dev.ed2c97f → 3.6.3-dev.fb51c0b

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 - 2021 ClashPerk
3
+ Copyright (c) 2020 - 2026 clashperk
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const Client_1 = require("./client/Client");
4
+ const Util_1 = require("./util/Util");
5
+ describe('root', () => {
6
+ const client = new Client_1.Client({ baseURL: process.env.BASE_URL });
7
+ it('should return battle logs', async () => {
8
+ const { body: result } = await client.rest.getBattleLog('#9JPLU2RJ2');
9
+ const legendAttacks = result.items.filter((item) => item.battleType === 'legend').slice(-8);
10
+ console.log(legendAttacks.map((m) => Util_1.Util.calculateTrophies(m.stars, m.destructionPercentage, m.attack, true)));
11
+ expect(result).toHaveProperty('items');
12
+ });
13
+ });
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from 'node:events';
3
- import { APIBuilderBaseLeague, APIBuilderBaseLeagueList, APICapitalLeague, APICapitalLeagueList, APICapitalRaidSeasons, APIClan, APIClanBuilderBaseRankingList, APIClanCapitalRankingList, APIClanList, APIClanMemberList, APIClanRankingList, APIClanWar, APIClanWarLeagueGroup, APIClanWarLogList, APIGoldPassSeason, APILabelList, APILeagueSeasonList, APILeagueTier, APILeagueTierList, APILocation, APILocationList, APIPlayer, APIPlayerBuilderBaseRankingList, APIPlayerRankingList, APIPlayerSeasonRankingList, APIVerifyToken, APIWarLeague, APIWarLeagueList, ClanSearchOptions, LoginOptions, OverrideOptions, RESTOptions, SearchOptions } from '../types';
3
+ import { APIBattleLogEntryList, APIBuilderBaseLeague, APIBuilderBaseLeagueList, APICapitalLeague, APICapitalLeagueList, APICapitalRaidSeasons, APIClan, APIClanBuilderBaseRankingList, APIClanCapitalRankingList, APIClanList, APIClanMemberList, APIClanRankingList, APIClanWar, APIClanWarLeagueGroup, APIClanWarLogList, APIGoldPassSeason, APILabelList, APILeagueGroupList, APILeagueSeasonList, APILeagueSeasonResultList, APILeagueTier, APILeagueTierList, APILocation, APILocationList, APIPlayer, APIPlayerBuilderBaseRankingList, APIPlayerRankingList, APIPlayerSeasonRankingList, APIVerifyToken, APIWarLeague, APIWarLeagueList, ClanSearchOptions, LoginOptions, OverrideOptions, RESTOptions, SearchOptions } from '../types';
4
4
  import { RestEvents } from '../util/Constants';
5
5
  import { Util } from '../util/Util';
6
6
  import { RequestHandler } from './RequestHandler';
@@ -72,6 +72,11 @@ export declare class RESTManager extends EventEmitter {
72
72
  getPlayer(playerTag: string, options?: OverrideOptions): Promise<import("../types").Result<APIPlayer>>;
73
73
  /** Verify Player API token that can be found from the Game settings. */
74
74
  verifyPlayerToken(playerTag: string, token: string, options?: OverrideOptions): Promise<import("../types").Result<APIVerifyToken>>;
75
+ getLeagueHistory(playerTag: string, options?: OverrideOptions): Promise<import("../types").Result<APILeagueSeasonResultList>>;
76
+ getBattleLog(playerTag: string, options?: OverrideOptions): Promise<import("../types").Result<APIBattleLogEntryList>>;
77
+ getLeagueGroup(leagueGroupTag: string, seasonId: string, options?: OverrideOptions & {
78
+ playerTag?: string;
79
+ }): Promise<import("../types").Result<APILeagueGroupList>>;
75
80
  /** Get a list of League Tiers. */
76
81
  getLeagueTiers(options?: SearchOptions): Promise<import("../types").Result<APILeagueTierList>>;
77
82
  /** Get a League tier info. */
@@ -81,6 +81,15 @@ class RESTManager extends node_events_1.EventEmitter {
81
81
  ...options
82
82
  });
83
83
  }
84
+ getLeagueHistory(playerTag, options) {
85
+ return this.requestHandler.request(`/players/${Util_1.Util.encodeURI(playerTag)}/leaguehistory`, options);
86
+ }
87
+ getBattleLog(playerTag, options) {
88
+ return this.requestHandler.request(`/players/${Util_1.Util.encodeURI(playerTag)}/battlelog`, options);
89
+ }
90
+ getLeagueGroup(leagueGroupTag, seasonId, options) {
91
+ return this.requestHandler.request(`/leaguegroup/${leagueGroupTag}/${seasonId}`, options);
92
+ }
84
93
  /** Get a list of League Tiers. */
85
94
  getLeagueTiers(options) {
86
95
  const query = Util_1.Util.queryString(options);
@@ -6,6 +6,8 @@ const Constants_1 = require("../util/Constants");
6
6
  class Unit {
7
7
  // #endregion static
8
8
  constructor(data, unit) {
9
+ /** Training time of this unit. */
10
+ this.trainingTime = 0;
9
11
  this.name = unit.name;
10
12
  this.level = unit.level;
11
13
  this.maxLevel = unit.maxLevel;
@@ -317,6 +317,42 @@ export interface APIVerifyToken {
317
317
  token: string;
318
318
  status: 'ok' | 'invalid';
319
319
  }
320
+ export interface APIBattleLogEntryList {
321
+ items: APIBattleLogEntry[];
322
+ }
323
+ export interface APILootEntry {
324
+ name: string;
325
+ amount: number;
326
+ }
327
+ export interface APIBattleLogEntry {
328
+ battleType: 'legend' | 'homeVillage' | 'ranked';
329
+ attack: boolean;
330
+ armyShareCode: string;
331
+ opponentPlayerTag: string;
332
+ stars: number;
333
+ destructionPercentage: number;
334
+ lootedResources: APILootEntry[];
335
+ extraLootedResources: APILootEntry[];
336
+ availableLoot: APILootEntry[];
337
+ }
338
+ export interface APILeagueSeasonResult {
339
+ leagueSeasonId: number;
340
+ leagueTrophies: number;
341
+ leagueTierId: number;
342
+ placement: number;
343
+ attackWins: number;
344
+ attackLosses: number;
345
+ attackStars: number;
346
+ defenseWins: number;
347
+ defenseLosses: number;
348
+ defenseStars: number;
349
+ maxBattles: number;
350
+ }
351
+ export interface APILeagueSeasonResultList {
352
+ items: APILeagueSeasonResult[];
353
+ }
354
+ export interface APILeagueGroupList {
355
+ }
320
356
  /** /locations */
321
357
  export interface APILocationList {
322
358
  items: APILocation[];
@@ -70,37 +70,6 @@ export declare const RawData: {
70
70
  building: string;
71
71
  buildingLevel: number;
72
72
  };
73
- trainingTime: number;
74
- regenerationTimes: never[];
75
- dps: number[];
76
- upgrade: {
77
- cost: number[];
78
- time: number[];
79
- resource: string;
80
- resources: never[];
81
- };
82
- allowedCharacters: never[];
83
- minLevel: number;
84
- seasonal: boolean;
85
- levels: number[];
86
- resourceType?: undefined;
87
- } | {
88
- tid: string;
89
- id: number;
90
- name: string;
91
- housingSpace: number;
92
- village: string;
93
- category: string;
94
- subCategory: string;
95
- unlock: {
96
- hall: number;
97
- cost: number;
98
- time: number;
99
- resource: string;
100
- building: string;
101
- buildingLevel: number;
102
- };
103
- trainingTime: string;
104
73
  regenerationTimes: never[];
105
74
  dps: number[];
106
75
  upgrade: {
@@ -114,6 +83,7 @@ export declare const RawData: {
114
83
  seasonal: boolean;
115
84
  levels: number[];
116
85
  resourceType?: undefined;
86
+ trainingTime?: undefined;
117
87
  } | {
118
88
  tid: string;
119
89
  id: number;
@@ -132,7 +102,7 @@ export declare const RawData: {
132
102
  };
133
103
  resourceType: string;
134
104
  trainingTime: number;
135
- regenerationTimes: number[];
105
+ regenerationTimes: null[];
136
106
  dps: number[];
137
107
  upgrade: {
138
108
  cost: number[];
@@ -65,5 +65,6 @@ export declare class Util extends null {
65
65
  endTime: Date;
66
66
  };
67
67
  static allSettled<T>(values: Promise<T>[]): Promise<T[]>;
68
+ static calculateTrophies(stars: number, destruction: number, isAttack: boolean, isLegendLeague: boolean): number;
68
69
  static delay(ms: number): Promise<unknown>;
69
70
  }
package/dist/util/Util.js CHANGED
@@ -226,6 +226,44 @@ class Util extends null {
226
226
  .filter((res) => res.status === 'fulfilled')
227
227
  .map((res) => res.value);
228
228
  }
229
+ static calculateTrophies(stars, destruction, isAttack, isLegendLeague) {
230
+ let attackerGain = 0;
231
+ if (stars === 3) {
232
+ // 3 stars always awards the full pool
233
+ attackerGain = 40;
234
+ }
235
+ else if (stars === 2) {
236
+ // 16 base + 1 per 3% over 50%
237
+ attackerGain = 16 + Math.floor((destruction - 50) / 3);
238
+ }
239
+ else if (stars === 1) {
240
+ // 5 base + 1 per 9% destruction
241
+ attackerGain = 5 + Math.floor(destruction / 9);
242
+ }
243
+ else {
244
+ // 0 stars: 1 trophy per 10% destruction (minimum 10% required)
245
+ if (destruction >= 10) {
246
+ attackerGain = Math.floor(destruction / 10);
247
+ }
248
+ }
249
+ // Cap at 40 (standard trophy pool)
250
+ if (attackerGain > 40) {
251
+ attackerGain = 40;
252
+ }
253
+ if (isAttack) {
254
+ return attackerGain;
255
+ }
256
+ // In Legend League, the defender LOSES what the attacker gains
257
+ if (isLegendLeague) {
258
+ return -attackerGain;
259
+ }
260
+ // In Ranked, the defender GAINS the remainder of the 40 pool
261
+ // 0-star defense always gives full 40 to defender
262
+ if (stars === 0) {
263
+ return 40;
264
+ }
265
+ return 40 - attackerGain;
266
+ }
229
267
  static async delay(ms) {
230
268
  return new Promise((res) => setTimeout(res, ms));
231
269
  }