UNPKG

@haelp/teto

Version:

A typescript-based controllable TETR.IO client.

184 lines (173 loc) 4.15 kB
import { Mino, type SpinType } from "../.."; export const garbageData = { single: 0, double: 1, triple: 2, quad: 4, penta: 5, tspinMini: 0, tspin: 0, tspinMiniSingle: 0, tspinSingle: 2, tspinMiniDouble: 1, tspinMiniTriple: 2, tspinDouble: 4, tspinTriple: 6, tspinQuad: 10, tspinPenta: 12, backtobackBonus: 1, backtobackBonusLog: 0.8, comboMinifier: 1, comboMinifierLog: 1.25, comboBonus: 0.25, allClear: 10, comboTable: { none: [0], "classic guideline": [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5], "modern guideline": [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4] } } as const; export const garbageCalcV2 = ( data: { lines: number; spin?: SpinType; piece: Mino; b2b: number; combo: number; enemies: number; }, config: { spinBonuses: string; comboTable: keyof (typeof garbageData)["comboTable"] | "multiplier"; garbageTargetBonus: "none" | "normal" | string; b2b: { chaining: boolean; charging: boolean; }; } ) => { let garbage = 0; const { spin: rawSpin, lines, piece, combo, b2b, enemies } = data; const { spinBonuses, comboTable, garbageTargetBonus, b2b: b2bOptions } = config; const spin: "mini" | "normal" | null | undefined = rawSpin === "none" ? null : rawSpin; switch (lines) { case 0: garbage = spin === "mini" ? garbageData.tspinMini : spin === "normal" ? garbageData.tspin : 0; break; case 1: garbage = spin === "mini" ? garbageData.tspinMiniSingle : spin === "normal" ? garbageData.tspinSingle : garbageData.single; break; case 2: garbage = spin === "mini" ? garbageData.tspinMiniDouble : spin === "normal" ? garbageData.tspinDouble : garbageData.double; break; case 3: garbage = spin === "mini" ? garbageData.tspinMiniTriple : spin === "normal" ? garbageData.tspinTriple : garbageData.triple; break; case 4: garbage = spin ? garbageData.tspinQuad : garbageData.quad; break; case 5: garbage = spin ? garbageData.tspinPenta : garbageData.penta; break; default: { const t = lines - 5; garbage = spin ? garbageData.tspinPenta + 2 * t : garbageData.penta + t; break; } } if (spin && spinBonuses === "handheld" && piece.toUpperCase() !== "T") { garbage /= 2; } if (lines > 0 && b2b > 0) { if (b2bOptions.chaining) { const b2bGains = garbageData.backtobackBonus * (Math.floor(1 + Math.log1p(b2b * garbageData.backtobackBonusLog)) + (b2b == 1 ? 0 : (1 + (Math.log1p(b2b * garbageData.backtobackBonusLog) % 1)) / 3)); garbage += b2bGains; } else { garbage += garbageData.backtobackBonus; } } if (combo > 0) { if (comboTable === "multiplier") { garbage *= 1 + garbageData.comboBonus * combo; if (combo > 1) { garbage = Math.max( Math.log1p( garbageData.comboMinifier * combo * garbageData.comboMinifierLog ), garbage ); } } else { const comboTableData = garbageData.comboTable[comboTable] || [0]; garbage += comboTableData[ Math.max(0, Math.min(combo - 1, comboTableData.length - 1)) ]; } } let garbageBonus = 0; if (lines > 0 && garbageTargetBonus !== "none") { let targetBonus = 0; switch (enemies) { case 0: case 1: break; case 2: targetBonus += 1; break; case 3: targetBonus += 3; break; case 4: targetBonus += 5; break; case 5: targetBonus += 7; break; default: targetBonus += 9; } if (garbageTargetBonus === "normal") { garbage += targetBonus; } else { garbageBonus = targetBonus; } } // TODO: how to bonus return { garbage, bonus: garbageBonus }; };