import { Ennoblement, ServerConfig, TWHelpClient } from './lib/twhelp'; import { createTranslationFunc } from './utils'; import { DialogTable } from './common/dialog-table'; import { calcLoyalty } from './lib/tw'; import { Cache } from './lib/cache'; const t = createTranslationFunc({ pl_PL: { 'Show ennoblements': 'Pokaż przejęcia', 'Date/time': 'Data/czas', Village: 'Wioska', 'Old owner': 'Stary właściciel', 'New owner': 'Nowy właściciel', Points: 'Punkty', Barbarian: 'Barbarzyńska', 'Ennobled at': 'Ostatnio przejęta', Unknown: 'Nieznany', Loyalty: 'Poparcie', Never: 'Nigdy', }, }); class TWHelpConnector { private static SERVER_CONFIG_CACHE_KEY = 'extended_village_profile_server_config'; private cache = new Cache(localStorage); constructor( private readonly client: TWHelpClient, private readonly version: string, private readonly server: string, private readonly id: number ) {} serverConfig() { return this.cache.load( TWHelpConnector.SERVER_CONFIG_CACHE_KEY, 3600, () => { return this.client.serverConfig(this.version, this.server); } ); } async latestEnnoblement() { const ennoblements = await this.client.villageEnnoblements( this.version, this.server, this.id, { limit: 1, sort: ['createdAt:DESC'], } ); return ennoblements.data.length > 0 ? ennoblements.data[0] : null; } villageEnnoblements(page: number, limit: number) { return this.client.villageEnnoblements(this.version, this.server, this.id, { offset: (page - 1) * limit, limit, sort: ['createdAt:desc'], }); } } enum DialogId { ENNOBLEMENTS = 'extended_village_profile_ennoblements', } class UI { constructor( private readonly config: ServerConfig, private readonly ennoblement: Ennoblement | null, private readonly connector: TWHelpConnector ) {} render() { this.renderAdditionalInfo(); this.renderActions(); } private renderAdditionalInfo() { const tbody = document.querySelector('#embedmap_village')?.closest('tbody'); if (!(tbody instanceof HTMLTableSectionElement)) { return; } tbody.insertAdjacentHTML( 'beforeend', ` ${t('Ennobled at')}: ${ this.ennoblement ? new Date(this.ennoblement.createdAt).toLocaleString() : t('Never') } ${t('Loyalty')}: ${calcLoyalty( this.ennoblement?.createdAt ?? 0, this.config.speed )} ` ); } private renderActions() { const tbody = document .querySelector('#content_value a[href*="twstats"]') ?.closest('tbody'); if (!(tbody instanceof HTMLTableSectionElement)) { return; } [ { name: t('Show ennoblements'), handler: this.showEnnoblements.bind(this), }, ].forEach(({ name, handler }) => { const tr = document.createElement('tr'); const td = document.createElement('td'); td.colSpan = 2; const a = document.createElement('a'); a.innerText = name; a.href = '#'; a.addEventListener('click', handler); td.appendChild(a); tr.appendChild(td); tbody.appendChild(tr); }); } private async showEnnoblements(e: Event) { e.preventDefault(); await new DialogTable( DialogId.ENNOBLEMENTS, [ { header: t('Village'), accessor: (e) => `${e.village.fullName}`, }, { header: t('Points'), accessor: (e) => e.points.toLocaleString(), }, { header: t('Old owner'), accessor: ({ village: { player } }) => { if (!player) { return t('Barbarian'); } return `${player.name}${ player.tribe ? ` (${player.tribe.tag})` : '' }`; }, }, { header: t('New owner'), accessor: ({ newOwner }) => { if (!newOwner) { return t('Unknown'); } return `${newOwner.name}${ newOwner.tribe ? ` (${newOwner.tribe.tag})` : '' }`; }, }, { header: t('Date/time'), accessor: (e) => new Date(e.createdAt).toLocaleString(), }, ], 30, (page: number, limit: number) => { return this.connector.villageEnnoblements(page, limit); } ).render(); } } class ExtendedVillageProfile { connector: TWHelpConnector; constructor(client: TWHelpClient) { this.connector = new TWHelpConnector( client, window.game_data.market, window.game_data.world, this.getVillageId() ); } async run() { const [config, ennoblement] = await Promise.all([ this.connector.serverConfig(), this.connector.latestEnnoblement(), ]); new UI(config, ennoblement, this.connector).render(); } private getVillageId() { const str = new URLSearchParams(window.location.search).get('id'); if (!str) { return 0; } return parseInt(str); } } (async () => { if ( window.game_data.screen !== 'info_village' || window.game_data.mode !== null ) { return; } await new ExtendedVillageProfile( new TWHelpClient(process.env.TWHELP_API_BASE_URL ?? '') ) .run() .catch((err) => { console.log(err); }); })();