Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (async function illionCalcV1() {
- // ═══════════════════════════════════════════════════════════════
- // CONFIGURATION SETTINGS
- // ═══════════════════════════════════════════════════════════════
- const CONFIG = {
- prefix: "/",
- botTag: "[illion calc]",
- chatPollInterval: 100,
- commandCooldown: 500,
- startupDelay: 500,
- typingDelay: 6,
- maxChatLength: 180,
- logToConsole: true,
- announceOnStart: true,
- version: "v3.0.0",
- // Color IDs for typing
- superColorCID: 11,
- megaColorCID: 9,
- gigaColorCID: 15,
- teraColorCID: 7,
- normalColorCID: 0,
- // Hex colors for chat
- superColorHex: "#0000ff",
- megaColorHex: "#00aa00",
- gigaColorHex: "#aa00aa",
- teraColorHex: "#ffff00",
- // Mode toggles
- logModeEnabled: false,
- typeModeEnabled: false
- };
- const SUPPORTED_OPS = "+ - * / ^ ()";
- const VALID_COMMANDS = ['info', 'help', 'setnum', 'input', 'convert', 'logmode', 'typemode'];
- // ═══════════════════════════════════════════════════════════════
- // UTILITY FUNCTIONS
- // ═══════════════════════════════════════════════════════════════
- const sleep = ms => new Promise(r => setTimeout(r, ms));
- function log(...args) {
- if (CONFIG.logToConsole) console.log("[illion calc]", ...args);
- }
- function logError(...args) {
- console.error("[illion calc]", ...args);
- }
- // ═══════════════════════════════════════════════════════════════
- // LOAD BREAK ETERNITY
- // ═══════════════════════════════════════════════════════════════
- async function loadBreakEternity() {
- if (window.Decimal) {
- log("Break Eternity already loaded!");
- return true;
- }
- const sources = [
- 'https://cdn.jsdelivr.net/npm/[email protected]/break_eternity.min.js',
- 'https://unpkg.com/[email protected]/break_eternity.min.js',
- 'https://cdnjs.cloudflare.com/ajax/libs/break_eternity.js/2.0.0/break_eternity.min.js',
- 'https://cdn.jsdelivr.net/gh/Patashu/break_eternity.js@master/break_eternity.min.js',
- 'https://raw.githubusercontent.com/Patashu/break_eternity.js/master/break_eternity.min.js',
- 'https://cdn.jsdelivr.net/npm/break_eternity.js/break_eternity.min.js',
- 'https://unpkg.com/break_eternity.js/break_eternity.min.js',
- 'https://cdn.statically.io/gh/Patashu/break_eternity.js/master/break_eternity.min.js'
- ];
- for (const src of sources) {
- try {
- log("Trying:", src);
- await new Promise((resolve, reject) => {
- const script = document.createElement('script');
- script.src = src;
- script.onload = resolve;
- script.onerror = reject;
- document.head.appendChild(script);
- });
- await sleep(100);
- if (window.Decimal) {
- log("Loaded from:", src);
- return true;
- }
- } catch (e) {
- log("Failed:", src);
- }
- }
- return false;
- }
- const beLoaded = await loadBreakEternity();
- if (!beLoaded || !window.Decimal) {
- logError("Break Eternity failed to load!");
- return;
- }
- const Decimal = window.Decimal;
- // ═══════════════════════════════════════════════════════════════
- // DECIMAL HELPERS
- // ═══════════════════════════════════════════════════════════════
- function isDecimalNaN(num) {
- if (!num) return true;
- return Number.isNaN(num.sign) || Number.isNaN(num.layer) || Number.isNaN(num.mag);
- }
- function isDecimalFinite(num) {
- if (!num) return false;
- return Number.isFinite(num.layer) && Number.isFinite(num.mag);
- }
- function isDecimalPositive(num) {
- return num && num.sign > 0;
- }
- // ═══════════════════════════════════════════════════════════════
- // ILLION NAMING SYSTEM
- // ═══════════════════════════════════════════════════════════════
- // Standard illions 1-9
- const ONES_SINGLE = ['', 'M', 'B', 'T', 'Qa', 'Qi', 'Sx', 'Sp', 'Oc', 'No'];
- const ONES = ['', 'U', 'D', 'T', 'Qa', 'Qi', 'Sx', 'Sp', 'Oc', 'No'];
- const TENS = ['', 'De', 'Vi', 'Tr', 'Qu', 'Qt', 'Se', 'Si', 'Oi', 'Nn'];
- const HUNDREDS = ['', 'Ce', 'Du', 'Te', 'Qe', 'Qr', 'Su', 'St', 'Ot', 'Ne'];
- // Base Super Illions (super index 1-10): Mi -> Ve
- const BASE_SUPER_ILLIONS = ['', 'Mi', 'Mc', 'Na', 'Pi', 'Fe', 'At', 'Ze', 'Yc', 'Xn', 'Ve'];
- // Super Illions 1 - Ones for 11-19 and compound ones
- const SUPER_ILLIONS_1 = ['', 'Me', 'Duc', 'Tec', 'Ttec', 'Pnec', 'Hxec', 'Hpec', 'Ocec', 'Enec'];
- // Super Illions 2 - Tens (20=Ic, 30=Tcnt, etc.)
- const SUPER_ILLIONS_2 = ['', 'Ic', 'Tcnt', 'Tecnt', 'Pecnt', 'Hxcnt', 'Hpcnt', 'Occnt', 'Eccnt'];
- // Super Illions 3 - Hundreds (100=Hct, 200=Dhct, etc.)
- const SUPER_ILLIONS_3 = ['', 'Hct', 'Dhct', 'Thct', 'Tehct', 'Pehct', 'Hxhct', 'Hphct', 'Ochct', 'Enhct'];
- // Mega Illions Tier 1: Base names at powers of 1000 in super index
- const MEGA_ILLIONS_1 = ['', 'Kil', 'Meg', 'Gig', 'Ter', 'Pet', 'Ex', 'Zet', 'Yoc', 'Xen', 'Hnd'];
- // Mega Illions with remainder suffix (Kil->Kia, etc.)
- const MEGA_ILLIONS_1_REM = ['', 'Kia', 'Mea', 'Gia', 'Tea', 'Pea', 'Exa', 'Zea', 'Yoa', 'Xea', 'Hna'];
- // Giga Illions Tier 1 (1-9 at giga level)
- const GIGA_ILLIONS_1 = ['', 'Kal', 'Mij', 'Gij', 'Tej', 'Pej', 'Exj', 'Zej', 'Yej', 'Xej', 'Vej'];
- // Giga Illions Tier 2 (10-90 ones position at giga level)
- const GIGA_ILLIONS_2 = ['', 'Mej', 'Ij', 'Tecj', 'Trecj', 'Pecj', 'Hecj', 'Hpcj', 'Ocej', 'Enej'];
- // Giga Illions Tier 3 (100-900 at giga level)
- const GIGA_ILLIONS_3 = ['', 'Hej', 'Dhej', 'Thej', 'Trhej', 'Pehej', 'Hxhej', 'Hphej', 'Ochej', 'Enhej'];
- // Kiv = Tera Illion 1 (CID 7, #ffff00) at super index 10^(3*10^3000)
- const KIV = 'Kiv';
- // Threshold for skipping normal illions (super index >= 1001 = MiKia)
- const SKIP_NORMAL_THRESHOLD = new Decimal(1001);
- // Splice threshold - after 100 super indexes, use mod 100
- const SPLICE_THRESHOLD = 100;
- // Tier thresholds
- const GIGA_THRESHOLD = Decimal.pow(10, 3000); // 10^3000
- const TERA_THRESHOLD = Decimal.pow(10, Decimal.pow(10, 3000).mul(3)); // 10^(3*10^3000)
- // Maximum: 1e1e1e3e3003 = 10^10^10^(3*10^3003)
- const MAX_ILLION = Decimal.pow(10, Decimal.pow(10, Decimal.pow(10, 3003).mul(3)));
- // Get standard name for illion index 1-999
- function getStandardName(n) {
- if (n <= 0 || n > 999) return '';
- if (n < 10) return ONES_SINGLE[n];
- const ones = n % 10;
- const tens = Math.floor(n / 10) % 10;
- const hundreds = Math.floor(n / 100) % 10;
- return ONES[ones] + TENS[tens] + HUNDREDS[hundreds];
- }
- // Get standard compound name for multipliers 2-999 (using U, D, T, De, Vi, Ce, etc.)
- function getStandardCompoundName(n) {
- if (n <= 1 || n > 999) return '';
- if (n < 10) return ONES[n];
- const ones = n % 10;
- const tens = Math.floor(n / 10) % 10;
- const hundreds = Math.floor(n / 100) % 10;
- return ONES[ones] + TENS[tens] + HUNDREDS[hundreds];
- }
- // Get super illion suffix for indices 1-999 (within a mega tier)
- function getSuperIllionName(superIndex) {
- if (superIndex <= 0 || superIndex >= 1000) return '';
- // Base tier (1-10): Mi, Mc, Na, Pi, Fe, At, Ze, Yc, Xn, Ve
- if (superIndex <= 10) {
- return BASE_SUPER_ILLIONS[superIndex];
- }
- // 11-19: Me, Duc, Tec, Ttec, Pnec, Hxec, Hpec, Ocec, Enec
- if (superIndex <= 19) {
- return SUPER_ILLIONS_1[superIndex - 10];
- }
- // 20+: Compound naming
- const ones = superIndex % 10;
- const tens = Math.floor(superIndex / 10) % 10;
- const hundreds = Math.floor(superIndex / 100) % 10;
- let name = '';
- if (ones > 0) {
- name += SUPER_ILLIONS_1[ones];
- }
- if (tens >= 2) {
- name += SUPER_ILLIONS_2[tens - 1];
- }
- if (hundreds > 0) {
- name += SUPER_ILLIONS_3[hundreds];
- }
- return name;
- }
- // Get super illion name with splice (after 100, use mod 100)
- function getSuperIllionNameSpliced(superIndex) {
- if (superIndex <= 0) return '';
- // Splice: if >= 100, use mod 100
- if (superIndex >= SPLICE_THRESHOLD) {
- superIndex = superIndex % SPLICE_THRESHOLD;
- }
- if (superIndex === 0) return '';
- if (superIndex >= 1000) return '';
- return getSuperIllionName(superIndex);
- }
- // Get giga tier compound name for multipliers 1-999
- function getGigaCompoundName(index) {
- if (index <= 0 || index > 999) return '';
- // 1-9: Use GIGA_ILLIONS_1
- if (index <= 9) {
- return GIGA_ILLIONS_1[index] || '';
- }
- const ones = index % 10;
- const tens = Math.floor(index / 10) % 10;
- const hundreds = Math.floor(index / 100);
- let name = '';
- // Ones (1-9) from GIGA_ILLIONS_1
- if (ones >= 1 && ones <= 9) {
- name += GIGA_ILLIONS_1[ones] || '';
- }
- // Tens (1-9) from GIGA_ILLIONS_2
- if (tens >= 1 && tens <= 9) {
- name += GIGA_ILLIONS_2[tens] || '';
- }
- // Hundreds (1-9) from GIGA_ILLIONS_3
- if (hundreds >= 1 && hundreds <= 9) {
- name += GIGA_ILLIONS_3[hundreds] || '';
- }
- return name;
- }
- // Cleanup tier overlap - use replace() to blank out lower tiers when higher tier starts
- function cleanupTierOverlap(name, parts) {
- const hasTera = parts.some(p => p.type === 'tera');
- const hasGiga = parts.some(p => p.type === 'giga');
- let cleanedName = name;
- let cleanedParts = [...parts];
- if (hasTera) {
- // Use replace() to remove giga and mega text from name
- for (const part of parts) {
- if (part.type === 'mega' || part.type === 'giga') {
- cleanedName = cleanedName.replace(part.text, '');
- }
- }
- // Filter out mega and giga parts
- cleanedParts = parts.filter(p => p.type !== 'mega' && p.type !== 'giga');
- } else if (hasGiga) {
- // Use replace() to remove mega text from name
- for (const part of parts) {
- if (part.type === 'mega') {
- cleanedName = cleanedName.replace(part.text, '');
- }
- }
- // Filter out mega parts
- cleanedParts = parts.filter(p => p.type !== 'mega');
- }
- return { name: cleanedName, parts: cleanedParts, isMega: true };
- }
- // Get mega illion suffix for a given super index (Decimal)
- function getMegaIllionSuffix(superIndex) {
- if (!(superIndex instanceof Decimal)) {
- superIndex = new Decimal(superIndex);
- }
- if (superIndex.lt(1000)) {
- return { name: '', parts: [], isMega: false };
- }
- let parts = [];
- let name = '';
- // Check for Tera tier first (highest)
- if (superIndex.gte(TERA_THRESHOLD)) {
- const teraPower = superIndex.div(TERA_THRESHOLD).floor();
- const teraRemainder = superIndex.mod(TERA_THRESHOLD);
- // Get the remainder first (lower tiers) - will be cleaned up later
- if (teraRemainder.gte(1000)) {
- const remResult = getMegaIllionSuffixRaw(teraRemainder);
- if (remResult.name) {
- name += remResult.name;
- parts = [...parts, ...remResult.parts];
- }
- } else if (teraRemainder.gte(1)) {
- const splicedRemainder = teraRemainder.toNumber() % SPLICE_THRESHOLD;
- if (splicedRemainder > 0) {
- const superName = getSuperIllionName(splicedRemainder);
- if (superName) {
- name += superName;
- parts.push({ text: superName, type: 'super' });
- }
- }
- }
- // Add Tera suffix
- if (teraPower.eq(1)) {
- name += KIV;
- parts.push({ text: KIV, type: 'tera' });
- } else if (teraPower.lt(1000)) {
- const multiplier = getGigaCompoundName(teraPower.toNumber());
- const kivText = multiplier + KIV;
- name += kivText;
- parts.push({ text: kivText, type: 'tera' });
- } else {
- const multResult = getMegaIllionSuffixRaw(teraPower);
- if (multResult.name) {
- name += multResult.name;
- parts = [...parts, ...multResult.parts];
- }
- name += KIV;
- parts.push({ text: KIV, type: 'tera' });
- }
- // Apply tier cleanup using replace()
- return cleanupTierOverlap(name, parts);
- }
- // Check for Giga tier
- if (superIndex.gte(GIGA_THRESHOLD)) {
- const gigaPower = superIndex.div(GIGA_THRESHOLD).floor();
- const gigaRemainder = superIndex.mod(GIGA_THRESHOLD);
- // Get the remainder first (lower mega tiers) - will be cleaned up later
- if (gigaRemainder.gte(1000)) {
- const remResult = getMegaIllionSuffixRaw(gigaRemainder);
- if (remResult.name) {
- name += remResult.name;
- parts = [...parts, ...remResult.parts];
- }
- } else if (gigaRemainder.gte(1)) {
- const splicedRemainder = gigaRemainder.toNumber() % SPLICE_THRESHOLD;
- if (splicedRemainder > 0) {
- const superName = getSuperIllionName(splicedRemainder);
- if (superName) {
- name += superName;
- parts.push({ text: superName, type: 'super' });
- }
- }
- }
- // Get giga name
- if (gigaPower.eq(1)) {
- const gigaName = GIGA_ILLIONS_1[1]; // Mij
- name += gigaName;
- parts.push({ text: gigaName, type: 'giga' });
- } else if (gigaPower.lt(1000)) {
- const gigaName = getGigaCompoundName(gigaPower.toNumber());
- name += gigaName;
- parts.push({ text: gigaName, type: 'giga' });
- } else {
- const gigaResult = getMegaIllionSuffixRaw(gigaPower);
- if (gigaResult.name) {
- name += gigaResult.name;
- parts = [...parts, ...gigaResult.parts];
- }
- const gigaBase = GIGA_ILLIONS_1[1];
- name += gigaBase;
- parts.push({ text: gigaBase, type: 'giga' });
- }
- // Apply tier cleanup using replace()
- return cleanupTierOverlap(name, parts);
- }
- // Mega tier (1000 to 10^3000-1)
- return getMegaIllionSuffixRaw(superIndex);
- }
- // Raw mega suffix without tier cleanup (for recursion)
- function getMegaIllionSuffixRaw(superIndex) {
- if (!(superIndex instanceof Decimal)) {
- superIndex = new Decimal(superIndex);
- }
- if (superIndex.lt(1000)) {
- return { name: '', parts: [], isMega: false };
- }
- let parts = [];
- let name = '';
- // Check for Giga tier
- if (superIndex.gte(GIGA_THRESHOLD)) {
- const gigaPower = superIndex.div(GIGA_THRESHOLD).floor();
- const gigaRemainder = superIndex.mod(GIGA_THRESHOLD);
- if (gigaRemainder.gte(1000)) {
- const remResult = getMegaIllionSuffixRaw(gigaRemainder);
- if (remResult.name) {
- name += remResult.name;
- parts = [...parts, ...remResult.parts];
- }
- } else if (gigaRemainder.gte(1)) {
- const splicedRemainder = gigaRemainder.toNumber() % SPLICE_THRESHOLD;
- if (splicedRemainder > 0) {
- const superName = getSuperIllionName(splicedRemainder);
- if (superName) {
- name += superName;
- parts.push({ text: superName, type: 'super' });
- }
- }
- }
- if (gigaPower.eq(1)) {
- const gigaName = GIGA_ILLIONS_1[1];
- name += gigaName;
- parts.push({ text: gigaName, type: 'giga' });
- } else if (gigaPower.lt(1000)) {
- const gigaName = getGigaCompoundName(gigaPower.toNumber());
- name += gigaName;
- parts.push({ text: gigaName, type: 'giga' });
- } else {
- const gigaResult = getMegaIllionSuffixRaw(gigaPower);
- if (gigaResult.name) {
- name += gigaResult.name;
- parts = [...parts, ...gigaResult.parts];
- }
- const gigaBase = GIGA_ILLIONS_1[1];
- name += gigaBase;
- parts.push({ text: gigaBase, type: 'giga' });
- }
- return { name, parts, isMega: true };
- }
- // Mega tier (1000 to 10^3000-1)
- const log10Val = superIndex.log10().toNumber();
- let megaTier = Math.floor(log10Val / 3);
- if (megaTier > 10) megaTier = 10;
- if (megaTier < 1) megaTier = 1;
- const tierBase = Decimal.pow(10, megaTier * 3);
- const tierMultiplier = superIndex.div(tierBase).floor();
- const tierRemainder = superIndex.mod(tierBase);
- const hasRemainder = tierRemainder.gte(1);
- // Handle the remainder first (lower tiers + super)
- if (tierRemainder.gte(1000)) {
- const remResult = getMegaIllionSuffixRaw(tierRemainder);
- if (remResult.name) {
- name += remResult.name;
- parts = [...parts, ...remResult.parts];
- }
- } else if (tierRemainder.gte(1)) {
- // Apply splice: if >= 100, use mod 100
- const splicedRemainder = tierRemainder.toNumber() % SPLICE_THRESHOLD;
- if (splicedRemainder > 0) {
- const superName = getSuperIllionName(splicedRemainder);
- if (superName) {
- name += superName;
- parts.push({ text: superName, type: 'super' });
- }
- }
- }
- // Get the appropriate mega base name (Kil->Kia when has remainder)
- const megaBaseName = hasRemainder
- ? (MEGA_ILLIONS_1_REM[megaTier] || MEGA_ILLIONS_1[megaTier])
- : MEGA_ILLIONS_1[megaTier];
- if (!megaBaseName) {
- return { name, parts, isMega: true };
- }
- if (tierMultiplier.eq(1)) {
- name += megaBaseName;
- parts.push({ text: megaBaseName, type: 'mega' });
- } else if (tierMultiplier.lt(1000)) {
- const multiplier = getStandardCompoundName(tierMultiplier.toNumber());
- const fullName = multiplier + megaBaseName;
- name += fullName;
- parts.push({ text: fullName, type: 'mega' });
- } else {
- const multResult = getMegaIllionSuffixRaw(tierMultiplier);
- if (multResult.name) {
- name += multResult.name;
- parts = [...parts, ...multResult.parts];
- }
- name += megaBaseName;
- parts.push({ text: megaBaseName, type: 'mega' });
- }
- return { name, parts, isMega: true };
- }
- // Get complete suffix with proper type info for a super index
- function getSuperIllionSuffix(superIndex) {
- if (!(superIndex instanceof Decimal)) {
- superIndex = new Decimal(superIndex);
- }
- if (superIndex.lte(0)) return { name: '', isSuper: false, isMega: false, parts: [] };
- // Handle mega tier (1000+)
- if (superIndex.gte(1000)) {
- const megaResult = getMegaIllionSuffix(superIndex);
- return {
- name: megaResult.name,
- isSuper: true,
- isMega: true,
- parts: megaResult.parts
- };
- }
- // Pure super tier (1-999) - apply splice
- const splicedIndex = superIndex.toNumber() % SPLICE_THRESHOLD;
- if (splicedIndex === 0) return { name: '', isSuper: false, isMega: false, parts: [] };
- const superName = getSuperIllionName(splicedIndex);
- return {
- name: superName,
- isSuper: true,
- isMega: false,
- parts: [{ text: superName, type: 'super' }]
- };
- }
- // Main illion naming function
- function getIllionName(illionIndex) {
- let num;
- if (illionIndex instanceof Decimal) {
- num = illionIndex;
- } else {
- num = new Decimal(illionIndex);
- }
- if (num.gte(MAX_ILLION)) return null;
- if (num.lte(0)) return { name: '', parts: [] };
- // Simple names for 1-9
- if (num.lt(10)) {
- return {
- name: ONES_SINGLE[num.toNumber()],
- parts: [{ text: ONES_SINGLE[num.toNumber()], type: 'normal' }]
- };
- }
- // Standard names for 10-999
- if (num.lt(1000)) {
- const name = getStandardName(num.toNumber());
- return { name, parts: [{ text: name, type: 'normal' }] };
- }
- // Extended: 1000+ illion index
- const groups = [];
- let remaining = num;
- let groupIndex = new Decimal(0);
- while (remaining.gte(1)) {
- groups.push({
- value: remaining.mod(1000).floor().toNumber(),
- index: groupIndex
- });
- remaining = remaining.div(1000).floor();
- groupIndex = groupIndex.add(1);
- }
- let name = '';
- let parts = [];
- for (let i = groups.length - 1; i >= 0; i--) {
- const group = groups[i];
- if (group.value === 0) continue;
- // Check if this group's index is >= 1001 (MiKia and above)
- const isInHighMegaTier = group.index.gte(SKIP_NORMAL_THRESHOLD);
- if (!isInHighMegaTier) {
- let groupName;
- if (i === groups.length - 1 && group.value < 10) {
- groupName = ONES_SINGLE[group.value];
- } else {
- groupName = getStandardName(group.value);
- }
- if (groupName) {
- parts.push({ text: groupName, type: 'normal' });
- name += groupName;
- }
- }
- // Add super/mega suffix for non-zero group index
- if (group.index.gt(0)) {
- const suffix = getSuperIllionSuffix(group.index);
- if (suffix.name) {
- parts = [...parts, ...suffix.parts];
- name += suffix.name;
- }
- }
- }
- return { name, parts };
- }
- // ═══════════════════════════════════════════════════════════════
- // ILLION CONVERTER
- // ═══════════════════════════════════════════════════════════════
- function parseIllionName(input) {
- input = input.trim();
- if (!input) return null;
- if (/^\d+$/.test(input)) return new Decimal(input);
- for (let i = 1; i <= 9; i++) {
- if (input === ONES_SINGLE[i]) return new Decimal(i);
- }
- return null;
- }
- function illionToScientific(illionIndex) {
- if (!(illionIndex instanceof Decimal)) {
- illionIndex = new Decimal(illionIndex);
- }
- const exponent = illionIndex.mul(3).add(3);
- if (exponent.lt(1e6)) {
- return `1e${exponent.toFixed(0)}`;
- } else if (exponent.lt(1e15)) {
- return `1e${exponent.toPrecision(6)}`;
- } else {
- const expLog = exponent.log10();
- if (expLog.lt(1e15)) {
- return `10^10^${expLog.toFixed(3)}`;
- } else {
- const expLogLog = expLog.log10();
- return `10^10^10^${expLogLog.toFixed(3)}`;
- }
- }
- }
- // ═══════════════════════════════════════════════════════════════
- // OUTPUT FUNCTIONS
- // ═══════════════════════════════════════════════════════════════
- function buildChatMessage(prefix, parts) {
- let message = prefix;
- for (const part of parts) {
- if (part.type === 'super') {
- message += `<start ${CONFIG.superColorHex}>${part.text}<end>`;
- } else if (part.type === 'mega') {
- message += `<start ${CONFIG.megaColorHex}>${part.text}<end>`;
- } else if (part.type === 'giga') {
- message += `<start ${CONFIG.gigaColorHex}>${part.text}<end>`;
- } else if (part.type === 'tera') {
- message += `<start ${CONFIG.teraColorHex}>${part.text}<end>`;
- } else {
- message += part.text;
- }
- }
- return message;
- }
- function buildPlainMessage(prefix, parts) {
- let message = prefix;
- for (const part of parts) {
- message += part.text;
- }
- return message;
- }
- async function typeText(text, colorCID = CONFIG.normalColorCID) {
- try {
- w.changeColor(colorCID);
- } catch (e) {}
- for (let i = 0; i < text.length; i++) {
- try {
- w.typeChar(text[i], 1);
- } catch (e) {}
- await sleep(CONFIG.typingDelay);
- }
- }
- async function typeColoredOutput(parts) {
- for (const part of parts) {
- let colorCID = CONFIG.normalColorCID;
- if (part.type === 'super') {
- colorCID = CONFIG.superColorCID;
- } else if (part.type === 'mega') {
- colorCID = CONFIG.megaColorCID;
- } else if (part.type === 'giga') {
- colorCID = CONFIG.gigaColorCID;
- } else if (part.type === 'tera') {
- colorCID = CONFIG.teraColorCID;
- }
- await typeText(part.text, colorCID);
- }
- try {
- w.changeColor(CONFIG.normalColorCID);
- w.typeChar('\n', 1);
- } catch (e) {}
- }
- async function forceSendToChat(message) {
- try {
- const result = w.chat.send(message);
- if (result !== false) {
- log("Force sent:", message);
- return true;
- }
- } catch (e) {
- log("Force send failed:", e);
- }
- return false;
- }
- async function sendOutput(prefix, parts = []) {
- const plainMessage = buildPlainMessage(prefix, parts);
- const coloredMessage = buildChatMessage(prefix, parts);
- if (CONFIG.typeModeEnabled) {
- log("TypeMode: typing output...");
- const contentParts = [{ text: prefix.replace(CONFIG.botTag + ' ', ''), type: 'normal' }, ...parts];
- await typeColoredOutput(contentParts);
- return true;
- }
- if (plainMessage.length > CONFIG.maxChatLength) {
- log("Message too long, typing instead...");
- const contentParts = [{ text: prefix.replace(CONFIG.botTag + ' ', ''), type: 'normal' }, ...parts];
- await typeColoredOutput(contentParts);
- return true;
- }
- try {
- const result = w.chat.send(coloredMessage);
- if (result !== false) {
- log("Sent:", plainMessage);
- return true;
- }
- } catch (e) {
- log("Chat failed, typing instead...");
- }
- const contentParts = [{ text: prefix.replace(CONFIG.botTag + ' ', ''), type: 'normal' }, ...parts];
- await typeColoredOutput(contentParts);
- return true;
- }
- async function sendSimpleOutput(message) {
- if (CONFIG.typeModeEnabled) {
- log("TypeMode: typing output...");
- const content = message.replace(CONFIG.botTag + ' ', '');
- await typeText(content, CONFIG.normalColorCID);
- try { w.typeChar('\n', 1); } catch (e) {}
- return true;
- }
- if (message.length > CONFIG.maxChatLength) {
- log("Message too long, typing instead...");
- const content = message.replace(CONFIG.botTag + ' ', '');
- await typeText(content, CONFIG.normalColorCID);
- try { w.typeChar('\n', 1); } catch (e) {}
- return true;
- }
- try {
- const result = w.chat.send(message);
- if (result !== false) {
- log("Sent:", message);
- return true;
- }
- } catch (e) {}
- const content = message.replace(CONFIG.botTag + ' ', '');
- await typeText(content, CONFIG.normalColorCID);
- try { w.typeChar('\n', 1); } catch (e) {}
- return true;
- }
- function formatLogMode(num) {
- if (!(num instanceof Decimal)) {
- num = new Decimal(num);
- }
- if (isDecimalNaN(num)) return 'NaN';
- if (!isDecimalFinite(num)) return isDecimalPositive(num) ? 'Infinity' : '-Infinity';
- const isNeg = num.lt(0);
- num = num.abs();
- const prefix = isNeg ? '-' : '';
- if (num.eq(0)) return '0';
- if (num.lt(1e-6) || num.gte(1e6)) {
- const log10 = num.log10();
- const exp = log10.floor();
- const mantissa = num.div(Decimal.pow(10, exp));
- return `${prefix}${mantissa.toFixed(6)} * 10^${exp.toFixed(0)}`;
- }
- return prefix + num.toFixed(6);
- }
- function formatNumber(num) {
- if (!(num instanceof Decimal)) {
- try {
- num = new Decimal(num);
- } catch (e) {
- return { text: 'Invalid Number', parts: [{ text: 'Invalid Number', type: 'normal' }] };
- }
- }
- if (isDecimalNaN(num)) {
- return { text: 'NaN', parts: [{ text: 'NaN', type: 'normal' }] };
- }
- if (!isDecimalFinite(num)) {
- const text = isDecimalPositive(num) ? 'Infinity' : '-Infinity';
- return { text, parts: [{ text, type: 'normal' }] };
- }
- if (CONFIG.logModeEnabled) {
- const text = formatLogMode(num);
- return { text, parts: [{ text, type: 'normal' }] };
- }
- const isNeg = num.lt(0);
- num = num.abs();
- const prefix = isNeg ? '-' : '';
- if (num.lt(1000)) {
- const text = prefix + num.toFixed(3);
- return { text, parts: [{ text, type: 'normal' }] };
- }
- if (num.lt(1e6)) {
- const text = prefix + num.toFixed(0);
- return { text, parts: [{ text, type: 'normal' }] };
- }
- const log10 = num.log10();
- if (log10.lt(6)) {
- const text = prefix + num.toPrecision(6);
- return { text, parts: [{ text, type: 'normal' }] };
- }
- const illionIndex = log10.sub(3).div(3).floor();
- const exponent = illionIndex.mul(3).add(3);
- const mantissa = num.div(Decimal.pow(10, exponent));
- const illionResult = getIllionName(illionIndex);
- if (illionResult === null) {
- return {
- text: "Too Big to Calculate.",
- parts: [{ text: "Too Big to Calculate.", type: 'normal' }]
- };
- }
- const mantissaText = prefix + mantissa.toFixed(3) + ' ';
- const parts = [{ text: mantissaText, type: 'normal' }, ...illionResult.parts];
- return { text: mantissaText + illionResult.name, parts };
- }
- // ═══════════════════════════════════════════════════════════════
- // EXPRESSION PARSER
- // ═══════════════════════════════════════════════════════════════
- function isValidExpression(expr) {
- if (!expr || expr.trim().length === 0) return false;
- return /\d/.test(expr) && /^[\d\s+\-*/^().eE]+$/.test(expr);
- }
- function tokenize(expr) {
- const tokens = [];
- let current = '';
- let lastWasOp = true;
- for (let i = 0; i < expr.length; i++) {
- const char = expr[i];
- if (/[\d.]/.test(char)) {
- current += char;
- lastWasOp = false;
- } else if (/[eE]/.test(char) && current.length > 0) {
- current += char;
- } else if (/[+-]/.test(char) && current.match(/[eE]$/)) {
- current += char;
- } else if (/[+-]/.test(char) && lastWasOp) {
- current += char;
- } else if (/[+\-*/^()]/.test(char)) {
- if (current) {
- tokens.push({ type: 'num', value: current });
- current = '';
- }
- tokens.push({ type: 'op', value: char });
- lastWasOp = char !== ')';
- } else if (char === ' ') {
- if (current) {
- tokens.push({ type: 'num', value: current });
- current = '';
- }
- }
- }
- if (current) tokens.push({ type: 'num', value: current });
- return tokens;
- }
- function evaluateExpression(expr) {
- expr = expr.trim().replace(/\s+/g, ' ').replace(/×/g, '*').replace(/÷/g, '/').replace(/\*\*/g, '^');
- if (!isValidExpression(expr)) {
- return { success: false, error: 'Invalid Operation.' };
- }
- try {
- const tokens = tokenize(expr);
- if (tokens.length === 0) return { success: false, error: 'Invalid Operation.' };
- const outputQueue = [];
- const operatorStack = [];
- const precedence = { '+': 1, '-': 1, '*': 2, '/': 2, '^': 3 };
- const rightAssoc = { '^': true };
- for (const token of tokens) {
- if (token.type === 'num') {
- try {
- outputQueue.push(new Decimal(token.value));
- } catch (e) {
- return { success: false, error: `Invalid number: ${token.value}` };
- }
- } else if (token.value === '(') {
- operatorStack.push(token);
- } else if (token.value === ')') {
- while (operatorStack.length && operatorStack[operatorStack.length - 1].value !== '(') {
- outputQueue.push(operatorStack.pop());
- }
- if (operatorStack.length) operatorStack.pop();
- } else if (precedence[token.value] !== undefined) {
- while (
- operatorStack.length &&
- operatorStack[operatorStack.length - 1].value !== '(' &&
- precedence[operatorStack[operatorStack.length - 1].value] !== undefined &&
- (precedence[operatorStack[operatorStack.length - 1].value] > precedence[token.value] ||
- (precedence[operatorStack[operatorStack.length - 1].value] === precedence[token.value] &&
- !rightAssoc[token.value]))
- ) {
- outputQueue.push(operatorStack.pop());
- }
- operatorStack.push(token);
- }
- }
- while (operatorStack.length) outputQueue.push(operatorStack.pop());
- const evalStack = [];
- for (const item of outputQueue) {
- if (item instanceof Decimal) {
- evalStack.push(item);
- } else if (item.type === 'op') {
- if (evalStack.length < 2) {
- if (evalStack.length === 1) continue;
- return { success: false, error: 'Invalid Operation.' };
- }
- const b = evalStack.pop();
- const a = evalStack.pop();
- switch (item.value) {
- case '+': evalStack.push(a.add(b)); break;
- case '-': evalStack.push(a.sub(b)); break;
- case '*': evalStack.push(a.mul(b)); break;
- case '/': evalStack.push(a.div(b)); break;
- case '^': evalStack.push(a.pow(b)); break;
- }
- }
- }
- return evalStack.length === 1
- ? { success: true, result: evalStack[0] }
- : { success: false, error: 'Invalid Operation.' };
- } catch (e) {
- return { success: false, error: e.message || 'Unknown error' };
- }
- }
- // ═══════════════════════════════════════════════════════════════
- // COMMAND HANDLERS
- // ═══════════════════════════════════════════════════════════════
- async function handleInfo() {
- const logModeStatus = CONFIG.logModeEnabled ? 'ON' : 'OFF';
- const typeModeStatus = CONFIG.typeModeEnabled ? 'ON' : 'OFF';
- await sendSimpleOutput(`${CONFIG.botTag} Version: ${CONFIG.version} | Ops: ${SUPPORTED_OPS} | LogMode: ${logModeStatus} | TypeMode: ${typeModeStatus}`);
- }
- async function handleHelp() {
- await sendSimpleOutput(`${CONFIG.botTag} Commands: ${CONFIG.prefix}info, ${CONFIG.prefix}help, ${CONFIG.prefix}input, ${CONFIG.prefix}setnum, ${CONFIG.prefix}convert, ${CONFIG.prefix}logmode, ${CONFIG.prefix}typemode`);
- }
- async function handleLogMode() {
- CONFIG.logModeEnabled = !CONFIG.logModeEnabled;
- const status = CONFIG.logModeEnabled ? 'ENABLED' : 'DISABLED';
- await sendSimpleOutput(`${CONFIG.botTag} Log mode ${status}`);
- log(`Log mode: ${status}`);
- }
- async function handleTypeMode() {
- const newStatus = !CONFIG.typeModeEnabled;
- const statusText = newStatus ? 'ENABLED' : 'DISABLED';
- await forceSendToChat(`${CONFIG.botTag} Type mode ${statusText} - output will be typed instead of sent to chat`);
- CONFIG.typeModeEnabled = newStatus;
- log(`Type mode: ${statusText}`);
- }
- async function handleSetNum(args) {
- const parts = args.trim().split(/\s+/);
- if (parts.length < 2 || !parts[0] || !parts[1]) {
- await sendSimpleOutput(`${CONFIG.botTag} Usage: ${CONFIG.prefix}setnum <mantissa> <exponent>`);
- return;
- }
- const mantissa = parseFloat(parts[0]);
- const exponent = parseFloat(parts[1]);
- if (Number.isNaN(mantissa)) {
- await sendSimpleOutput(`${CONFIG.botTag} Invalid mantissa: ${parts[0]}`);
- return;
- }
- if (Number.isNaN(exponent)) {
- await sendSimpleOutput(`${CONFIG.botTag} Invalid exponent: ${parts[1]}`);
- return;
- }
- try {
- const num = new Decimal(mantissa).mul(Decimal.pow(10, exponent));
- const formatted = formatNumber(num);
- const prefix = `${CONFIG.botTag} ${mantissa}e${exponent} = `;
- await sendOutput(prefix, formatted.parts);
- } catch (e) {
- await sendSimpleOutput(`${CONFIG.botTag} Error: ${e.message}`);
- }
- }
- async function handleInput(args) {
- if (!args || !args.trim()) {
- await sendSimpleOutput(`${CONFIG.botTag} Usage: ${CONFIG.prefix}input <expression>`);
- return;
- }
- const expr = args.trim();
- if (!isValidExpression(expr)) {
- await sendSimpleOutput(`${CONFIG.botTag} Invalid Operation.`);
- return;
- }
- const evalResult = evaluateExpression(expr);
- if (evalResult.success) {
- const formatted = formatNumber(evalResult.result);
- const prefix = `${CONFIG.botTag} ${expr} = `;
- await sendOutput(prefix, formatted.parts);
- } else {
- await sendSimpleOutput(`${CONFIG.botTag} Error: ${evalResult.error}`);
- }
- }
- async function handleConvert(args) {
- if (!args || !args.trim()) {
- await sendSimpleOutput(`${CONFIG.botTag} Usage: ${CONFIG.prefix}convert <illion name or index>`);
- return;
- }
- const input = args.trim();
- let illionIndex = parseIllionName(input);
- if (illionIndex === null) {
- try {
- illionIndex = new Decimal(input);
- } catch (e) {
- await sendSimpleOutput(`${CONFIG.botTag} Invalid illion: ${input}`);
- return;
- }
- }
- try {
- const illionResult = getIllionName(illionIndex);
- const scientific = illionToScientific(illionIndex);
- if (illionResult === null) {
- await sendSimpleOutput(`${CONFIG.botTag} Illion too large to name.`);
- return;
- }
- const prefix = `${CONFIG.botTag} `;
- const suffix = ` (index ${illionIndex.toString()}) = ${scientific}`;
- const allParts = [
- ...illionResult.parts,
- { text: suffix, type: 'normal' }
- ];
- await sendOutput(prefix, allParts);
- } catch (e) {
- await sendSimpleOutput(`${CONFIG.botTag} Error: ${e.message}`);
- }
- }
- async function handleExpression(expr) {
- if (!expr || !expr.trim()) return;
- const expression = expr.trim();
- if (!isValidExpression(expression)) {
- await sendSimpleOutput(`${CONFIG.botTag} Invalid Operation.`);
- return;
- }
- const evalResult = evaluateExpression(expression);
- if (evalResult.success) {
- const formatted = formatNumber(evalResult.result);
- const prefix = `${CONFIG.botTag} ${expression} = `;
- await sendOutput(prefix, formatted.parts);
- } else {
- await sendSimpleOutput(`${CONFIG.botTag} Error: ${evalResult.error}`);
- }
- }
- // ═══════════════════════════════════════════════════════════════
- // COMMAND PROCESSOR
- // ═══════════════════════════════════════════════════════════════
- let processedCommands = new Map();
- async function processCommand(fullCommand) {
- if (!fullCommand || typeof fullCommand !== 'string') return;
- const cmd = fullCommand.trim();
- if (!cmd) return;
- const now = Date.now();
- const lastTime = processedCommands.get(cmd);
- if (lastTime && (now - lastTime) < CONFIG.commandCooldown) return;
- processedCommands.set(cmd, now);
- if (processedCommands.size > 100) {
- processedCommands = new Map(Array.from(processedCommands.entries()).slice(-50));
- }
- log("Processing:", cmd);
- const spaceIndex = cmd.indexOf(' ');
- const cmdName = spaceIndex > -1 ? cmd.slice(0, spaceIndex).toLowerCase() : cmd.toLowerCase();
- const cmdArgs = spaceIndex > -1 ? cmd.slice(spaceIndex + 1) : '';
- switch (cmdName) {
- case 'info': await handleInfo(); return;
- case 'help': await handleHelp(); return;
- case 'setnum': await handleSetNum(cmdArgs); return;
- case 'input': await handleInput(cmdArgs); return;
- case 'convert': await handleConvert(cmdArgs); return;
- case 'logmode': await handleLogMode(); return;
- case 'typemode': await handleTypeMode(); return;
- }
- if (/^[a-zA-Z]+$/.test(cmdName) && !VALID_COMMANDS.includes(cmdName)) {
- await sendSimpleOutput(`${CONFIG.botTag} Invalid Command.`);
- return;
- }
- if (/[\d]/.test(cmd)) {
- await handleExpression(cmd);
- } else {
- await sendSimpleOutput(`${CONFIG.botTag} Invalid Command.`);
- }
- }
- // ═══════════════════════════════════════════════════════════════
- // MESSAGE & EVENT SYSTEM
- // ═══════════════════════════════════════════════════════════════
- function extractMessageText(data) {
- if (!data) return null;
- if (typeof data === 'string') return data.trim();
- if (typeof data === 'object') {
- for (const prop of ['message', 'msg', 'text', 'content', 'chat', 'data', 'body', 'value', 'payload']) {
- if (data[prop]) {
- const extracted = extractMessageText(data[prop]);
- if (extracted) return extracted;
- }
- }
- }
- return null;
- }
- function isBotMessage(text) {
- return !text || text.includes(CONFIG.botTag);
- }
- function extractCommands(text) {
- const commands = [];
- if (!text || typeof text !== 'string' || isBotMessage(text)) return commands;
- let pos = 0;
- while (pos < text.length) {
- const prefixIdx = text.indexOf(CONFIG.prefix, pos);
- if (prefixIdx === -1) break;
- let cmdEnd = text.indexOf('\n', prefixIdx);
- if (cmdEnd === -1) cmdEnd = text.length;
- let cmd = text.slice(prefixIdx + CONFIG.prefix.length, cmdEnd).trim();
- for (const sep of [' - ', ' | ', ' = ', ': ']) {
- const idx = cmd.indexOf(sep);
- if (idx > 0) cmd = cmd.slice(0, idx).trim();
- }
- if (cmd) commands.push(cmd);
- pos = prefixIdx + 1;
- }
- return commands;
- }
- let registeredEvents = [];
- function handleEventData(eventName, data) {
- try {
- const text = extractMessageText(data);
- if (!text || isBotMessage(text) || !text.includes(CONFIG.prefix)) return;
- log(`Event [${eventName}]:`, text.slice(0, 50));
- for (const cmd of extractCommands(text)) {
- processCommand(cmd);
- }
- } catch (e) {
- logError("Event handler error:", e);
- }
- }
- function registerEvent(eventName) {
- try {
- w.on(eventName, (data) => handleEventData(eventName, data));
- registeredEvents.push(eventName);
- log("Registered event:", eventName);
- return true;
- } catch (e) {
- return false;
- }
- }
- function discoverAndRegisterEvents() {
- const chatEvents = [
- 'chat', 'chatMessage', 'chat_message', 'message', 'msg',
- 'receive', 'receiveMessage', 'receive_message', 'messageReceive',
- 'newMessage', 'new_message', 'newChat', 'new_chat',
- 'data', 'text', 'incoming', 'incomingMessage',
- 'chatReceive', 'chat_receive', 'onMessage', 'onChat',
- 'messageEvent', 'chatEvent'
- ];
- log("Discovering events...");
- let successCount = 0;
- for (const e of chatEvents) if (registerEvent(e)) successCount++;
- try { if (w?.events) for (const e of Object.keys(w.events)) if (!registeredEvents.includes(e) && registerEvent(e)) successCount++; } catch (e) {}
- try { if (w?._events) for (const e of Object.keys(w._events)) if (!registeredEvents.includes(e) && registerEvent(e)) successCount++; } catch (e) {}
- try { if (typeof w?.eventNames === 'function') for (const e of w.eventNames()) if (!registeredEvents.includes(e) && registerEvent(e)) successCount++; } catch (e) {}
- log(`Registered ${successCount} events`);
- return successCount > 0;
- }
- // ═══════════════════════════════════════════════════════════════
- // INITIALIZATION
- // ═══════════════════════════════════════════════════════════════
- async function initialize() {
- log("Initializing...");
- if (!w || typeof w.on !== 'function') {
- logError("w.on() not available!");
- return false;
- }
- if (!discoverAndRegisterEvents()) {
- logError("No events registered!");
- return false;
- }
- await sleep(CONFIG.startupDelay);
- if (CONFIG.announceOnStart) {
- await forceSendToChat(`${CONFIG.botTag} Illion Calc ${CONFIG.version} online! Commands: ${CONFIG.prefix}help`);
- }
- log("Ready!");
- return true;
- }
- // ═══════════════════════════════════════════════════════════════
- // START
- // ═══════════════════════════════════════════════════════════════
- console.log("═══════════════════════════════════════════════════════════");
- console.log(`[illion calc] Illion Calc ${CONFIG.version}`);
- console.log("═══════════════════════════════════════════════════════════");
- window.illionCalcConfig = CONFIG;
- window.illionCalc = {
- config: CONFIG,
- registeredEvents: () => registeredEvents,
- processCommand, formatNumber, evaluate: evaluateExpression,
- getIllionName, parseIllionName, illionToScientific,
- getSuperIllionSuffix, getSuperIllionName, getSuperIllionNameSpliced,
- getMegaIllionSuffix, getMegaIllionSuffixRaw,
- getStandardCompoundName, getGigaCompoundName, cleanupTierOverlap,
- sendOutput, sendSimpleOutput, forceSendToChat,
- BASE_SUPER_ILLIONS, SUPER_ILLIONS_1, SUPER_ILLIONS_2, SUPER_ILLIONS_3,
- MEGA_ILLIONS_1, MEGA_ILLIONS_1_REM,
- GIGA_ILLIONS_1, GIGA_ILLIONS_2, GIGA_ILLIONS_3, KIV
- };
- try {
- if (!(await initialize())) logError("Initialization failed!");
- } catch (e) {
- logError("Init error:", e);
- }
- })();
Advertisement
Add Comment
Please, Sign In to add comment