-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: war win streak announcer (#248)
- Loading branch information
Showing
8 changed files
with
235 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* @param {import('postgres').Sql} sql | ||
*/ | ||
export async function up(sql) { | ||
await sql.unsafe(` | ||
CREATE TABLE war_win_streak_announcement | ||
( | ||
id SERIAL PRIMARY KEY, | ||
clan_tag TEXT NOT NULL, | ||
current_win_streak INTEGER NOT NULL DEFAULT 0, | ||
guild_id TEXT NOT NULL, | ||
channel_id TEXT NOT NULL, | ||
enabled BOOLEAN DEFAULT TRUE, | ||
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), | ||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() | ||
); | ||
`); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { ApplyOptions } from '@sapphire/decorators'; | ||
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; | ||
import { Result } from '@sapphire/result'; | ||
import type { Clan, HTTPError as COCHttpError } from 'clashofclans.js'; | ||
import { RESTJSONErrorCodes, Routes } from 'discord-api-types/v10'; | ||
import { bold, EmbedBuilder, Status } from 'discord.js'; | ||
import type { HTTPError } from 'discord.js'; | ||
import { logInfo, logWarning } from '#utils/functions/logging'; | ||
|
||
@ApplyOptions<ScheduledTask.Options>({ | ||
pattern: '*/2 * * * *', | ||
customJobOptions: { | ||
removeOnComplete: true, | ||
removeOnFail: true | ||
} | ||
}) | ||
export class WarStreakAnnouncer extends ScheduledTask { | ||
#winStreakMessages = [ | ||
'What a powerhouse! #NAME is on fire with a #STREAK win streak. Keep the wins rolling in!', | ||
'Incredible teamwork pays off! #NAME is celebrating a #STREAK war win streak. GG!', | ||
'Talk about domination! #NAME secures a #STREAK win streak. Next stop: greatness!', | ||
"Victory dance time! #NAME just locked in a #STREAK streak. Let's go!" | ||
]; | ||
|
||
#winStreakColors = [0xff4500, 0x32cd32, 0x1e90ff, 0xffd700]; | ||
|
||
public override async run() { | ||
if (this.container.client.ws.status !== Status.Ready) { | ||
return; | ||
} | ||
|
||
const data = await this.sql<WarStreakAnnouncerData[]>`SELECT clan_tag, | ||
channel_id, | ||
current_win_streak | ||
FROM war_win_streak_announcement | ||
WHERE enabled = true`; | ||
|
||
if (!data) { | ||
return; | ||
} | ||
|
||
for (const x of data) { | ||
await this.announceWarStreak(x); | ||
} | ||
} | ||
|
||
private async announceWarStreak(data: WarStreakAnnouncerData) { | ||
const clan = await this.getClan(data.clanTag, data.channelId); | ||
if (!clan) { | ||
return; | ||
} | ||
|
||
// Don't want to send the message if the streak is 0 or the same as the last streak | ||
// Streak is incremental, can never be the same value again without going down first | ||
if (clan.warWinStreak === 0 || clan.warWinStreak === data.currentWinStreak) { | ||
return; | ||
} | ||
|
||
const streakMessage = this.#winStreakMessages[Math.floor(Math.random() * this.#winStreakMessages.length)] | ||
.replace('#NAME', bold(clan.name)) | ||
.replace('#STREAK', bold(`${clan.warWinStreak}`)); | ||
|
||
const streakEmbed = new EmbedBuilder() | ||
.setDescription(streakMessage) | ||
.setColor(this.#winStreakColors[Math.floor(Math.random() * this.#winStreakColors.length)]) | ||
.setThumbnail(clan.badge.medium); | ||
|
||
const result = await Result.fromAsync<unknown, HTTPError>(async () => | ||
this.client.rest.post(Routes.channelMessages(data.channelId), { | ||
body: { embeds: [streakEmbed.toJSON()] } | ||
}) | ||
); | ||
|
||
if (result.isErr()) { | ||
const error = result.unwrapErr(); | ||
if ( | ||
[ | ||
RESTJSONErrorCodes.MissingAccess, | ||
RESTJSONErrorCodes.MissingPermissions, | ||
RESTJSONErrorCodes.UnknownMessage | ||
].includes(error.status) | ||
) { | ||
await this.stopWarStreakAnnouncer(data.clanTag, data.channelId); | ||
this.logger.info( | ||
logInfo( | ||
'War Streak Announcer', | ||
`Stopping war streak announcement for ${data.clanTag} with reason ${error.message}` | ||
) | ||
); | ||
return; | ||
} | ||
|
||
this.logger.warn( | ||
logWarning( | ||
'War Streak Announcer', | ||
`Failed to announce war streak for ${data.clanTag} with reason ${error.message}` | ||
) | ||
); | ||
} else { | ||
await this.sql`UPDATE war_win_streak_announcement | ||
SET current_win_streak = ${clan.warWinStreak} | ||
WHERE clan_tag = ${data.clanTag} AND channel_id = ${data.channelId}`; | ||
} | ||
} | ||
|
||
/** | ||
* Get clan information from the clan tag. | ||
* Stops the clan embed if clan not found and logs it | ||
* | ||
* @param clanTag - Clan Tag to get information for | ||
* @param channelId - Channel ID where the clan board is running | ||
*/ | ||
private async getClan(clanTag: string, channelId: string) { | ||
const result = await Result.fromAsync<Clan, COCHttpError>(async () => this.coc.getClan(clanTag)); | ||
|
||
if (result.isErr() && result.unwrapErr().status === 404) { | ||
await this.stopWarStreakAnnouncer(clanTag, channelId); | ||
this.logger.info( | ||
logInfo('ClanEmbed Syncer', `Stopping clan embed for ${clanTag} with reason Clan not found`) | ||
); | ||
return; | ||
} | ||
|
||
return result.unwrap(); | ||
} | ||
|
||
private async stopWarStreakAnnouncer(clanTag: string, channelId: string) { | ||
await this.sql`UPDATE war_win_streak_announcement | ||
SET enabled = false | ||
WHERE clan_tag = ${clanTag} AND channel_id = ${channelId}`; | ||
} | ||
} | ||
|
||
type WarStreakAnnouncerData = { | ||
channelId: string; | ||
clanTag: string; | ||
currentWinStreak: number; | ||
}; |