Skip to content

Commit

Permalink
Basic support for a checking command for TTT Level 9
Browse files Browse the repository at this point in the history
  • Loading branch information
gausie committed Nov 25, 2023
1 parent b56dfb2 commit 05ed048
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/commands/kol/__fixtures__/automated_future.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<html><head><script language=Javascript><!--if (parent.frames.length == 0) location.href="game.php";//--></script><script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/keybinds.min.2.js"></script><script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/window.20111231.js"></script><script language="javascript">function chatFocus(){if(top.chatpane.document.chatform.graf) top.chatpane.document.chatform.graf.focus();}if (typeof defaultBind != 'undefined') { defaultBind(47, 2, chatFocus); defaultBind(190, 2, chatFocus);defaultBind(191, 2, chatFocus); defaultBind(47, 8, chatFocus);defaultBind(190, 8, chatFocus); defaultBind(191, 8, chatFocus); }</script><script language="javascript">function updateParseItem(iid, field, info) {var tbl = $('#ic'+iid);var data = parseItem(tbl);if (!data) return;data[field] = info;var out = [];for (i in data) {if (!data.hasOwnProperty(i)) continue;out.push(i+'='+data[i]);}tbl.attr('rel', out.join('&'));}function parseItem(tbl) {tbl = $(tbl);var rel = tbl.attr('rel');var data = {};if (!rel) return data;var parts = rel.split('&');for (i in parts) {if (!parts.hasOwnProperty(i)) continue;var kv = parts[i].split('=');tbl.data(kv[0], kv[1]);data[kv[0]] = kv[1];}return data;}</script><script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/jquery-1.3.1.min.js"></script><script type="text/javascript" src="https://d2uyhvukfffg5a.cloudfront.net/scripts/pop_query.20230713.js"></script><script type="text/javascript"> function pop_ircm(clicked) { return false; } </script> <link rel="stylesheet" type="text/css" href="https://d2uyhvukfffg5a.cloudfront.net/styles.20230117d.css"><style type='text/css'>.faded {zoom: 1;filter: alpha(opacity=35);opacity: 0.35;-khtml-opacity: 0.35;-moz-opacity: 0.35;}</style></head><body><centeR><table width=95% cellspacing=0 cellpadding=0><tr><td style="color: white;" align=center bgcolor=blue><b>The Time-Twitching Tower</b></td></tr><tr><td style="padding: 5px; border: 1px solid blue;"><center><table><tr><td><center><div id=background style='position: relative; width:575px;height:1750px' ><img id="place_bg" src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/twitch_bookground9.gif" width=575 height=1750 border=0><div id=twitch_bank class="element" style=' position: absolute; top: 850; left: 128; height: 160; width: 155;'><a href=place.php?whichplace=twitch&action=twitch_bank><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=155 height=160 border=0 alt="First Third Four-Fifths Bank of the West" title="First Third Four-Fifths Bank of the West"></a></div><div id=twitch_bearsign class="element" style='text-align: center; position: absolute; top: 133; left: 338; height: 15; width: 100;'><a style='text-decoration: none; font-size: 11px; padding: 10px; display: block' alt='001001028' title='001001028' href=adventure.php?snarfblat=582><div class="pp"><div><img alt="001001028" title="001001028" src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/1.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/1.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/2.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/8.gif" height="10" border="0" /></div></div></a></div><div id=twitch_boat1 class="element" style=' position: absolute; top: 602; left: 31; height: 200; width: 100;'><a href=shop.php?whichshop=nina><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=100 height=200 border=0 alt="The Ni&ntilde;a" title="The Ni&ntilde;a"></a></div><div id=twitch_boat2 class="element" style=' position: absolute; top: 602; left: 147; height: 200; width: 200;'><a href=place.php?whichplace=twitch&action=twitch_boat2><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=200 height=200 border=0 alt="The Pinta" title="The Pinta"></a></div><div id=twitch_boat3 class="element" style=' position: absolute; top: 602; left: 360; height: 200; width: 100;'><a href=place.php?whichplace=twitch&action=twitch_boat3><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=100 height=200 border=0 alt="The Santa Claus" title="The Santa Claus"></a></div><div id=twitch_colosseum class="element" style=' position: absolute; top: 1206; left: 305; height: 190; width: 180;'><a href=place.php?whichplace=twitch&action=twitch_colosseum><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=180 height=190 border=0 alt="The Chariot-Racing Colosseum" title="The Chariot-Racing Colosseum"></a></div><div id=twitch_constore class="element" style=' position: absolute; top: 305; left: 290; height: 70; width: 50;'><a href=shop.php?whichshop=conmerch><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=50 height=70 border=0 alt="KoL Con 13 Merch Table" title="KoL Con 13 Merch Table"></a></div><div id=twitch_dancave1 class="element" style=' position: absolute; top: 1692; left: 388; height: 55; width: 55;'><a href=place.php?whichplace=twitch&action=twitch_dancave1><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=55 height=55 border=0 alt="A Cave" title="A Cave"></a></div><div id=twitch_future1 class="element" style=' position: absolute; top: 23; left: 6; height: 180; width: 150;'><a href=adventure.php?snarfblat=581><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=150 height=180 border=0 alt="Spring Bros. Solenoids (1)" title="Spring Bros. Solenoids (1)"></a></div><div id=twitch_future2 class="element" style=' position: absolute; top: 30; left: 310; height: 180; width: 160;'><a href=adventure.php?snarfblat=582><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=160 height=180 border=0 alt="Botsmann Bearings (1)" title="Botsmann Bearings (1)"></a></div><div id=twitch_future3 class="element" style=' position: absolute; top: 48; left: 202; height: 100; width: 100;'><a href=adventure.php?snarfblat=580><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=100 height=100 border=0 alt="Home of the Future (1)" title="Home of the Future (1)"></a></div><div id=twitch_mallstore class="element" style=' position: absolute; top: 1088; left: 366; height: 100; width: 80;'><a href=shop.php?whichshop=applestore><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=80 height=100 border=0 alt="The Applecalypse Store" title="The Applecalypse Store"></a></div><div id=twitch_mallzone class="element" style=' position: absolute; top: 1120; left: 217; height: 70; width: 100;'><a href=adventure.php?snarfblat=418><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=100 height=70 border=0 alt="The Post-Mall (1)" title="The Post-Mall (1)"></a></div><div id=twitch_shakeshop class="element" style=' position: absolute; top: 508; left: 62; height: 93; width: 70;'><a href=shop.php?whichshop=shakeshop><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=70 height=93 border=0 alt="Ye Newe Souvenir Shoppe" title="Ye Newe Souvenir Shoppe"></a></div><div id=twitch_shoerepair class="element" style=' position: absolute; top: 1552; left: 427; height: 45; width: 35;'><a href=place.php?whichplace=twitch&action=twitch_shoerepair><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=35 height=45 border=0 alt="Shoe Repair Store" title="Shoe Repair Store"></a></div><div id=twitch_solsign class="element" style='text-align: center; position: absolute; top: 122; left: 27; height: 15; width: 100;'><a style='text-decoration: none; font-size: 11px; padding: 10px; display: block' alt='001001268' title='001001268' href=adventure.php?snarfblat=581><div class="pp"><div><img alt="001001268" title="001001268" src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/1.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/0.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/1.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/2.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/6.gif" height="10" border="0" /><img alt='' src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/zonefont_neg/8.gif" height="10" border="0" /></div></div></a></div><div id=twitch_store1 class="element" style=' position: absolute; top: 1692; left: 277; height: 59; width: 86;'><a href=shop.php?whichshop=caveshop><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/neandermall.gif" width=86 height=59 border=0 alt="The Neandermall" title="The Neandermall"></a></div><div id=twitch_survivors class="element" style=' position: absolute; top: 1108; left: 76; height: 80; width: 90;'><a href=place.php?whichplace=twitch&action=twitch_survivors><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=90 height=80 border=0 alt="Post-Apocalyptic Survivor Camp" title="Post-Apocalyptic Survivor Camp"></a></div><div id=twitch_votingbooth class="element" style=' position: absolute; top: 1664; left: -7; height: 80; width: 80;'><a href=place.php?whichplace=twitch&action=twitch_votingbooth><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=80 height=80 border=0 alt="Twitch Tower Voting Booth" title="Twitch Tower Voting Booth"></a></div><div id=twitch_zone1 class="element" style=' position: absolute; top: 1655; left: 148; height: 100; width: 100;'><a href=adventure.php?snarfblat=410><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=100 height=100 border=0 alt="The Cave Before Time (1)" title="The Cave Before Time (1)"></a></div><div id=twitch_zone2a class="element" style=' position: absolute; top: 1435; left: 16; height: 160; width: 175;'><a href=adventure.php?snarfblat=411><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=175 height=160 border=0 alt="An Illicit Bohemian Party (1)" title="An Illicit Bohemian Party (1)"></a></div><div id=twitch_zone2b class="element" style=' position: absolute; top: 1435; left: 193; height: 160; width: 170;'><a href=adventure.php?snarfblat=412><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=170 height=160 border=0 alt="Moonshiners' Woods (1)" title="Moonshiners' Woods (1)"></a></div><div id=twitch_zone3 class="element" style=' position: absolute; top: 1206; left: 60; height: 190; width: 240;'><a href=adventure.php?snarfblat=414><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=240 height=190 border=0 alt="The Roman Forum (1)" title="The Roman Forum (1)"></a></div><div id=twitch_zone4 class="element" style=' position: absolute; top: 851; left: 25; height: 160; width: 100;'><a href=adventure.php?snarfblat=422><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=100 height=160 border=0 alt="The Rowdy Saloon (1)" title="The Rowdy Saloon (1)"></a></div><div id=twitch_zone5 class="element" style=' position: absolute; top: 881; left: 342; height: 130; width: 130;'><a href=adventure.php?snarfblat=423><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=130 height=130 border=0 alt="The Spooky Old Abandoned Mine" title="The Spooky Old Abandoned Mine"></a></div><div id=twitch_zone6 class="element" style=' position: absolute; top: 511; left: 212; height: 95; width: 70;'><a href=adventure.php?snarfblat=453><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=70 height=95 border=0 alt="Globe Theatre Main Stage (1)" title="Globe Theatre Main Stage (1)"></a></div><div id=twitch_zone7 class="element" style=' position: absolute; top: 508; left: 358; height: 95; width: 80;'><a href=adventure.php?snarfblat=454><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=80 height=95 border=0 alt="Globe Theatre Backstage (1)" title="Globe Theatre Backstage (1)"></a></div><div id=twitch_zone8 class="element" style=' position: absolute; top: 301; left: 398; height: 80; width: 50;'><a href=adventure.php?snarfblat=475><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=50 height=80 border=0 alt="12 West Main (1)" title="12 West Main (1)"></a></div><div id=twitch_zone9 class="element" style=' position: absolute; top: 256; left: 50; height: 120; width: 150;'><a href=adventure.php?snarfblat=476><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/1x1trans.gif" width=150 height=120 border=0 alt="KoL Con Clan Party House (1)" title="KoL Con Clan Party House (1)"></a></div></div><p><a href=town.php>Back to Seaside Town</a></center></td></tr></table></center></td></tr><tr><td height=4></td></tr></table></center></body></html>
19 changes: 19 additions & 0 deletions src/commands/kol/automatedfuture.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect, test } from "vitest";

import { loadFixture } from "../../testUtils.js";
import { parseScores } from "./automatedfuture.js";

test("Can read scores", async () => {
const page = await loadFixture(__dirname, "automated_future.html");

const scores = parseScores(page);

expect(scores).toHaveProperty("solenoids", 1001268);
expect(scores).toHaveProperty("bearings", 1001028);
});

test("Returns null if scores cannot be read", () => {
const scores = parseScores("");

expect(scores).toBe(null);
});
79 changes: 79 additions & 0 deletions src/commands/kol/automatedfuture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {
ChatInputCommandInteraction,
SlashCommandBuilder,
bold,
} from "discord.js";

import { createEmbed } from "../../clients/discord.js";
import { kolClient } from "../../clients/kol.js";

export const data = new SlashCommandBuilder()
.setName("automatedfuture")
.setDescription("Find information about the current TTT Level 9 status");

async function visitTTT(): Promise<string> {
return await kolClient.actionMutex.runExclusive(async () => {
return kolClient.visitUrl("place.php?whichplace=twitch");
});
}

export function parseScores(page: string) {
const pattern = /title='(\d+)' href=adventure.php\?snarfblat=(581|582)/gs;
const matches = [...page.matchAll(pattern)];

if (matches.length != 2) return null;

const scores = matches.reduce(
(acc, m) => ({ ...acc, [m[2]]: Number(m[1]) }),
{} as Record<string, number>,
);

return {
solenoids: scores["581"] ?? 0,
bearings: scores["582"] ?? 0,
};
}

const numberFormat = new Intl.NumberFormat();

const formatWinner = (predicate: boolean, text: string) =>
predicate ? bold(text) : text;

export async function execute(interaction: ChatInputCommandInteraction) {
interaction.deferReply();

const page = await visitTTT();

if (page.includes("faded back into the swirling mists"))
return void (await interaction.editReply(
"The Time-Twitch Tower has faded back into the swirling mists.",
));

const scores = parseScores(page);

if (!scores)
return void (await interaction.editReply(
"I wasn't able to read the current scores",
));

const embed = createEmbed().setTitle(`Automated Future`);

embed.addFields([
{
name: formatWinner(
scores.solenoids > scores.bearings,
"Spring Bros. Solenoids",
),
value: numberFormat.format(scores.solenoids),
},
{
name: formatWinner(
scores.bearings > scores.solenoids,
"Boltsmann Bearings",
),
value: numberFormat.format(scores.bearings),
},
]);

interaction.editReply({ content: null, embeds: [embed] });
}

0 comments on commit 05ed048

Please sign in to comment.