diff --git a/package-lock.json b/package-lock.json index a4d67bb..ad32ec0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "denim_3001", - "version": "3001.61.3", + "version": "3001.62.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "denim_3001", - "version": "3001.61.2", + "version": "3001.62.0", "license": "ISC", "dependencies": { "@discordjs/voice": "^0.17.0", diff --git a/package.json b/package.json index 14b2b57..edbd7ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "denim_3001", - "version": "3001.61.3", + "version": "3001.62.0", "description": "Toto je velmi kvalitní bot.", "repository": { "url": "https://github.com/Histmy/Denim-Bot/" diff --git a/res/sachy/game.html b/res/sachy/game.html new file mode 100644 index 0000000..6d74a94 --- /dev/null +++ b/res/sachy/game.html @@ -0,0 +1,40 @@ + + + + + + + Hra - $domena + + + + + +

Hra

+ +

$pecko

+ + + $hra +
+ + + diff --git a/src/modules/sachy.ts b/src/modules/sachy.ts index ee3364b..e6d7713 100644 --- a/src/modules/sachy.ts +++ b/src/modules/sachy.ts @@ -98,7 +98,7 @@ function jeCheck(barva: Hra["hraje"], deska: Deska) { // od pawnů [7, 9].forEach(i => { const pis = deska[index - i]; - if (pis?.typ == "pawn" && pis.barva != barva) check = true; + if (pis?.typ == "pawn" && pocetKeStrane[index][i == 7 ? 1 : 3] > 0 && pis.barva != barva) check = true; }); // od králika @@ -173,6 +173,13 @@ function tahyProPawny(index: number, deska: Deska) { if (index % 8 != 7 && deska[index - 7] && deska[index - 7]!.barva != barva) tahy.push(index - 7); + // en croassant + if (pocetKeStrane[index][3] > 0 && deska[index - 1]?.enPassantovatelna) + tahy.push(index - 9); + + if (pocetKeStrane[index][1] > 0 && deska[index + 1]?.enPassantovatelna) + tahy.push(index - 7); + // Blokáda if (deska[index - 8]) return tahy; @@ -183,13 +190,6 @@ function tahyProPawny(index: number, deska: Deska) { if (deska[index]?.netahnuta && !deska[index - 16]) tahy.push(index - 16); - // en croassant - if (deska[index - 1]?.enPassantovatelna) - tahy.push(index - 9); - - if (deska[index + 1]?.enPassantovatelna) - tahy.push(index - 7); - return tahy; } @@ -218,6 +218,8 @@ function tahyProKrale(index: number, deska: Deska) { break; } + if (Math.abs(i) == 3) continue; + const novaDeska = [...deska]; novaDeska[index + i] = deska[index]; novaDeska[index] = undefined; @@ -302,6 +304,45 @@ function renderHra(hra: Hra, konec?: true) { const deska = [...hra.deska]; const vybranejPis = hra.vybranejPis; + const policka: Policko[] = []; + + hra.tahy = []; + + if (typeof vybranejPis == "number") hra.tahy = legalniTahy(vybranejPis, deska); + + for (let i = 0; i < 64; i++) { + + const figurka = deska[i]; + const jeTah = hra.tahy.includes(i); + + const cernyPozadi = (Math.floor(i / 8) + (i % 8)) % 2; + + if (!figurka) { + + policka.push(jeTah + ? { typ: "tahnutelne", emoutId: cernyPozadi ? "1066376051422404628" : "1066376343807336488" } + : { typ: "prazdne", barva: cernyPozadi ? "cerna" : "bila" } + ); + + } else { + + let klic = (cernyPozadi ? "g" : "w") + (figurka.barva == "bila" ? "w" : "b") + figurka.typ; + if (jeTah) klic += "t"; + else if (figurka.typ == "king" && figurka.barva == hra.hraje && jeCheck(figurka.barva, deska)) klic += "c"; + const emoutId = fokinLookupTable[klic]; + + const tahnutelny = !konec && figurka.barva == hra.hraje || jeTah; + policka.push({ emoutId, typ: tahnutelny ? "tahnutelne" : "figurka" }); + + } + + } + + return policka; +} + +function generateGameEmbed(hra: Hra, konec?: true) { + const embed: APIEmbed = { fields: [ { @@ -317,51 +358,64 @@ function renderHra(hra: Hra, konec?: true) { ] }; - hra.tahy = []; - - if (typeof vybranejPis == "number") hra.tahy = legalniTahy(vybranejPis, deska); + const policka = renderHra(hra, konec); for (let i = 0; i < 64; i++) { - const figurka = deska[i]; - const klikanec = klikance[i]; - - const prvniDuhy = (i % 8) < 4 ? 0 : 1; - const field = embed.fields![prvniDuhy]; - - const cernyPozadi = (Math.floor(i / 8) + (i % 8)) % 2; - - if (!figurka) { - - field.value += hra.tahy.includes(i) - ? (cernyPozadi ? `[<:h:1066376051422404628>](http://${sachyDomena}/${klikanec})` : `[<:h:1066376343807336488>](http://${sachyDomena}/${klikanec})`) - : (cernyPozadi ? "🟩" : "⬜"); - - } else { - - let klic = (cernyPozadi ? "g" : "w") + (figurka.barva == "bila" ? "w" : "b") + figurka.typ; - if (hra.tahy.includes(i)) klic += "t"; - if (figurka.typ == "king" && figurka.barva == hra.hraje && jeCheck(figurka.barva, deska)) klic += "c"; - const emout = fokinLookupTable[klic]; - const figurkaStr = `<:h:${emout}>`; - - if (!konec && figurka.barva == hra.hraje || hra.tahy.includes(i)) { - field.value += `[${figurkaStr}](http://${sachyDomena}/${klikanec})`; - } else { - field.value += figurkaStr; - } + const policko = policka[i]; + const field = embed.fields![(i % 8) < 4 ? 0 : 1]; + if (policko.typ == "prazdne") + field.value += policko.barva == "bila" ? "⬜" : "🟩"; + else { + const emout = `<:h:${policko.emoutId}>`; + field.value += policko.typ == "figurka" ? emout : `[${emout}](http://${sachyDomena}/${klikance[i]})`; } - if (i % 8 == 3 || i % 8 == 7) field.value += "\n"; + if ((i % 8 == 3 || i % 8 == 7)) field.value += "\n"; + } + if (embed.fields![0].value.length > 1024 || embed.fields![1].value.length > 1024) { + embed.fields = [ + { + name: "a je to pici!", + value: `Tuta pozice by vobsahovala moc vodkazu a diky pice diskordu se teda neda vykreslit. Tuten tah budes muset bohuzel vodehrat [na webu](http://${sachyDomena}/play).` + } + ]; } return embed; } +emiter.on("render", (hrac, respond) => { + const gameID = hraci.get(hrac)!; + if (!gameID) return respond("Však vůbec nehraješ ty magore", true); + const hra = hry.get(gameID)!; + const hraje = hra.hraje == (hra.bila == hrac ? "bila" : "cerna"); + + const policka = renderHra(hra); + let html = ""; + + + for (let i = 0; i < 64; i++) { + const policko = policka[i]; + + if (policko.typ == "prazdne") + html += policko.barva == "bila" ? `` : ``; + else { + const obrazek = ``; + html += (policko.typ == "figurka" || !hraje) ? `${obrazek}` : `${obrazek}`; + } + + if (i % 8 == 7) html += ""; + } + + respond(html); + +}); + function konec(mes: Message, hra: Hra, duvod: string) { - mes.edit({ content: `hra zkoncila ${duvod}`, embeds: [renderHra(hra, true)] }); + mes.edit({ content: `hra zkoncila ${duvod}`, embeds: [generateGameEmbed(hra, true)] }); const gameID = hra.id; @@ -399,7 +453,7 @@ function prekreslitHru(hra: Hra) { if (pat) return konec(mes, hra, `achylova sytuace`); - mes.edit({ content: "", embeds: [renderHra(hra)] }); + mes.edit({ content: "", embeds: [generateGameEmbed(hra)] }); } emiter.on("tah", (hrac, policko, respond, promo) => { @@ -412,7 +466,7 @@ emiter.on("tah", (hrac, policko, respond, promo) => { const index = klikance.findIndex(e => e == policko); - if (typeof index != "number") return respond("Co to meleš za hovna?"); + if (index == -1) return respond("Co to meleš za hovna?"); // Kliknul na stejnej pis if (hra.vybranejPis == index) { @@ -485,7 +539,7 @@ const exp: Modul = { hraci.set(mes.author.id, nextGameID); hraci.set(druhej, nextGameID); - message.edit({ content: "", embeds: [renderHra(hra)] }); + message.edit({ content: "", embeds: [generateGameEmbed(hra)] }); } }, @@ -510,7 +564,7 @@ type Hra = { bila: string; cerna: string; deska: Deska; - hraje: "bila" | "cerna"; + hraje: Figurka["barva"]; tahy: number[]; vybranejPis?: number; message: Message; @@ -524,3 +578,11 @@ type Figurka = { netahnuta: boolean; enPassantovatelna: boolean; }; + +type Policko = { + typ: "prazdne"; + barva: Figurka["barva"]; +} | { + typ: "figurka" | "tahnutelne"; + emoutId: string; +}; diff --git a/src/utils/sachyServer.ts b/src/utils/sachyServer.ts index 32b0c01..aa208de 100644 --- a/src/utils/sachyServer.ts +++ b/src/utils/sachyServer.ts @@ -14,11 +14,13 @@ const indexStranka = readFileSync(`${basePath}/index.html`).toString(); const tahStranka = readFileSync(`${basePath}/tah.html`).toString(); const promoStranka = readFileSync(`${basePath}/promotion.html`).toString(); const chybaStranka = readFileSync(`${basePath}/error.html`).toString(); +const hraStranka = readFileSync(`${basePath}/game.html`).toString(); export const sachyDomena = process.env.sachyDomena ?? "šach.ml"; interface Eventy { tah: (playerId: string, square: string, verify: (err?: string) => void, promotionType?: string) => void; + render: (playerId: string, send: (html: string, err?: true) => void) => void; } export const emiter = new TypedEmitter(); @@ -101,9 +103,9 @@ function loginErr(res: ServerResponse) { ); } -async function overeni(url: string, session: Session, res: ServerResponse) { +async function overeni(url: URL, session: Session, res: ServerResponse) { - const code = (new URL(url, "h:/")).searchParams.get("code"); + const code = url.searchParams.get("code"); const data = await fetch("https://discord.com/api/v10/oauth2/token", { method: "post", body: `client_id=1064269692165963826&client_secret=8HHKODmb1HTLWoJGVyoinSU_9323dEla&grant_type=authorization_code&code=${code}&redirect_uri=http%3A%2F%2F${encodeURIComponent(sachyDomena)}%2Foauth`, headers: { "Content-type": "application/x-www-form-urlencoded" } }) .then(r => r.json()) .catch(err => log("sachy jednotka:", err)); @@ -146,16 +148,48 @@ function validateMove(res: ServerResponse, session: Session, url: string) { emiter.emit("tah", session.discordId!, pismenko, overeni, promoNa); } +function renderHra(url: URL, session: Session, res: ServerResponse) { + if (!session.logedIn) return redirect(res, `/login?redirect=/play${url.search}`); + + let error: string | undefined = undefined; + + function serveHTML(html: string, err?: true) { + const vec = hraStranka + .replace("$domena", sachyDomena); + + let errForPrint = error ?? err; + if (errForPrint) return res.end(vec.replace("$pecko", html).replace("$hra", "")); + + res.end(vec.replace("$hra", html).replace("$pecko", "")); + } + + const tah = url.pathname.match(/\/play\/(.)$/); + if (!tah) return emiter.emit("render", session.discordId!, serveHTML); + const promoNa = url.search[1]; + + function handlePromote(err?: string) { + if (err == "--promote--") + return res.end(promoStranka.replace("$domena", sachyDomena)); + + error = err; + emiter.emit("render", session.discordId!, serveHTML); + } + emiter.emit("tah", session.discordId!, tah[1], handlePromote, promoNa); + +} + const server = createServer((req, res) => { const session = startSession(req, res); const url = new URL(req.url!, `http://${sachyDomena}`); + // log(url.pathname, url.search, url.searchParams, req.url); + // Zpracování tahu if (url.pathname.length == 2 || url.pathname.length == 4) return validateMove(res, session, req.url!); - // Oauth - if (req.url?.startsWith("/oauth")) return overeni(req.url, session, res); + // Hra v prohlížeči + if (url.pathname.startsWith("/play")) return renderHra(url, session, res); // Jinak switch (url.pathname) { @@ -172,6 +206,9 @@ const server = createServer((req, res) => { return login(session, res); } + case "/oauth": + return overeni(url, session, res); + case "/logout": return logout(session, res); diff --git a/src/utils/statuslog.ts b/src/utils/statuslog.ts index 3cec61c..828a7ee 100644 --- a/src/utils/statuslog.ts +++ b/src/utils/statuslog.ts @@ -55,7 +55,7 @@ const statusTable: SRecord = { export function statusToDLOG3(status: ClientPresenceStatusData | null) { if (!status) return "-"; - let tovje = []; + const tovje = []; for (const [key, value] of Object.entries(status)) { const platform = platformTable[key] ?? key;