feat(herowars): migrate JSON static imports to HttpClient assets
Replace all TypeScript JSON imports with an HWDataService that loads 6 data files from /assets/files-data/ via HttpClient with shareReplay(1). Update all 9 consumer components to subscribe asynchronously. Remove unused qcm-bpa.json import and dead methods from QcmComponent. Add ADR 0013 documenting the decision.
This commit is contained in:
@@ -0,0 +1,67 @@
|
|||||||
|
# Migrate HeroWars static JSON imports to HttpClient assets
|
||||||
|
|
||||||
|
- Status: accepted
|
||||||
|
- Date: 2026-04-26
|
||||||
|
|
||||||
|
## Context and Problem Statement
|
||||||
|
|
||||||
|
Six large JSON files (36 KB–3 MB) were statically imported directly into Angular components and services via TypeScript `import` statements. This bundled all the data into the main JavaScript bundle, inflating the initial download regardless of whether the user navigated to the HeroWars section. The largest file (`hw-guild-raids.json`, 3 MB) alone would significantly delay first contentful paint for all users.
|
||||||
|
|
||||||
|
Additionally, a seventh file (`qcm-bpa.json`, 210 KB) was imported but never consumed — the component had switched to a route resolver but the dead import remained.
|
||||||
|
|
||||||
|
## Decision Drivers
|
||||||
|
|
||||||
|
- Static JSON imports are compiled into the bundle — they cannot be lazy-loaded or cached by the browser independently.
|
||||||
|
- Updating the data files required a recompile and redeployment; serving them as assets allows hot-swapping without a rebuild.
|
||||||
|
- The HeroWars section is used by a small subset of users; its data should not penalise all other users' load time.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
- Keep static imports
|
||||||
|
- Move JSON to assets and load via `HttpClient`
|
||||||
|
- Fetch data from the API backend
|
||||||
|
|
||||||
|
## Decision Outcome
|
||||||
|
|
||||||
|
Chosen option: "Move JSON to assets and load via HttpClient", because it removes the data from the bundle, enables browser-level HTTP caching, and requires no backend changes. The files are not secret (guild-internal analytics data) so serving them as static assets is appropriate.
|
||||||
|
|
||||||
|
Structure:
|
||||||
|
|
||||||
|
- JSON files moved from `src/files-data/` to `src/assets/files-data/`
|
||||||
|
- `HWDataService` created at `src/app/core/services/herowars/hw-data.service.ts` — exposes one `readonly` observable per file, each piped through `shareReplay(1)` so the HTTP request fires at most once per app lifecycle
|
||||||
|
- `HWClanService.loadClan()` and `HWMemberService.loadMembers()` converted from synchronous return values to `Observable<T>`
|
||||||
|
- All consumer components inject `HWDataService` and subscribe in `ngOnInit()`; template-called methods that previously accessed `guildWarSlots.slots` inline now read from a `_slots` class property populated in the subscribe callback
|
||||||
|
- Unused `import data from 'src/qcm-bpa.json'` and two dead import-helper methods removed from `qcm.component.ts`
|
||||||
|
|
||||||
|
### Positive Consequences
|
||||||
|
|
||||||
|
- HeroWars JSON (~4 MB total) no longer shipped in the initial bundle.
|
||||||
|
- Each JSON file is independently cacheable by the browser with standard HTTP cache headers.
|
||||||
|
- Data files can be updated without recompiling the Angular application.
|
||||||
|
- `shareReplay(1)` ensures a single HTTP request per session even when multiple components subscribe to the same observable.
|
||||||
|
|
||||||
|
### Negative Consequences
|
||||||
|
|
||||||
|
- Components now initialize asynchronously — there is a brief render before data arrives (consistent with the rest of the app's HTTP-driven components).
|
||||||
|
- `Object.entries()` on `any`-typed HTTP responses requires explicit `Record<string, T>` casts to satisfy strict TypeScript, adding minor verbosity.
|
||||||
|
|
||||||
|
## Pros and Cons of the Options
|
||||||
|
|
||||||
|
### Keep static imports
|
||||||
|
|
||||||
|
- Good, because synchronous — no async lifecycle complexity.
|
||||||
|
- Bad, because adds up to 4 MB to the initial bundle.
|
||||||
|
- Bad, because data updates require a full rebuild and redeployment.
|
||||||
|
|
||||||
|
### Move JSON to assets and load via HttpClient
|
||||||
|
|
||||||
|
- Good, because removes data from the bundle entirely.
|
||||||
|
- Good, because browser-cacheable independently of the app JS.
|
||||||
|
- Good, because hot-swappable without a recompile.
|
||||||
|
- Bad, because converts synchronous service methods to observables, requiring component updates.
|
||||||
|
|
||||||
|
### Fetch from API backend
|
||||||
|
|
||||||
|
- Good, because data could be managed dynamically via the admin interface.
|
||||||
|
- Bad, because requires significant backend work (new endpoints, data model) for data that is currently managed as flat files.
|
||||||
|
- Bad, because adds latency and a failure mode not present with local assets.
|
||||||
@@ -17,9 +17,6 @@ import { ClanViewModel, MembersViewModel } from '@viewmodels/herowars';
|
|||||||
import { HWClanService, HWMemberService, UtilitiesService } from '@services';
|
import { HWClanService, HWMemberService, UtilitiesService } from '@services';
|
||||||
import { MAX_CLAN_MEMBERS } from '@constants';
|
import { MAX_CLAN_MEMBERS } from '@constants';
|
||||||
|
|
||||||
import guildData from '@data/hw-guild-data.json'; // page Membres
|
|
||||||
import guildStatistics from '@data/hw-guild-statistics.json'; // page Overview -> Statistics
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-herowars-guildwar',
|
selector: 'app-herowars-guildwar',
|
||||||
imports: [
|
imports: [
|
||||||
@@ -93,29 +90,35 @@ export class HerowarsGuildwarComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadClan(): void {
|
loadClan(): void {
|
||||||
this._guildClan = this._clanService.loadClan();
|
this._clanService.loadClan().subscribe((clan) => {
|
||||||
|
this._guildClan = clan;
|
||||||
this.clanViewModel = new ClanViewModel(this._guildClan);
|
this.clanViewModel = new ClanViewModel(this._guildClan);
|
||||||
this.clanLoaded = true;
|
this.clanLoaded = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData(): void {
|
loadData(): void {
|
||||||
this._guildClan = this._clanService.loadClan();
|
this._clanService.loadClan().subscribe((clan) => {
|
||||||
this._guildMembers = this._memberService.loadMembers(this._guildClan);
|
this._guildClan = clan;
|
||||||
|
this._memberService.loadMembers(this._guildClan).subscribe((members) => {
|
||||||
|
this._guildMembers = members;
|
||||||
this._guildClan = this._clanService.loadClanStats(this._guildClan, this._guildMembers);
|
this._guildClan = this._clanService.loadClanStats(this._guildClan, this._guildMembers);
|
||||||
this.daysToWarn = parseInt(this._guildClan.daysToKick) / 2;
|
this.daysToWarn = parseInt(this._guildClan.daysToKick) / 2;
|
||||||
this.clanViewModel = new ClanViewModel(this._guildClan);
|
this.clanViewModel = new ClanViewModel(this._guildClan);
|
||||||
this.clanLoaded = true;
|
this.clanLoaded = true;
|
||||||
this.membersViewModel = new MembersViewModel(this._guildMembers);
|
this.membersViewModel = new MembersViewModel(this._guildMembers);
|
||||||
this.membersLoaded = true;
|
this.membersLoaded = true;
|
||||||
console.log(this._guildClan);
|
});
|
||||||
console.log(this._guildMembers);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMembers(): void {
|
loadMembers(): void {
|
||||||
this._guildMembers = this._memberService.loadMembers(this._guildClan);
|
this._memberService.loadMembers(this._guildClan).subscribe((members) => {
|
||||||
|
this._guildMembers = members;
|
||||||
this.membersViewModel = new MembersViewModel(this._guildMembers);
|
this.membersViewModel = new MembersViewModel(this._guildMembers);
|
||||||
this._guildClan = this._clanService.loadClanStats(this._guildClan, this._guildMembers);
|
this._guildClan = this._clanService.loadClanStats(this._guildClan, this._guildMembers);
|
||||||
this.membersLoaded = true;
|
this.membersLoaded = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getMembers(): HWMember[] {
|
getMembers(): HWMember[] {
|
||||||
@@ -124,11 +127,9 @@ export class HerowarsGuildwarComponent implements OnInit {
|
|||||||
|
|
||||||
syncClan(): void {
|
syncClan(): void {
|
||||||
console.log(this._guildClan);
|
console.log(this._guildClan);
|
||||||
console.log(guildData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
syncMembers(): void {
|
syncMembers(): void {
|
||||||
console.log(this._guildMembers);
|
console.log(this._guildMembers);
|
||||||
console.log(guildStatistics);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||||
import { provideNativeDateAdapter } from '@angular/material/core';
|
import { provideNativeDateAdapter } from '@angular/material/core';
|
||||||
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
|
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
||||||
|
|
||||||
import { HerowarsComponent } from './herowars.component';
|
import { HerowarsComponent } from './herowars.component';
|
||||||
|
|
||||||
@@ -14,9 +16,10 @@ describe('HerowarsComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
provideAnimations(),
|
provideAnimations(),
|
||||||
provideNativeDateAdapter(),
|
provideNativeDateAdapter(),
|
||||||
|
provideHttpClient(),
|
||||||
|
provideHttpClientTesting(),
|
||||||
],
|
],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(HerowarsComponent);
|
fixture = TestBed.createComponent(HerowarsComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|||||||
@@ -18,10 +18,7 @@ import {
|
|||||||
MembersStatisticsComponent,
|
MembersStatisticsComponent,
|
||||||
} from '@components/shared';
|
} from '@components/shared';
|
||||||
import { Errors, HWMember } from '@models';
|
import { Errors, HWMember } from '@models';
|
||||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
import { HWDataService } from '@services';
|
||||||
//import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview -> Statistics | page Guild War -> Guild War
|
|
||||||
//import guildStatistics from 'src/files-data/hw-guild-statistics.json'; // page Overview -> Statistics
|
|
||||||
//import guildWarSlots from 'src/files-data/hw-guild-war-slots.json'; // no pages
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-herowars',
|
selector: 'app-herowars',
|
||||||
@@ -51,6 +48,7 @@ import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
|||||||
})
|
})
|
||||||
export class HerowarsComponent implements OnInit {
|
export class HerowarsComponent implements OnInit {
|
||||||
private _titleService = inject(Title);
|
private _titleService = inject(Title);
|
||||||
|
private _dataService = inject(HWDataService);
|
||||||
|
|
||||||
public title = 'HeroWars GM Tools';
|
public title = 'HeroWars GM Tools';
|
||||||
public description = 'Tools in working progress.';
|
public description = 'Tools in working progress.';
|
||||||
@@ -60,23 +58,20 @@ export class HerowarsComponent implements OnInit {
|
|||||||
private _guildMembers: HWMember[] = [];
|
private _guildMembers: HWMember[] = [];
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
try {
|
|
||||||
this._titleService.setTitle(this.title);
|
this._titleService.setTitle(this.title);
|
||||||
|
this._dataService.guildData$.subscribe({
|
||||||
|
next: (guildData) => {
|
||||||
for (const data of Object.entries(guildData.clan.members)) {
|
for (const data of Object.entries(guildData.clan.members)) {
|
||||||
const member: HWMember = {} as HWMember;
|
const member: HWMember = {} as HWMember;
|
||||||
Object.assign(member, data[1]);
|
Object.assign(member, data[1]);
|
||||||
if (guildData.clan.warriors.indexOf(parseInt(member.id)) !== -1) {
|
member.champion = guildData.clan.warriors.indexOf(parseInt(member.id)) !== -1;
|
||||||
member.champion = true;
|
|
||||||
} else {
|
|
||||||
member.champion = false;
|
|
||||||
}
|
|
||||||
member.heroes = { power: 0, teams: [] };
|
member.heroes = { power: 0, teams: [] };
|
||||||
member.titans = { power: 0, teams: [] };
|
member.titans = { power: 0, teams: [] };
|
||||||
this._guildMembers.push(member);
|
this._guildMembers.push(member);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
},
|
||||||
console.error(error);
|
error: (err) => console.error(err),
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getMembers(): HWMember[] {
|
getMembers(): HWMember[] {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { MenuItems } from '@components/shared';
|
|||||||
import { ListErrorsComponent } from '@components/shared';
|
import { ListErrorsComponent } from '@components/shared';
|
||||||
import { Errors, Qcm, QcmCategory, QcmQuestion, QcmQuestionState, User } from '@models';
|
import { Errors, Qcm, QcmCategory, QcmQuestion, QcmQuestionState, User } from '@models';
|
||||||
import { QcmService, UserService } from '@services';
|
import { QcmService, UserService } from '@services';
|
||||||
import data from 'src/qcm-bpa.json';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-qcm',
|
selector: 'app-qcm',
|
||||||
@@ -174,55 +173,6 @@ export class QcmComponent implements OnInit, OnDestroy {
|
|||||||
console.log('onSubmit');
|
console.log('onSubmit');
|
||||||
}
|
}
|
||||||
|
|
||||||
private _importChoices() {
|
|
||||||
try {
|
|
||||||
data.categories.forEach((category) => {
|
|
||||||
category.questions.forEach((question) => {
|
|
||||||
this._qcmService
|
|
||||||
.saveChoices(question)
|
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
||||||
.subscribe({
|
|
||||||
next: (question) => {
|
|
||||||
console.log('question : ', question);
|
|
||||||
//console.log(`Le saut n°${jump.numero} a été ajouté !`, 'OK');
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.log('err : ', err);
|
|
||||||
//console.log(`Le saut n'a pas été ajouté !`, 'Error', err);
|
|
||||||
this.errors = err;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _importQuestions() {
|
|
||||||
try {
|
|
||||||
data.categories.forEach((category) => {
|
|
||||||
//Object.assign(this.jump, category);
|
|
||||||
this._qcmService
|
|
||||||
.saveQuestions(category)
|
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
||||||
.subscribe({
|
|
||||||
next: (category) => {
|
|
||||||
console.log('category : ', category);
|
|
||||||
//console.log(`Le saut n°${jump.numero} a été ajouté !`, 'OK');
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.log('err : ', err);
|
|
||||||
//console.log(`Le saut n'a pas été ajouté !`, 'Error', err);
|
|
||||||
this.errors = err;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _resetErrors(): void {
|
private _resetErrors(): void {
|
||||||
this.errors = { errors: {} };
|
this.errors = { errors: {} };
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -1,4 +1,6 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
|
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
||||||
|
|
||||||
import { GuildCardComponent } from './guild-card.component';
|
import { GuildCardComponent } from './guild-card.component';
|
||||||
|
|
||||||
@@ -8,9 +10,9 @@ describe('GuildCardComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [GuildCardComponent]
|
imports: [GuildCardComponent],
|
||||||
})
|
providers: [provideHttpClient(), provideHttpClientTesting()],
|
||||||
.compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(GuildCardComponent);
|
fixture = TestBed.createComponent(GuildCardComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
|
||||||
import { HWGuildData, HWGuildClan, HWGuildStat } from '@models';
|
import { HWGuildData, HWGuildClan, HWGuildStat } from '@models';
|
||||||
|
import { HWDataService } from '@services';
|
||||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-guild-card',
|
selector: 'app-guild-card',
|
||||||
@@ -15,18 +14,34 @@ import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
|||||||
styleUrl: './guild-card.component.scss',
|
styleUrl: './guild-card.component.scss',
|
||||||
})
|
})
|
||||||
export class GuildCardComponent implements OnInit {
|
export class GuildCardComponent implements OnInit {
|
||||||
public guildData: HWGuildData = {} as HWGuildData;
|
private _dataService = inject(HWDataService);
|
||||||
|
|
||||||
|
public guildData: HWGuildData = {
|
||||||
|
clan: { warriors: [] as number[] } as unknown as HWGuildClan,
|
||||||
|
stat: {} as HWGuildStat,
|
||||||
|
slots: {},
|
||||||
|
membersStat: [],
|
||||||
|
serverResetTime: 0,
|
||||||
|
clanWarEndSeasonTime: 0,
|
||||||
|
freeClanChangeInterval: { start: 0, end: 0 },
|
||||||
|
giftUids: [],
|
||||||
|
};
|
||||||
private _guildClan: HWGuildClan = {} as HWGuildClan;
|
private _guildClan: HWGuildClan = {} as HWGuildClan;
|
||||||
private _guildStat: HWGuildStat = {} as HWGuildStat;
|
private _guildStat: HWGuildStat = {} as HWGuildStat;
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
Object.assign(this._guildClan, guildData.clan);
|
this._dataService.guildData$.subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
Object.assign(this._guildClan, data.clan);
|
||||||
this.guildData.clan = this._guildClan;
|
this.guildData.clan = this._guildClan;
|
||||||
Object.assign(this._guildStat, guildData.stat);
|
Object.assign(this._guildStat, data.stat);
|
||||||
this.guildData.stat = this._guildStat;
|
this.guildData.stat = this._guildStat;
|
||||||
this.guildData.serverResetTime = guildData.serverResetTime;
|
this.guildData.serverResetTime = data.serverResetTime;
|
||||||
this.guildData.clanWarEndSeasonTime = guildData.clanWarEndSeasonTime;
|
this.guildData.clanWarEndSeasonTime = data.clanWarEndSeasonTime;
|
||||||
this.guildData.freeClanChangeInterval = guildData.freeClanChangeInterval;
|
this.guildData.freeClanChangeInterval = data.freeClanChangeInterval;
|
||||||
this.guildData.giftUids = guildData.giftUids;
|
this.guildData.giftUids = data.giftUids;
|
||||||
|
},
|
||||||
|
error: (err) => console.error(err),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-31
@@ -13,8 +13,7 @@ import { MatStepperIntl, MatStepperModule } from '@angular/material/stepper';
|
|||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
|
||||||
import { HWGuildRaid, HWGuildRaidAttacker, HWGuildRaidAttackers, HWGuildRaidStage, HWMember } from '@models';
|
import { HWGuildRaid, HWGuildRaidAttacker, HWGuildRaidAttackers, HWGuildRaidStage, HWMember } from '@models';
|
||||||
|
import { HWDataService } from '@services';
|
||||||
import guildRaids from 'src/files-data/hw-guild-raids.json'; // page Asgard -> Guild Raid -> Log
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StepperIntl extends MatStepperIntl {
|
export class StepperIntl extends MatStepperIntl {
|
||||||
@@ -49,6 +48,7 @@ export class StepperIntl extends MatStepperIntl {
|
|||||||
})
|
})
|
||||||
export class GuildraidsLogComponent implements OnInit {
|
export class GuildraidsLogComponent implements OnInit {
|
||||||
private fb = inject(FormBuilder);
|
private fb = inject(FormBuilder);
|
||||||
|
private _dataService = inject(HWDataService);
|
||||||
|
|
||||||
public now: Date;
|
public now: Date;
|
||||||
public raidsForm: FormGroup;
|
public raidsForm: FormGroup;
|
||||||
@@ -107,18 +107,18 @@ export class GuildraidsLogComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.guildMembers.map((data) => {
|
this.guildMembers.map((data) => {
|
||||||
data.raids = [];
|
data.raids = [];
|
||||||
data.raidsInfo = {
|
data.raidsInfo = { variationAvg: 0, variationSum: 0 };
|
||||||
variationAvg: 0,
|
|
||||||
variationSum: 0,
|
|
||||||
};
|
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._dataService.guildRaids$.subscribe({
|
||||||
|
next: (guildRaids) => {
|
||||||
for (const member of Object.entries(guildRaids)) {
|
for (const member of Object.entries(guildRaids)) {
|
||||||
const index = this.guildMembers.findIndex((item) => item.id === member[0]);
|
const index = this.guildMembers.findIndex((item) => item.id === member[0]);
|
||||||
const memberRaids: HWGuildRaid[] = [];
|
const memberRaids: HWGuildRaid[] = [];
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
for (const data of Object.entries(member[1])) {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const data of Object.entries(member[1] as Record<string, any>)) {
|
||||||
const raid: HWGuildRaid = {} as HWGuildRaid;
|
const raid: HWGuildRaid = {} as HWGuildRaid;
|
||||||
Object.assign(raid, data[1]);
|
Object.assign(raid, data[1]);
|
||||||
const startTime: number = parseInt(raid.startTime) * 1000;
|
const startTime: number = parseInt(raid.startTime) * 1000;
|
||||||
@@ -133,14 +133,11 @@ export class GuildraidsLogComponent implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
raid.stage = this._raidStages[0];
|
raid.stage = this._raidStages[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
raid.damage = data[1].result.damage;
|
raid.damage = data[1].result.damage;
|
||||||
raid.level = data[1].result.level;
|
raid.level = data[1].result.level;
|
||||||
raid.userName = this.guildMembers[index].name;
|
raid.userName = this.guildMembers[index].name;
|
||||||
|
|
||||||
const attackers: HWGuildRaidAttackers = {} as HWGuildRaidAttackers;
|
const attackers: HWGuildRaidAttackers = {} as HWGuildRaidAttackers;
|
||||||
Object.assign(attackers, data[1].attackers);
|
Object.assign(attackers, data[1].attackers);
|
||||||
//Object.assign(raid.attackers, data[1].attackers);
|
|
||||||
raid.attackers = [];
|
raid.attackers = [];
|
||||||
raid.power = 0;
|
raid.power = 0;
|
||||||
for (const item of Object.entries(attackers)) {
|
for (const item of Object.entries(attackers)) {
|
||||||
@@ -168,39 +165,24 @@ export class GuildraidsLogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
value = raid.power - raid.stage.maxPower;
|
value = raid.power - raid.stage.maxPower;
|
||||||
}
|
}
|
||||||
raid.variation = {
|
raid.variation = { value, percent, color };
|
||||||
value: value,
|
|
||||||
percent: percent,
|
|
||||||
color: color,
|
|
||||||
};
|
|
||||||
raid.tooltip = Math.floor(raid.variation.value / 1000) + 'k';
|
raid.tooltip = Math.floor(raid.variation.value / 1000) + 'k';
|
||||||
//console.log(raid.attackers);
|
|
||||||
|
|
||||||
memberRaids.push(raid);
|
memberRaids.push(raid);
|
||||||
this._guildRaids.push(raid);
|
this._guildRaids.push(raid);
|
||||||
}
|
}
|
||||||
this.guildMembers[index].raids = memberRaids;
|
this.guildMembers[index].raids = memberRaids;
|
||||||
const varSum = memberRaids.reduce(
|
const varSum = memberRaids.reduce((acc, cur) => acc + cur.variation.percent, 0);
|
||||||
(accumulator, currentValue) => accumulator + currentValue.variation.percent,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
this.guildMembers[index].raidsInfo = {
|
this.guildMembers[index].raidsInfo = {
|
||||||
variationAvg: varSum / memberRaids.length,
|
variationAvg: varSum / memberRaids.length,
|
||||||
variationSum: varSum,
|
variationSum: varSum,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._guildRaids
|
this._guildRaids.sort((a, b) => (a.startTime < b.startTime ? -1 : 1));
|
||||||
.sort((a, b) => (a.startTime < b.startTime ? -1 : 1))
|
this.guildMembers.sort((a, b) => (a.raidsInfo.variationAvg > b.raidsInfo.variationAvg ? -1 : 1));
|
||||||
.map((data) => {
|
},
|
||||||
return data;
|
error: (err) => console.error(err),
|
||||||
});
|
});
|
||||||
this.guildMembers.sort((a, b) =>
|
|
||||||
a.raidsInfo.variationAvg > b.raidsInfo.variationAvg ? -1 : 1,
|
|
||||||
); /*.map((data) => {
|
|
||||||
console.log(data.name, data.raidsInfo.variationAvg, data.raids.length);
|
|
||||||
return data;
|
|
||||||
});*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMembers(): HWMember[] {
|
public getMembers(): HWMember[] {
|
||||||
|
|||||||
+5
-3
@@ -1,4 +1,6 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
|
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
||||||
|
|
||||||
import { GuildwarAttackComponent } from './guildwar-attack.component';
|
import { GuildwarAttackComponent } from './guildwar-attack.component';
|
||||||
|
|
||||||
@@ -8,9 +10,9 @@ describe('GuildwarAttackComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [GuildwarAttackComponent]
|
imports: [GuildwarAttackComponent],
|
||||||
})
|
providers: [provideHttpClient(), provideHttpClientTesting()],
|
||||||
.compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(GuildwarAttackComponent);
|
fixture = TestBed.createComponent(GuildwarAttackComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|||||||
+41
-21
@@ -1,4 +1,4 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit, inject } from '@angular/core';
|
||||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
@@ -14,12 +14,8 @@ import {
|
|||||||
HWGuildWarSlots,
|
HWGuildWarSlots,
|
||||||
HWMember,
|
HWMember,
|
||||||
} from '@models';
|
} from '@models';
|
||||||
|
import { HWDataService } from '@services';
|
||||||
/* JSON data */
|
import { combineLatest } from 'rxjs';
|
||||||
import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview -> Statistics | page Guild War -> Guild War
|
|
||||||
import guildWarInfo from 'src/files-data/hw-guild-war-info.json'; // page Guild War -> Guild War
|
|
||||||
//import guildWarLog from 'src/files-data/hw-guild-war-log.json'; // page Guild War -> Guild War
|
|
||||||
import guildWarSlots from 'src/files-data/hw-guild-war-slots.json'; // no pages
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-guildwar-attack',
|
selector: 'app-guildwar-attack',
|
||||||
@@ -28,8 +24,10 @@ import guildWarSlots from 'src/files-data/hw-guild-war-slots.json'; // no pages
|
|||||||
styleUrl: './guildwar-attack.component.scss',
|
styleUrl: './guildwar-attack.component.scss',
|
||||||
})
|
})
|
||||||
export class GuildwarAttackComponent implements OnInit {
|
export class GuildwarAttackComponent implements OnInit {
|
||||||
|
private _dataService = inject(HWDataService);
|
||||||
private _championsByPower: HWMember[] = [];
|
private _championsByPower: HWMember[] = [];
|
||||||
private _enemySlots: number[] = [];
|
private _enemySlots: number[] = [];
|
||||||
|
private _slots: HWGuildWarSlots = {};
|
||||||
public guildEnemies: HWMember[] = [];
|
public guildEnemies: HWMember[] = [];
|
||||||
public guildMembers: HWMember[] = [];
|
public guildMembers: HWMember[] = [];
|
||||||
public title = 'Fortifications';
|
public title = 'Fortifications';
|
||||||
@@ -49,18 +47,29 @@ export class GuildwarAttackComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
combineLatest([
|
||||||
|
this._dataService.guildWarData$,
|
||||||
|
this._dataService.guildWarInfo$,
|
||||||
|
this._dataService.guildWarSlots$,
|
||||||
|
]).subscribe({
|
||||||
|
next: ([guildWarData, guildWarInfo, guildWarSlotsData]) => {
|
||||||
|
this._slots = guildWarSlotsData.slots;
|
||||||
this.warInfo.day = parseInt(guildWarInfo.day);
|
this.warInfo.day = parseInt(guildWarInfo.day);
|
||||||
this.warInfo.clanEnemyName = guildWarInfo.enemyClan.title;
|
this.warInfo.clanEnemyName = guildWarInfo.enemyClan.title;
|
||||||
this.warInfo.endTime = guildWarInfo.endTime * 1000;
|
this.warInfo.endTime = guildWarInfo.endTime * 1000;
|
||||||
this.warInfo.nextWarTime = guildWarInfo.nextWarTime * 1000;
|
this.warInfo.nextWarTime = guildWarInfo.nextWarTime * 1000;
|
||||||
this.warInfo.nextLockTime = guildWarInfo.nextLockTime * 1000;
|
this.warInfo.nextLockTime = guildWarInfo.nextLockTime * 1000;
|
||||||
this._setChampionsByPower();
|
this._setChampionsByPower(guildWarData);
|
||||||
this._setEnemies();
|
this._setEnemies(guildWarInfo);
|
||||||
|
},
|
||||||
|
error: (err) => console.error(err),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getFortification(indexes: number[], type: string, name: string): HWGuildWarFortification {
|
private _getFortification(indexes: number[], type: string, name: string): HWGuildWarFortification {
|
||||||
const teams: HWMember[] = [];
|
const teams: HWMember[] = [];
|
||||||
const slots: HWGuildWarSlots = guildWarSlots.slots;
|
const slots: HWGuildWarSlots = this._slots;
|
||||||
|
if (!slots[name]) return { name, type, count: 0, teams: [], positions: this._enemySlots, slots: [] };
|
||||||
let count = 0;
|
let count = 0;
|
||||||
indexes.forEach((data) => {
|
indexes.forEach((data) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -88,7 +97,8 @@ export class GuildwarAttackComponent implements OnInit {
|
|||||||
|
|
||||||
private _getDefense(type: string, name: string): HWGuildWarFortification {
|
private _getDefense(type: string, name: string): HWGuildWarFortification {
|
||||||
const teams: HWMember[] = [];
|
const teams: HWMember[] = [];
|
||||||
const slots: HWGuildWarSlots = guildWarSlots.slots;
|
const slots: HWGuildWarSlots = this._slots;
|
||||||
|
if (!slots[name]) return { name, type, count: 0, teams: [], positions: this._enemySlots, slots: [] };
|
||||||
let count = 0;
|
let count = 0;
|
||||||
slots[name].forEach((slot) => {
|
slots[name].forEach((slot) => {
|
||||||
let enemies: HWMember[] = [];
|
let enemies: HWMember[] = [];
|
||||||
@@ -120,12 +130,15 @@ export class GuildwarAttackComponent implements OnInit {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setEnemies(): void {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
private _setEnemies(guildWarInfo: any): void {
|
||||||
const warriors: number[] = [];
|
const warriors: number[] = [];
|
||||||
for (const data of Object.entries(guildWarInfo.enemyClanTries)) {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const data of Object.entries(guildWarInfo.enemyClanTries as Record<string, any>)) {
|
||||||
warriors.push(parseInt(data[0]));
|
warriors.push(parseInt(data[0]));
|
||||||
}
|
}
|
||||||
for (const data of Object.entries(guildWarInfo.enemyClanMembers)) {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const data of Object.entries(guildWarInfo.enemyClanMembers as Record<string, any>)) {
|
||||||
const enemy: HWMember = {} as HWMember;
|
const enemy: HWMember = {} as HWMember;
|
||||||
Object.assign(enemy, data[1]);
|
Object.assign(enemy, data[1]);
|
||||||
if (warriors.indexOf(parseInt(enemy.id)) !== -1) {
|
if (warriors.indexOf(parseInt(enemy.id)) !== -1) {
|
||||||
@@ -141,16 +154,17 @@ export class GuildwarAttackComponent implements OnInit {
|
|||||||
this.guildEnemies.push(enemy);
|
this.guildEnemies.push(enemy);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const data of Object.entries(guildWarInfo.enemySlots)) {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const data of Object.entries(guildWarInfo.enemySlots as Record<string, any>)) {
|
||||||
const ennemySlot: HWGuildWarEnemySlot = {} as HWGuildWarEnemySlot;
|
const ennemySlot: HWGuildWarEnemySlot = {} as HWGuildWarEnemySlot;
|
||||||
Object.assign(ennemySlot, data[1]);
|
Object.assign(ennemySlot, data[1]);
|
||||||
//console.log(ennemySlot.slotId, ennemySlot.user.name, ennemySlot.user.id); //, ennemySlot.team["1"].power);
|
|
||||||
ennemySlot.teams = [];
|
ennemySlot.teams = [];
|
||||||
let totalHeroPower = 0;
|
let totalHeroPower = 0;
|
||||||
let totalTitanPower = 0;
|
let totalTitanPower = 0;
|
||||||
if (ennemySlot.user !== null) {
|
if (ennemySlot.user !== null) {
|
||||||
this._enemySlots[ennemySlot.slotId] = parseInt(ennemySlot.user.id);
|
this._enemySlots[ennemySlot.slotId] = parseInt(ennemySlot.user.id);
|
||||||
for (const team of Object.entries(data[1].team[0])) {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const team of Object.entries(data[1].team[0] as Record<string, any>)) {
|
||||||
/*
|
/*
|
||||||
ennemySlot.teams.push(enemyTeam);
|
ennemySlot.teams.push(enemyTeam);
|
||||||
console.log(enemyTeam);
|
console.log(enemyTeam);
|
||||||
@@ -194,8 +208,10 @@ export class GuildwarAttackComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setChampionsByPower(): void {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
for (const [teamId, teamValues] of Object.entries(guildWarData.teams)) {
|
private _setChampionsByPower(guildWarData: any): void {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const [teamId, teamValues] of Object.entries(guildWarData.teams as Record<string, any>)) {
|
||||||
const index = this.guildMembers.findIndex((member) => member.id === teamId);
|
const index = this.guildMembers.findIndex((member) => member.id === teamId);
|
||||||
if (index === -1) continue;
|
if (index === -1) continue;
|
||||||
let totalHeroPower = 0;
|
let totalHeroPower = 0;
|
||||||
@@ -203,11 +219,15 @@ export class GuildwarAttackComponent implements OnInit {
|
|||||||
const heroes: HWGuildWarHeroTeam[] = [];
|
const heroes: HWGuildWarHeroTeam[] = [];
|
||||||
const titans: HWGuildWarTitanTeam[] = [];
|
const titans: HWGuildWarTitanTeam[] = [];
|
||||||
|
|
||||||
for (const unit of Object.entries(teamValues.clanDefence_heroes.units)) {
|
for (const unit of Object.entries(
|
||||||
|
teamValues.clanDefence_heroes.units as Record<string, HWGuildWarHeroTeam>,
|
||||||
|
)) {
|
||||||
heroes.push(unit[1]);
|
heroes.push(unit[1]);
|
||||||
totalHeroPower += unit[1].power;
|
totalHeroPower += unit[1].power;
|
||||||
}
|
}
|
||||||
for (const unit of Object.entries(teamValues.clanDefence_titans.units)) {
|
for (const unit of Object.entries(
|
||||||
|
teamValues.clanDefence_titans.units as Record<string, HWGuildWarTitanTeam>,
|
||||||
|
)) {
|
||||||
titans.push(unit[1]);
|
titans.push(unit[1]);
|
||||||
totalTitanPower += unit[1].power;
|
totalTitanPower += unit[1].power;
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-13
@@ -1,4 +1,4 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit, inject } from '@angular/core';
|
||||||
//import { DecimalPipe } from '@angular/common';
|
//import { DecimalPipe } from '@angular/common';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
@@ -7,10 +7,8 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import { FortificationCardContentComponent } from '../fortification-card-content/fortification-card-content.component';
|
import { FortificationCardContentComponent } from '../fortification-card-content/fortification-card-content.component';
|
||||||
//import { HWMember } from '@models';
|
//import { HWMember } from '@models';
|
||||||
import { HWGuildWarFortification, HWGuildWarHeroTeam, HWGuildWarSlots, HWGuildWarTitanTeam, HWMember } from '@models';
|
import { HWGuildWarFortification, HWGuildWarHeroTeam, HWGuildWarSlots, HWGuildWarTitanTeam, HWMember } from '@models';
|
||||||
|
import { HWDataService } from '@services';
|
||||||
/* JSON data */
|
import { combineLatest } from 'rxjs';
|
||||||
import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview -> Statistics | page Guild War -> Guild War
|
|
||||||
import guildWarSlots from 'src/files-data/hw-guild-war-slots.json'; // no pages
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-guildwar-defence',
|
selector: 'app-guildwar-defence',
|
||||||
@@ -19,8 +17,10 @@ import guildWarSlots from 'src/files-data/hw-guild-war-slots.json'; // no pages
|
|||||||
styleUrl: './guildwar-defence.component.scss',
|
styleUrl: './guildwar-defence.component.scss',
|
||||||
})
|
})
|
||||||
export class GuildwarDefenceComponent implements OnInit {
|
export class GuildwarDefenceComponent implements OnInit {
|
||||||
|
private _dataService = inject(HWDataService);
|
||||||
private _championsByPower: HWMember[] = [];
|
private _championsByPower: HWMember[] = [];
|
||||||
private _championSlots: number[] = [];
|
private _championSlots: number[] = [];
|
||||||
|
private _slots: HWGuildWarSlots = {};
|
||||||
public guildMembers: HWMember[] = [];
|
public guildMembers: HWMember[] = [];
|
||||||
public teamType: string = '';
|
public teamType: string = '';
|
||||||
public title = 'Fortifications';
|
public title = 'Fortifications';
|
||||||
@@ -35,7 +35,11 @@ export class GuildwarDefenceComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
for (const [teamId, teamValues] of Object.entries(guildWarData.teams)) {
|
combineLatest([this._dataService.guildWarData$, this._dataService.guildWarSlots$]).subscribe({
|
||||||
|
next: ([guildWarData, guildWarSlotsData]) => {
|
||||||
|
this._slots = guildWarSlotsData.slots;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const [teamId, teamValues] of Object.entries(guildWarData.teams as Record<string, any>)) {
|
||||||
const index = this.guildMembers.findIndex((member) => member.id === teamId);
|
const index = this.guildMembers.findIndex((member) => member.id === teamId);
|
||||||
if (index === -1) continue;
|
if (index === -1) continue;
|
||||||
let totalHeroPower = 0;
|
let totalHeroPower = 0;
|
||||||
@@ -44,39 +48,45 @@ export class GuildwarDefenceComponent implements OnInit {
|
|||||||
const titans: HWGuildWarTitanTeam[] = [];
|
const titans: HWGuildWarTitanTeam[] = [];
|
||||||
this.guildMembers[index].heroes = { power: totalHeroPower, teams: heroes };
|
this.guildMembers[index].heroes = { power: totalHeroPower, teams: heroes };
|
||||||
this.guildMembers[index].titans = { power: totalTitanPower, teams: titans };
|
this.guildMembers[index].titans = { power: totalTitanPower, teams: titans };
|
||||||
|
for (const unit of Object.entries(
|
||||||
for (const unit of Object.entries(teamValues.clanDefence_heroes.units)) {
|
teamValues.clanDefence_heroes.units as Record<string, HWGuildWarHeroTeam>,
|
||||||
|
)) {
|
||||||
heroes.push(unit[1]);
|
heroes.push(unit[1]);
|
||||||
totalHeroPower += unit[1].power;
|
totalHeroPower += unit[1].power;
|
||||||
}
|
}
|
||||||
for (const unit of Object.entries(teamValues.clanDefence_titans.units)) {
|
for (const unit of Object.entries(
|
||||||
|
teamValues.clanDefence_titans.units as Record<string, HWGuildWarTitanTeam>,
|
||||||
|
)) {
|
||||||
titans.push(unit[1]);
|
titans.push(unit[1]);
|
||||||
totalTitanPower += unit[1].power;
|
totalTitanPower += unit[1].power;
|
||||||
}
|
}
|
||||||
this.guildMembers[index].heroes = { power: totalHeroPower, teams: heroes };
|
this.guildMembers[index].heroes = { power: totalHeroPower, teams: heroes };
|
||||||
this.guildMembers[index].titans = { power: totalTitanPower, teams: titans };
|
this.guildMembers[index].titans = { power: totalTitanPower, teams: titans };
|
||||||
}
|
}
|
||||||
for (const data of Object.entries(guildWarData.slots)) {
|
for (const data of Object.entries(guildWarData.slots as Record<string, number>)) {
|
||||||
this._championSlots[parseInt(data[0])] = data[1];
|
this._championSlots[parseInt(data[0])] = data[1];
|
||||||
}
|
}
|
||||||
switch (this.teamType) {
|
switch (this.teamType) {
|
||||||
case 'heroes':
|
case 'heroes':
|
||||||
this.title = 'Heroes Fortifications';
|
this.title = 'Heroes Fortifications';
|
||||||
this.guildMembers.sort((a, b) => (a.heroes.power > b.heroes.power ? -1 : 1)); // Descending
|
this.guildMembers.sort((a, b) => (a.heroes.power > b.heroes.power ? -1 : 1));
|
||||||
break;
|
break;
|
||||||
case 'titans':
|
case 'titans':
|
||||||
this.title = 'Titans Fortifications';
|
this.title = 'Titans Fortifications';
|
||||||
this.guildMembers.sort((a, b) => (a.titans.power > b.titans.power ? -1 : 1)); // Descending
|
this.guildMembers.sort((a, b) => (a.titans.power > b.titans.power ? -1 : 1));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this._championsByPower = this.guildMembers.filter((member) => member.champion === true);
|
this._championsByPower = this.guildMembers.filter((member) => member.champion === true);
|
||||||
|
},
|
||||||
|
error: (err) => console.error(err),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getFortification(indexes: number[], type: string, name: string): HWGuildWarFortification {
|
private _getFortification(indexes: number[], type: string, name: string): HWGuildWarFortification {
|
||||||
const teams: HWMember[] = [];
|
const teams: HWMember[] = [];
|
||||||
const slots: HWGuildWarSlots = guildWarSlots.slots;
|
const slots: HWGuildWarSlots = this._slots;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
indexes.forEach((data) => {
|
indexes.forEach((data) => {
|
||||||
const member = this._championsByPower[data];
|
const member = this._championsByPower[data];
|
||||||
|
|||||||
+16
-13
@@ -1,12 +1,11 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit, inject } from '@angular/core';
|
||||||
import { DecimalPipe } from '@angular/common';
|
import { DecimalPipe } from '@angular/common';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
|
||||||
import { HWGuildWarHeroTeam, HWGuildWarTitanTeam, HWMember } from '@models';
|
import { HWGuildWarHeroTeam, HWGuildWarTitanTeam, HWMember } from '@models';
|
||||||
|
import { HWDataService } from '@services';
|
||||||
import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview -> Statistics | page Guild War -> Guild War
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-guildwar-teams',
|
selector: 'app-guildwar-teams',
|
||||||
@@ -15,6 +14,7 @@ import guildWarData from 'src/files-data/hw-guild-war.json'; // page Overview ->
|
|||||||
styleUrl: './guildwar-teams.component.scss',
|
styleUrl: './guildwar-teams.component.scss',
|
||||||
})
|
})
|
||||||
export class GuildwarTeamsComponent implements OnInit {
|
export class GuildwarTeamsComponent implements OnInit {
|
||||||
|
private _dataService = inject(HWDataService);
|
||||||
private _championsByPower: HWMember[] = [];
|
private _championsByPower: HWMember[] = [];
|
||||||
public guildMembers: HWMember[] = [];
|
public guildMembers: HWMember[] = [];
|
||||||
public title = 'Members';
|
public title = 'Members';
|
||||||
@@ -32,29 +32,29 @@ export class GuildwarTeamsComponent implements OnInit {
|
|||||||
this.guildMembers
|
this.guildMembers
|
||||||
.sort((a, b) => ((a.heroes.power + a.titans.power) / 2 > (b.heroes.power + b.titans.power) / 2 ? -1 : 1))
|
.sort((a, b) => ((a.heroes.power + a.titans.power) / 2 > (b.heroes.power + b.titans.power) / 2 ? -1 : 1))
|
||||||
.map((data) => {
|
.map((data) => {
|
||||||
/*
|
|
||||||
this.guildTotalHeroesPower += data.heroes.power;
|
|
||||||
this.guildTotalTitansPower += data.titans.power;
|
|
||||||
this.guildAverageHeroesPower = Math.floor((this.guildTotalHeroesPower / this.guildMembers.length));
|
|
||||||
this.guildAverageTitansPower = Math.floor((this.guildTotalTitansPower / this.guildMembers.length));
|
|
||||||
*/
|
|
||||||
this._championsByPower.push(data);
|
this._championsByPower.push(data);
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const [teamId, teamValues] of Object.entries(guildWarData.teams)) {
|
this._dataService.guildWarData$.subscribe({
|
||||||
|
next: (guildWarData) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const [teamId, teamValues] of Object.entries(guildWarData.teams as Record<string, any>)) {
|
||||||
const index = this._championsByPower.findIndex((member) => member.id === teamId);
|
const index = this._championsByPower.findIndex((member) => member.id === teamId);
|
||||||
if (index === -1) continue;
|
if (index === -1) continue;
|
||||||
let totalHeroPower = 0;
|
let totalHeroPower = 0;
|
||||||
let totalTitanPower = 0;
|
let totalTitanPower = 0;
|
||||||
const heroes: HWGuildWarHeroTeam[] = [];
|
const heroes: HWGuildWarHeroTeam[] = [];
|
||||||
const titans: HWGuildWarTitanTeam[] = [];
|
const titans: HWGuildWarTitanTeam[] = [];
|
||||||
|
for (const unit of Object.entries(
|
||||||
for (const unit of Object.entries(teamValues.clanDefence_heroes.units)) {
|
teamValues.clanDefence_heroes.units as Record<string, HWGuildWarHeroTeam>,
|
||||||
|
)) {
|
||||||
heroes.push(unit[1]);
|
heroes.push(unit[1]);
|
||||||
totalHeroPower += unit[1].power;
|
totalHeroPower += unit[1].power;
|
||||||
}
|
}
|
||||||
for (const unit of Object.entries(teamValues.clanDefence_titans.units)) {
|
for (const unit of Object.entries(
|
||||||
|
teamValues.clanDefence_titans.units as Record<string, HWGuildWarTitanTeam>,
|
||||||
|
)) {
|
||||||
titans.push(unit[1]);
|
titans.push(unit[1]);
|
||||||
totalTitanPower += unit[1].power;
|
totalTitanPower += unit[1].power;
|
||||||
}
|
}
|
||||||
@@ -68,6 +68,9 @@ export class GuildwarTeamsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
this.guildAverageHeroesPower = Math.floor(this.guildTotalHeroesPower / this._championsByPower.length);
|
this.guildAverageHeroesPower = Math.floor(this.guildTotalHeroesPower / this._championsByPower.length);
|
||||||
this.guildAverageTitansPower = Math.floor(this.guildTotalTitansPower / this._championsByPower.length);
|
this.guildAverageTitansPower = Math.floor(this.guildTotalTitansPower / this._championsByPower.length);
|
||||||
|
},
|
||||||
|
error: (err) => console.error(err),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getChampionsByPower(): HWMember[] {
|
getChampionsByPower(): HWMember[] {
|
||||||
|
|||||||
+18
-28
@@ -1,14 +1,12 @@
|
|||||||
import { Component, Input, OnInit, inject } from '@angular/core';
|
import { Component, Input, OnInit, inject } from '@angular/core';
|
||||||
|
import { combineLatest } from 'rxjs';
|
||||||
import { DatePipe, DecimalPipe } from '@angular/common';
|
import { DatePipe, DecimalPipe } from '@angular/common';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
|
||||||
import { HWActivityStat, HWGuildClan, HWGuildData, HWMember, HWMemberStat, HWWeekStat } from '@models/herowars';
|
import { HWActivityStat, HWGuildClan, HWGuildData, HWMember, HWMemberStat, HWWeekStat } from '@models/herowars';
|
||||||
import { UtilitiesService } from '@services';
|
import { HWDataService, UtilitiesService } from '@services';
|
||||||
|
|
||||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
|
||||||
import guildStatistics from 'src/files-data/hw-guild-statistics.json'; // page Overview -> Statistics
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-members-statistics',
|
selector: 'app-members-statistics',
|
||||||
@@ -18,6 +16,7 @@ import guildStatistics from 'src/files-data/hw-guild-statistics.json'; // page O
|
|||||||
})
|
})
|
||||||
export class MembersStatisticsComponent implements OnInit {
|
export class MembersStatisticsComponent implements OnInit {
|
||||||
private _utilitiesService = inject(UtilitiesService);
|
private _utilitiesService = inject(UtilitiesService);
|
||||||
|
private _dataService = inject(HWDataService);
|
||||||
|
|
||||||
public guildMembers: HWMember[] = [];
|
public guildMembers: HWMember[] = [];
|
||||||
public title = 'Members';
|
public title = 'Members';
|
||||||
@@ -85,6 +84,8 @@ export class MembersStatisticsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
combineLatest([this._dataService.guildData$, this._dataService.guildStatistics$]).subscribe({
|
||||||
|
next: ([guildData, guildStatistics]) => {
|
||||||
const oneDayInSec = 24 * 60 * 60;
|
const oneDayInSec = 24 * 60 * 60;
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const daysToKick = parseInt(guildData.clan.daysToKick);
|
const daysToKick = parseInt(guildData.clan.daysToKick);
|
||||||
@@ -101,15 +102,14 @@ export class MembersStatisticsComponent implements OnInit {
|
|||||||
timeLeft = diff - daysLeft * oneDayInSec;
|
timeLeft = diff - daysLeft * oneDayInSec;
|
||||||
}
|
}
|
||||||
data.inactivity = {
|
data.inactivity = {
|
||||||
daysLeft: daysLeft,
|
daysLeft,
|
||||||
timeLeft: timeLeft,
|
timeLeft,
|
||||||
dropDelay: `${daysLeft}d, ${this._utilitiesService.secondsToDuration(timeLeft)}`,
|
dropDelay: `${daysLeft}d, ${this._utilitiesService.secondsToDuration(timeLeft)}`,
|
||||||
dropDate: Math.floor(exp.getTime() / 1000),
|
dropDate: Math.floor(exp.getTime() / 1000),
|
||||||
};
|
};
|
||||||
this._membersByName.push(data);
|
this._membersByName.push(data);
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.assign(this._guildClan, guildData.clan);
|
Object.assign(this._guildClan, guildData.clan);
|
||||||
this.guildData.clan = this._guildClan;
|
this.guildData.clan = this._guildClan;
|
||||||
this.guildData.membersStat = guildData.membersStat;
|
this.guildData.membersStat = guildData.membersStat;
|
||||||
@@ -118,15 +118,15 @@ export class MembersStatisticsComponent implements OnInit {
|
|||||||
const index = this._membersByName.findIndex((member) => member.id === item[1].id);
|
const index = this._membersByName.findIndex((member) => member.id === item[1].id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this._membersByName[index].adventureSum = item[1].adventureStat.reduce(
|
this._membersByName[index].adventureSum = item[1].adventureStat.reduce(
|
||||||
(accumulator, currentValue) => accumulator + currentValue,
|
(acc: number, cur: number) => acc + cur,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
this._membersByName[index].clanGiftsSum = item[1].clanGifts.reduce(
|
this._membersByName[index].clanGiftsSum = item[1].clanGifts.reduce(
|
||||||
(accumulator, currentValue) => accumulator + currentValue,
|
(acc: number, cur: number) => acc + cur,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
this._membersByName[index].clanWarSum = item[1].clanWarStat.reduce(
|
this._membersByName[index].clanWarSum = item[1].clanWarStat.reduce(
|
||||||
(accumulator, currentValue) => accumulator + currentValue,
|
(acc: number, cur: number) => acc + cur,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
this.guildSumTotal.adventure += this._membersByName[index].adventureSum;
|
this.guildSumTotal.adventure += this._membersByName[index].adventureSum;
|
||||||
@@ -135,34 +135,23 @@ export class MembersStatisticsComponent implements OnInit {
|
|||||||
const stat: HWWeekStat = {} as HWWeekStat;
|
const stat: HWWeekStat = {} as HWWeekStat;
|
||||||
Object.assign(stat, item[1]);
|
Object.assign(stat, item[1]);
|
||||||
this._membersByName[index].weekStat = stat;
|
this._membersByName[index].weekStat = stat;
|
||||||
} else {
|
|
||||||
console.log(item[1].id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const data of Object.entries(guildData.membersStat)) {
|
for (const data of Object.entries(guildData.membersStat)) {
|
||||||
const stat: HWMemberStat = {} as HWMemberStat;
|
const stat: HWMemberStat = {} as HWMemberStat;
|
||||||
Object.assign(stat, data[1]);
|
Object.assign(stat, data[1]);
|
||||||
const index = this._membersByName.findIndex((member) => member.id === data[1].userId);
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
if (index !== -1) {
|
const index = this._membersByName.findIndex((member) => member.id === (data[1] as any).userId);
|
||||||
|
if (index === -1) continue;
|
||||||
this._membersByName[index].stat = stat;
|
this._membersByName[index].stat = stat;
|
||||||
} else {
|
this._membersByName[index].score = stat.dungeonActivitySum + stat.activitySum + stat.prestigeSum;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
this._membersByName[index].score =
|
|
||||||
this._membersByName[index].stat.dungeonActivitySum +
|
|
||||||
this._membersByName[index].stat.activitySum +
|
|
||||||
this._membersByName[index].stat.prestigeSum;
|
|
||||||
this._membersByName[index].warGifts =
|
this._membersByName[index].warGifts =
|
||||||
((guildData.clan.giftsCount / 2) * ((this._membersByName[index].clanWarSum * 10) / 100)) / 20;
|
((guildData.clan.giftsCount / 2) * ((this._membersByName[index].clanWarSum * 10) / 100)) / 20;
|
||||||
|
|
||||||
this.guildTodayTotal.activity += stat.todayActivity;
|
this.guildTodayTotal.activity += stat.todayActivity;
|
||||||
this.guildTodayTotal.prestige += stat.todayPrestige;
|
this.guildTodayTotal.prestige += stat.todayPrestige;
|
||||||
this.guildTodayTotal.titanite += stat.todayDungeonActivity;
|
this.guildTodayTotal.titanite += stat.todayDungeonActivity;
|
||||||
this.guildTodayTotal.score +=
|
this.guildTodayTotal.score += stat.todayDungeonActivity + stat.todayActivity + stat.todayPrestige;
|
||||||
this._membersByName[index].stat.todayDungeonActivity +
|
|
||||||
this._membersByName[index].stat.todayActivity +
|
|
||||||
this._membersByName[index].stat.todayPrestige;
|
|
||||||
this.guildSumTotal.activity += stat.activitySum;
|
this.guildSumTotal.activity += stat.activitySum;
|
||||||
this.guildSumTotal.prestige += stat.prestigeSum;
|
this.guildSumTotal.prestige += stat.prestigeSum;
|
||||||
this.guildSumTotal.titanite += stat.dungeonActivitySum;
|
this.guildSumTotal.titanite += stat.dungeonActivitySum;
|
||||||
@@ -171,7 +160,6 @@ export class MembersStatisticsComponent implements OnInit {
|
|||||||
this._deviations.activity.push(stat.activitySum);
|
this._deviations.activity.push(stat.activitySum);
|
||||||
this._deviations.prestige.push(stat.prestigeSum);
|
this._deviations.prestige.push(stat.prestigeSum);
|
||||||
this._deviations.titanite.push(stat.dungeonActivitySum);
|
this._deviations.titanite.push(stat.dungeonActivitySum);
|
||||||
//this.guildSumTotal.warGifts += ((this._membersByName[index].score / this.guildSumTotal.score) * (guildData.clan.giftsCount / 2))
|
|
||||||
}
|
}
|
||||||
this.guildSumTotal.scoreGifts = guildData.clan.giftsCount - Math.floor(this.guildSumTotal.warGifts);
|
this.guildSumTotal.scoreGifts = guildData.clan.giftsCount - Math.floor(this.guildSumTotal.warGifts);
|
||||||
this.guildTodayAverages.activity = this.guildTodayTotal.activity / this._membersByName.length;
|
this.guildTodayAverages.activity = this.guildTodayTotal.activity / this._membersByName.length;
|
||||||
@@ -185,7 +173,6 @@ export class MembersStatisticsComponent implements OnInit {
|
|||||||
this.guildSumAverages.adventure = this.guildSumTotal.adventure / this._membersByName.length;
|
this.guildSumAverages.adventure = this.guildSumTotal.adventure / this._membersByName.length;
|
||||||
this.guildSumAverages.gifts = this.guildSumTotal.gifts / this._membersByName.length;
|
this.guildSumAverages.gifts = this.guildSumTotal.gifts / this._membersByName.length;
|
||||||
this.guildSumAverages.score = this.guildSumTotal.score / this._membersByName.length;
|
this.guildSumAverages.score = this.guildSumTotal.score / this._membersByName.length;
|
||||||
|
|
||||||
this._membersByName.map((data) => {
|
this._membersByName.map((data) => {
|
||||||
data.scoreGifts = (data.score / this.guildSumTotal.score) * this.guildSumTotal.scoreGifts;
|
data.scoreGifts = (data.score / this.guildSumTotal.score) * this.guildSumTotal.scoreGifts;
|
||||||
data.rewards = Math.floor(data.scoreGifts + data.warGifts);
|
data.rewards = Math.floor(data.scoreGifts + data.warGifts);
|
||||||
@@ -193,6 +180,9 @@ export class MembersStatisticsComponent implements OnInit {
|
|||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
this.guildSumAverages.rewards = this.guildSumTotal.rewards / this._membersByName.length;
|
this.guildSumAverages.rewards = this.guildSumTotal.rewards / this._membersByName.length;
|
||||||
|
},
|
||||||
|
error: (err) => console.error(err),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getMembersByName(): HWMember[] {
|
getMembersByName(): HWMember[] {
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ import {
|
|||||||
HWGuildClan,
|
HWGuildClan,
|
||||||
HWMember,
|
HWMember,
|
||||||
} from '@models';
|
} from '@models';
|
||||||
|
import { HWDataService } from './hw-data.service';
|
||||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class HWClanService {
|
export class HWClanService {
|
||||||
private apiService = inject(ApiService);
|
private apiService = inject(ApiService);
|
||||||
|
private _dataService = inject(HWDataService);
|
||||||
|
|
||||||
private _apiDomain = '/herowars';
|
private _apiDomain = '/herowars';
|
||||||
|
|
||||||
@@ -87,15 +87,18 @@ export class HWClanService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadClan(): HWGuildClan {
|
loadClan(): Observable<HWGuildClan> {
|
||||||
|
return this._dataService.guildData$.pipe(
|
||||||
|
map((guildData) => {
|
||||||
const guildClan: HWGuildClan = {} as HWGuildClan;
|
const guildClan: HWGuildClan = {} as HWGuildClan;
|
||||||
Object.assign(guildClan, guildData.clan);
|
Object.assign(guildClan, guildData.clan);
|
||||||
guildClan.sumAverages = this._resetActivity();
|
guildClan.sumAverages = this._resetActivity();
|
||||||
guildClan.sumTotal = this._resetActivity();
|
guildClan.sumTotal = this._resetActivity();
|
||||||
guildClan.todayAverages = this._resetActivity();
|
guildClan.todayAverages = this._resetActivity();
|
||||||
guildClan.todayTotal = this._resetActivity();
|
guildClan.todayTotal = this._resetActivity();
|
||||||
|
|
||||||
return guildClan;
|
return guildClan;
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadClanStats(clan: HWGuildClan, members: HWMember[]): HWGuildClan {
|
loadClanStats(clan: HWGuildClan, members: HWMember[]): HWGuildClan {
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { Injectable, inject } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { shareReplay } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { HWGuildData, HWGuildWarSlots, HWWeekStat } from '@models';
|
||||||
|
|
||||||
|
export interface HWGuildStatistics {
|
||||||
|
stat: (HWWeekStat & { id: string })[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class HWDataService {
|
||||||
|
private _http = inject(HttpClient);
|
||||||
|
|
||||||
|
readonly guildData$: Observable<HWGuildData> = this._http
|
||||||
|
.get<HWGuildData>('/assets/files-data/hw-guild-data.json')
|
||||||
|
.pipe(shareReplay(1));
|
||||||
|
|
||||||
|
readonly guildStatistics$: Observable<HWGuildStatistics> = this._http
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
.get<HWGuildStatistics>('/assets/files-data/hw-guild-statistics.json')
|
||||||
|
.pipe(shareReplay(1));
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
readonly guildRaids$: Observable<Record<string, Record<string, any>>> = this._http
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
.get<Record<string, Record<string, any>>>('/assets/files-data/hw-guild-raids.json')
|
||||||
|
.pipe(shareReplay(1));
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
readonly guildWarData$: Observable<any> = this._http
|
||||||
|
.get<any>('/assets/files-data/hw-guild-war.json')
|
||||||
|
.pipe(shareReplay(1));
|
||||||
|
|
||||||
|
readonly guildWarInfo$: Observable<any> = this._http
|
||||||
|
.get<any>('/assets/files-data/hw-guild-war-info.json')
|
||||||
|
.pipe(shareReplay(1));
|
||||||
|
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
|
readonly guildWarSlots$: Observable<{ slots: HWGuildWarSlots }> = this._http
|
||||||
|
.get<{ slots: HWGuildWarSlots }>('/assets/files-data/hw-guild-war-slots.json')
|
||||||
|
.pipe(shareReplay(1));
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Injectable, inject } from '@angular/core';
|
import { Injectable, inject } from '@angular/core';
|
||||||
import { HttpParams } from '@angular/common/http';
|
import { HttpParams } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { combineLatest, Observable } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ApiService, UtilitiesService } from '@services';
|
import { ApiService, UtilitiesService } from '@services';
|
||||||
@@ -14,13 +14,12 @@ import {
|
|||||||
HWMemberPageData,
|
HWMemberPageData,
|
||||||
HWMemberStat,
|
HWMemberStat,
|
||||||
} from '@models';
|
} from '@models';
|
||||||
|
import { HWDataService } from './hw-data.service';
|
||||||
import guildData from 'src/files-data/hw-guild-data.json'; // page Membres
|
|
||||||
import guildStatistics from 'src/files-data/hw-guild-statistics.json'; // page Overview -> Statistics
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class HWMemberService {
|
export class HWMemberService {
|
||||||
private _apiService = inject(ApiService);
|
private _apiService = inject(ApiService);
|
||||||
private _utilitiesService = inject(UtilitiesService);
|
private _utilitiesService = inject(UtilitiesService);
|
||||||
|
private _dataService = inject(HWDataService);
|
||||||
|
|
||||||
private _apiDomain = '/herowars';
|
private _apiDomain = '/herowars';
|
||||||
|
|
||||||
@@ -76,7 +75,9 @@ export class HWMemberService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMembers(clan: HWGuildClan): HWMember[] {
|
loadMembers(clan: HWGuildClan): Observable<HWMember[]> {
|
||||||
|
return combineLatest([this._dataService.guildData$, this._dataService.guildStatistics$]).pipe(
|
||||||
|
map(([guildData, guildStatistics]) => {
|
||||||
const guildMembers: HWMember[] = [];
|
const guildMembers: HWMember[] = [];
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const oneDayInSec = 24 * 60 * 60;
|
const oneDayInSec = 24 * 60 * 60;
|
||||||
@@ -84,11 +85,7 @@ export class HWMemberService {
|
|||||||
for (const data of Object.entries(guildData.clan.members)) {
|
for (const data of Object.entries(guildData.clan.members)) {
|
||||||
const member: HWMember = {} as HWMember;
|
const member: HWMember = {} as HWMember;
|
||||||
Object.assign(member, data[1]);
|
Object.assign(member, data[1]);
|
||||||
if (guildData.clan.warriors.indexOf(parseInt(member.id)) !== -1) {
|
member.champion = guildData.clan.warriors.indexOf(parseInt(member.id)) !== -1;
|
||||||
member.champion = true;
|
|
||||||
} else {
|
|
||||||
member.champion = false;
|
|
||||||
}
|
|
||||||
member.heroes = { power: 0, teams: [] };
|
member.heroes = { power: 0, teams: [] };
|
||||||
member.titans = { power: 0, teams: [] };
|
member.titans = { power: 0, teams: [] };
|
||||||
guildMembers.push(member);
|
guildMembers.push(member);
|
||||||
@@ -109,12 +106,10 @@ export class HWMemberService {
|
|||||||
dropDate: Math.floor(exp.getTime() / 1000),
|
dropDate: Math.floor(exp.getTime() / 1000),
|
||||||
};
|
};
|
||||||
data.raids = [];
|
data.raids = [];
|
||||||
data.raidsInfo = {
|
data.raidsInfo = { variationAvg: 0, variationSum: 0 };
|
||||||
variationAvg: 0,
|
|
||||||
variationSum: 0,
|
|
||||||
};
|
|
||||||
data.stat = {} as HWMemberStat;
|
data.stat = {} as HWMemberStat;
|
||||||
let index = guildData.membersStat.findIndex((stat) => stat.userId === data.id);
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
let index = guildData.membersStat.findIndex((stat) => (stat as any).userId === data.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
||||||
const { userId, ...memberStatWithoutUserId } = guildData.membersStat[index] as any;
|
const { userId, ...memberStatWithoutUserId } = guildData.membersStat[index] as any;
|
||||||
@@ -128,15 +123,15 @@ export class HWMemberService {
|
|||||||
Object.assign(stat, weekStatSource);
|
Object.assign(stat, weekStatSource);
|
||||||
data.weekStat = stat;
|
data.weekStat = stat;
|
||||||
data.adventureSum = guildStatistics.stat[index].adventureStat.reduce(
|
data.adventureSum = guildStatistics.stat[index].adventureStat.reduce(
|
||||||
(accumulator, currentValue) => accumulator + currentValue,
|
(acc: number, cur: number) => acc + cur,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
data.clanGiftsSum = guildStatistics.stat[index].clanGifts.reduce(
|
data.clanGiftsSum = guildStatistics.stat[index].clanGifts.reduce(
|
||||||
(accumulator, currentValue) => accumulator + currentValue,
|
(acc: number, cur: number) => acc + cur,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
data.clanWarSum = guildStatistics.stat[index].clanWarStat.reduce(
|
data.clanWarSum = guildStatistics.stat[index].clanWarStat.reduce(
|
||||||
(accumulator, currentValue) => accumulator + currentValue,
|
(acc: number, cur: number) => acc + cur,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -145,14 +140,14 @@ export class HWMemberService {
|
|||||||
data.clanGiftsSum = 0;
|
data.clanGiftsSum = 0;
|
||||||
data.clanWarSum = 0;
|
data.clanWarSum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.score = data.stat.dungeonActivitySum + data.stat.activitySum + data.stat.prestigeSum;
|
data.score = data.stat.dungeonActivitySum + data.stat.activitySum + data.stat.prestigeSum;
|
||||||
data.warGifts = ((clan.giftsCount / 2) * ((data.clanWarSum * 10) / 100)) / 20;
|
data.warGifts = ((clan.giftsCount / 2) * ((data.clanWarSum * 10) / 100)) / 20;
|
||||||
data.scoreGifts = 0;
|
data.scoreGifts = 0;
|
||||||
data.rewards = 0;
|
data.rewards = 0;
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
|
|
||||||
return guildMembers;
|
return guildMembers;
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
export * from './hw-clan.service';
|
export * from './hw-clan.service';
|
||||||
|
export * from './hw-data.service';
|
||||||
export * from './hw-member.service';
|
export * from './hw-member.service';
|
||||||
Executable
+1128
File diff suppressed because it is too large
Load Diff
Executable
+69955
File diff suppressed because it is too large
Load Diff
+277
@@ -0,0 +1,277 @@
|
|||||||
|
{
|
||||||
|
"stat": [
|
||||||
|
{
|
||||||
|
"id": "276065239",
|
||||||
|
"activity": [5772, 4182, 4060, 6246, 5354, 7454, 8662],
|
||||||
|
"dungeonActivity": [375, 375, 375, 375, 375, 375, 375],
|
||||||
|
"adventureStat": [0, 10, 0, 0, 0, 0, 0],
|
||||||
|
"clanWarStat": [2, 0, 2, 2, 0, 0, 0],
|
||||||
|
"prestigeStat": [4370, 4600, 4770, 4370, 4270, 4650, 4370],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276066337",
|
||||||
|
"activity": [108, 1998, 2396, 1938, 12976, 3122, 2884],
|
||||||
|
"dungeonActivity": [150, 454, 519, 504, 694, 874, 688],
|
||||||
|
"adventureStat": [0, 1, 3, 0, 1, 11, 1],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [0, 4840, 5000, 4670, 5000, 5080, 4460],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276067105",
|
||||||
|
"activity": [5712, 12358, 5314, 3972, 19208, 19986, 6186],
|
||||||
|
"dungeonActivity": [527, 75, 1052, 491, 405, 577, 301],
|
||||||
|
"adventureStat": [1, 1, 2, 2, 1, 5, 1],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [4310, 3900, 4410, 4410, 4330, 4330, 4340],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276071624",
|
||||||
|
"activity": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"dungeonActivity": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"adventureStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276077824",
|
||||||
|
"activity": [6458, 23290, 36592, 4746, 4338, 7508, 2196],
|
||||||
|
"dungeonActivity": [1639, 1300, 1243, 774, 789, 1456, 893],
|
||||||
|
"adventureStat": [2, 2, 4, 0, 4, 11, 0],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [5000, 5000, 6590, 3720, 5000, 5020, 4670],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276088477",
|
||||||
|
"activity": [4840, 6912, 4670, 5240, 21956, 64, 4738],
|
||||||
|
"dungeonActivity": [435, 435, 435, 435, 510, 0, 435],
|
||||||
|
"adventureStat": [1, 2, 1, 1, 1, 0, 7],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [4360, 3860, 3730, 4130, 5810, 50, 3910],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276091174",
|
||||||
|
"activity": [5420, 2910, 1750, 1750, 1466, 1740, 1460],
|
||||||
|
"dungeonActivity": [234, 152, 159, 152, 159, 152, 159],
|
||||||
|
"adventureStat": [1, 2, 4, 1, 5, 1, 1],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [5790, 3550, 3540, 3570, 2690, 2640, 2670],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276091473",
|
||||||
|
"activity": [2880, 6436, 7460, 4246, 6546, 5510, 7466],
|
||||||
|
"dungeonActivity": [225, 225, 75, 225, 225, 225, 225],
|
||||||
|
"adventureStat": [1, 2, 1, 2, 3, 3, 10],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [3630, 4370, 4440, 4340, 4190, 4130, 3970],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276098983",
|
||||||
|
"activity": [3334, 3118, 1138, 1758, 16872, 20794, 1018],
|
||||||
|
"dungeonActivity": [3090, 1216, 1576, 3796, 2476, 4443, 4482],
|
||||||
|
"adventureStat": [1, 3, 1, 3, 1, 13, 1],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [5010, 4610, 4180, 4960, 4210, 4430, 4010],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276123996",
|
||||||
|
"activity": [850, 1890, 2070, 3450, 2250, 2470, 5530],
|
||||||
|
"dungeonActivity": [75, 369, 234, 322, 526, 166, 448],
|
||||||
|
"adventureStat": [1, 1, 1, 5, 0, 8, 1],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [2180, 3890, 2860, 4310, 3190, 3460, 3540],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276125516",
|
||||||
|
"activity": [4184, 16714, 2491, 998, 10314, 1094, 12612],
|
||||||
|
"dungeonActivity": [795, 167, 343, 75, 435, 75, 435],
|
||||||
|
"adventureStat": [1, 1, 0, 0, 0, 0, 31],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [4670, 4290, 4080, 3740, 4050, 3860, 4600],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276135490",
|
||||||
|
"activity": [11056, 850, 1150, 850, 2938, 226, 850],
|
||||||
|
"dungeonActivity": [330, 420, 90, 75, 165, 75, 75],
|
||||||
|
"adventureStat": [3, 1, 0, 0, 0, 0, 6],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [3310, 3160, 1090, 3270, 2960, 1600, 3150],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276140072",
|
||||||
|
"activity": [290, 1900, 1130, 3624, 5202, 454, 3016],
|
||||||
|
"dungeonActivity": [0, 165, 165, 165, 165, 75, 165],
|
||||||
|
"adventureStat": [0, 3, 1, 3, 0, 1, 8],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [110, 3770, 3720, 4320, 3830, 3190, 4150],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276173310",
|
||||||
|
"activity": [4730, 5502, 4194, 4024, 3798, 9262, 3942],
|
||||||
|
"dungeonActivity": [315, 735, 225, 225, 225, 225, 225],
|
||||||
|
"adventureStat": [3, 2, 1, 6, 2, 1, 5],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 0, 0, 0],
|
||||||
|
"prestigeStat": [4440, 4210, 3750, 4110, 3820, 3710, 3550],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276183485",
|
||||||
|
"activity": [1956, 4446, 13694, 3216, 7316, 4180, 2086],
|
||||||
|
"dungeonActivity": [4480, 1707, 1380, 1384, 1151, 0, 338],
|
||||||
|
"adventureStat": [2, 11, 2, 0, 0, 0, 6],
|
||||||
|
"clanWarStat": [0, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [5000, 5000, 5060, 5160, 3590, 100, 4370],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276201648",
|
||||||
|
"activity": [4458, 2858, 3488, 2288, 30380, 4518, 2088],
|
||||||
|
"dungeonActivity": [225, 225, 225, 225, 225, 225, 225],
|
||||||
|
"adventureStat": [1, 4, 1, 0, 10, 4, 1],
|
||||||
|
"clanWarStat": [0, 0, 2, 2, 0, 0, 0],
|
||||||
|
"prestigeStat": [5000, 4710, 4390, 4370, 4600, 4600, 4600],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276202599",
|
||||||
|
"activity": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"dungeonActivity": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"adventureStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "276204664",
|
||||||
|
"activity": [6590, 3550, 2380, 1510, 57752, 24950, 2850],
|
||||||
|
"dungeonActivity": [609, 507, 209, 587, 630, 489, 225],
|
||||||
|
"adventureStat": [1, 3, 1, 3, 1, 13, 1],
|
||||||
|
"clanWarStat": [0, 2, 0, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [4520, 4600, 2300, 4140, 6900, 4140, 4040],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "277175311",
|
||||||
|
"activity": [180, 960, 880, 180, 2572, 190, 180],
|
||||||
|
"dungeonActivity": [75, 388, 388, 388, 388, 388, 388],
|
||||||
|
"adventureStat": [0, 1, 0, 0, 0, 0, 0],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [2280, 3900, 3700, 3540, 3720, 3540, 3540],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "283734465",
|
||||||
|
"activity": [3342, 4762, 4560, 2942, 13418, 15438, 10040],
|
||||||
|
"dungeonActivity": [375, 375, 375, 375, 374, 377, 375],
|
||||||
|
"adventureStat": [1, 1, 1, 1, 3, 3, 1],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [4180, 4500, 4500, 4260, 4340, 4340, 4340],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "283942135",
|
||||||
|
"activity": [2426, 2402, 3980, 3080, 24900, 16498, 4640],
|
||||||
|
"dungeonActivity": [411, 523, 555, 555, 555, 555, 536],
|
||||||
|
"adventureStat": [1, 4, 1, 1, 4, 3, 10],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [4060, 5740, 4260, 4600, 4450, 4880, 4480],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "284997421",
|
||||||
|
"activity": [0, 4718, 724, 1198, 1394, 2588, 0],
|
||||||
|
"dungeonActivity": [240, 150, 150, 75, 75, 300, 0],
|
||||||
|
"adventureStat": [0, 2, 4, 0, 2, 9, 1],
|
||||||
|
"clanWarStat": [2, 0, 2, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [1020, 5000, 4380, 3580, 3900, 7280, 380],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "284998229",
|
||||||
|
"activity": [880, 3980, 1900, 2298, 8258, 11062, 1602],
|
||||||
|
"dungeonActivity": [360, 495, 435, 510, 360, 510, 150],
|
||||||
|
"adventureStat": [2, 2, 4, 2, 1, 4, 9],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [2300, 4690, 4600, 6240, 2400, 6480, 2540],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "285266598",
|
||||||
|
"activity": [3680, 2030, 5370, 4500, 31484, 21878, 4366],
|
||||||
|
"dungeonActivity": [219, 249, 419, 354, 255, 240, 946],
|
||||||
|
"adventureStat": [1, 1, 0, 0, 21, 7, 0],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [2240, 2990, 3870, 4670, 4100, 3860, 3960],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "285405675",
|
||||||
|
"activity": [5050, 2394, 4350, 4316, 4356, 57802, 3830],
|
||||||
|
"dungeonActivity": [435, 435, 435, 435, 435, 435, 435],
|
||||||
|
"adventureStat": [1, 2, 2, 2, 3, 1, 4],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [4600, 5000, 5000, 5000, 5000, 5000, 5000],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "286288116",
|
||||||
|
"activity": [3800, 12890, 2750, 2610, 2156, 15670, 2700],
|
||||||
|
"dungeonActivity": [603, 569, 449, 564, 574, 454, 519],
|
||||||
|
"adventureStat": [2, 4, 3, 2, 1, 3, 4],
|
||||||
|
"clanWarStat": [0, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [4600, 4600, 4600, 4600, 4600, 4600, 5000],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "286289402",
|
||||||
|
"activity": [8036, 18022, 7664, 4806, 19456, 21418, 4970],
|
||||||
|
"dungeonActivity": [555, 390, 562, 490, 568, 591, 575],
|
||||||
|
"adventureStat": [1, 1, 1, 1, 1, 1, 6],
|
||||||
|
"clanWarStat": [0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"prestigeStat": [4600, 4600, 4440, 4600, 4520, 4600, 4600],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "286549064",
|
||||||
|
"activity": [1394, 2146, 2080, 2080, 1412, 1830, 3610],
|
||||||
|
"dungeonActivity": [225, 75, 225, 435, 225, 225, 225],
|
||||||
|
"adventureStat": [2, 2, 5, 1, 2, 5, 3],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [4500, 4500, 4620, 4290, 4110, 4000, 4070],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "286570009",
|
||||||
|
"activity": [0, 1378, 5354, 534, 6360, 13142, 1732],
|
||||||
|
"dungeonActivity": [0, 1097, 962, 1421, 555, 1095, 1035],
|
||||||
|
"adventureStat": [0, 2, 3, 3, 4, 3, 1],
|
||||||
|
"clanWarStat": [0, 2, 2, 0, 2, 0, 0],
|
||||||
|
"prestigeStat": [0, 4250, 4420, 4270, 4090, 4600, 3840],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "287684146",
|
||||||
|
"activity": [6250, 11810, 3250, 2220, 16950, 21110, 3952],
|
||||||
|
"dungeonActivity": [675, 735, 675, 675, 675, 225, 675],
|
||||||
|
"adventureStat": [3, 3, 1, 1, 4, 1, 11],
|
||||||
|
"clanWarStat": [2, 2, 2, 2, 2, 0, 0],
|
||||||
|
"prestigeStat": [5050, 5450, 4860, 4720, 5800, 2970, 6970],
|
||||||
|
"clanGifts": [0, 0, 0, 0, 0, 0, 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"today": "202678",
|
||||||
|
"dayInWeek": "5",
|
||||||
|
"giftsCount": 338
|
||||||
|
}
|
||||||
Executable
+12069
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"slots": {
|
||||||
|
"Mage Academy": [1, 2, 31],
|
||||||
|
"Lighthouse": [3, 4, 32],
|
||||||
|
"Barracks": [5, 6, 33],
|
||||||
|
"Foundry": [13, 14, 15, 36],
|
||||||
|
"Citadel": [25, 26, 27, 28, 29, 30, 40],
|
||||||
|
"Bridge": [7, 8, 9, 34],
|
||||||
|
"Bastion Of Ice": [22, 23, 24, 39],
|
||||||
|
"Bastion Of Fire": [19, 20, 21, 38],
|
||||||
|
"Gates Of Nature": [16, 17, 18, 37],
|
||||||
|
"Spring Of Elements": [10, 11, 12, 35]
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+4995
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user