RubixYT1

Illion calculator 3.0.0 tw.2s4.me

Dec 11th, 2025 (edited)
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 54.95 KB | None | 0 0
  1. (async function illionCalcV1() {
  2. // ═══════════════════════════════════════════════════════════════
  3. // CONFIGURATION SETTINGS
  4. // ═══════════════════════════════════════════════════════════════
  5. const CONFIG = {
  6. prefix: "/",
  7. botTag: "[illion calc]",
  8. chatPollInterval: 100,
  9. commandCooldown: 500,
  10. startupDelay: 500,
  11. typingDelay: 6,
  12. maxChatLength: 180,
  13. logToConsole: true,
  14. announceOnStart: true,
  15. version: "v3.0.0",
  16. // Color IDs for typing
  17. superColorCID: 11,
  18. megaColorCID: 9,
  19. gigaColorCID: 15,
  20. teraColorCID: 7,
  21. normalColorCID: 0,
  22. // Hex colors for chat
  23. superColorHex: "#0000ff",
  24. megaColorHex: "#00aa00",
  25. gigaColorHex: "#aa00aa",
  26. teraColorHex: "#ffff00",
  27. // Mode toggles
  28. logModeEnabled: false,
  29. typeModeEnabled: false
  30. };
  31.  
  32. const SUPPORTED_OPS = "+ - * / ^ ()";
  33. const VALID_COMMANDS = ['info', 'help', 'setnum', 'input', 'convert', 'logmode', 'typemode'];
  34.  
  35. // ═══════════════════════════════════════════════════════════════
  36. // UTILITY FUNCTIONS
  37. // ═══════════════════════════════════════════════════════════════
  38. const sleep = ms => new Promise(r => setTimeout(r, ms));
  39.  
  40. function log(...args) {
  41. if (CONFIG.logToConsole) console.log("[illion calc]", ...args);
  42. }
  43.  
  44. function logError(...args) {
  45. console.error("[illion calc]", ...args);
  46. }
  47.  
  48. // ═══════════════════════════════════════════════════════════════
  49. // LOAD BREAK ETERNITY
  50. // ═══════════════════════════════════════════════════════════════
  51. async function loadBreakEternity() {
  52. if (window.Decimal) {
  53. log("Break Eternity already loaded!");
  54. return true;
  55. }
  56.  
  57. const sources = [
  58. 'https://cdn.jsdelivr.net/npm/[email protected]/break_eternity.min.js',
  59. 'https://unpkg.com/[email protected]/break_eternity.min.js',
  60. 'https://cdnjs.cloudflare.com/ajax/libs/break_eternity.js/2.0.0/break_eternity.min.js',
  61. 'https://cdn.jsdelivr.net/gh/Patashu/break_eternity.js@master/break_eternity.min.js',
  62. 'https://raw.githubusercontent.com/Patashu/break_eternity.js/master/break_eternity.min.js',
  63. 'https://cdn.jsdelivr.net/npm/break_eternity.js/break_eternity.min.js',
  64. 'https://unpkg.com/break_eternity.js/break_eternity.min.js',
  65. 'https://cdn.statically.io/gh/Patashu/break_eternity.js/master/break_eternity.min.js'
  66. ];
  67.  
  68. for (const src of sources) {
  69. try {
  70. log("Trying:", src);
  71. await new Promise((resolve, reject) => {
  72. const script = document.createElement('script');
  73. script.src = src;
  74. script.onload = resolve;
  75. script.onerror = reject;
  76. document.head.appendChild(script);
  77. });
  78. await sleep(100);
  79. if (window.Decimal) {
  80. log("Loaded from:", src);
  81. return true;
  82. }
  83. } catch (e) {
  84. log("Failed:", src);
  85. }
  86. }
  87. return false;
  88. }
  89.  
  90. const beLoaded = await loadBreakEternity();
  91. if (!beLoaded || !window.Decimal) {
  92. logError("Break Eternity failed to load!");
  93. return;
  94. }
  95. const Decimal = window.Decimal;
  96.  
  97. // ═══════════════════════════════════════════════════════════════
  98. // DECIMAL HELPERS
  99. // ═══════════════════════════════════════════════════════════════
  100.  
  101. function isDecimalNaN(num) {
  102. if (!num) return true;
  103. return Number.isNaN(num.sign) || Number.isNaN(num.layer) || Number.isNaN(num.mag);
  104. }
  105.  
  106. function isDecimalFinite(num) {
  107. if (!num) return false;
  108. return Number.isFinite(num.layer) && Number.isFinite(num.mag);
  109. }
  110.  
  111. function isDecimalPositive(num) {
  112. return num && num.sign > 0;
  113. }
  114.  
  115. // ═══════════════════════════════════════════════════════════════
  116. // ILLION NAMING SYSTEM
  117. // ═══════════════════════════════════════════════════════════════
  118.  
  119. // Standard illions 1-9
  120. const ONES_SINGLE = ['', 'M', 'B', 'T', 'Qa', 'Qi', 'Sx', 'Sp', 'Oc', 'No'];
  121. const ONES = ['', 'U', 'D', 'T', 'Qa', 'Qi', 'Sx', 'Sp', 'Oc', 'No'];
  122. const TENS = ['', 'De', 'Vi', 'Tr', 'Qu', 'Qt', 'Se', 'Si', 'Oi', 'Nn'];
  123. const HUNDREDS = ['', 'Ce', 'Du', 'Te', 'Qe', 'Qr', 'Su', 'St', 'Ot', 'Ne'];
  124.  
  125. // Base Super Illions (super index 1-10): Mi -> Ve
  126. const BASE_SUPER_ILLIONS = ['', 'Mi', 'Mc', 'Na', 'Pi', 'Fe', 'At', 'Ze', 'Yc', 'Xn', 'Ve'];
  127.  
  128. // Super Illions 1 - Ones for 11-19 and compound ones
  129. const SUPER_ILLIONS_1 = ['', 'Me', 'Duc', 'Tec', 'Ttec', 'Pnec', 'Hxec', 'Hpec', 'Ocec', 'Enec'];
  130.  
  131. // Super Illions 2 - Tens (20=Ic, 30=Tcnt, etc.)
  132. const SUPER_ILLIONS_2 = ['', 'Ic', 'Tcnt', 'Tecnt', 'Pecnt', 'Hxcnt', 'Hpcnt', 'Occnt', 'Eccnt'];
  133.  
  134. // Super Illions 3 - Hundreds (100=Hct, 200=Dhct, etc.)
  135. const SUPER_ILLIONS_3 = ['', 'Hct', 'Dhct', 'Thct', 'Tehct', 'Pehct', 'Hxhct', 'Hphct', 'Ochct', 'Enhct'];
  136.  
  137. // Mega Illions Tier 1: Base names at powers of 1000 in super index
  138. const MEGA_ILLIONS_1 = ['', 'Kil', 'Meg', 'Gig', 'Ter', 'Pet', 'Ex', 'Zet', 'Yoc', 'Xen', 'Hnd'];
  139.  
  140. // Mega Illions with remainder suffix (Kil->Kia, etc.)
  141. const MEGA_ILLIONS_1_REM = ['', 'Kia', 'Mea', 'Gia', 'Tea', 'Pea', 'Exa', 'Zea', 'Yoa', 'Xea', 'Hna'];
  142.  
  143. // Giga Illions Tier 1 (1-9 at giga level)
  144. const GIGA_ILLIONS_1 = ['', 'Kal', 'Mij', 'Gij', 'Tej', 'Pej', 'Exj', 'Zej', 'Yej', 'Xej', 'Vej'];
  145.  
  146. // Giga Illions Tier 2 (10-90 ones position at giga level)
  147. const GIGA_ILLIONS_2 = ['', 'Mej', 'Ij', 'Tecj', 'Trecj', 'Pecj', 'Hecj', 'Hpcj', 'Ocej', 'Enej'];
  148.  
  149. // Giga Illions Tier 3 (100-900 at giga level)
  150. const GIGA_ILLIONS_3 = ['', 'Hej', 'Dhej', 'Thej', 'Trhej', 'Pehej', 'Hxhej', 'Hphej', 'Ochej', 'Enhej'];
  151.  
  152. // Kiv = Tera Illion 1 (CID 7, #ffff00) at super index 10^(3*10^3000)
  153. const KIV = 'Kiv';
  154.  
  155. // Threshold for skipping normal illions (super index >= 1001 = MiKia)
  156. const SKIP_NORMAL_THRESHOLD = new Decimal(1001);
  157.  
  158. // Splice threshold - after 100 super indexes, use mod 100
  159. const SPLICE_THRESHOLD = 100;
  160.  
  161. // Tier thresholds
  162. const GIGA_THRESHOLD = Decimal.pow(10, 3000); // 10^3000
  163. const TERA_THRESHOLD = Decimal.pow(10, Decimal.pow(10, 3000).mul(3)); // 10^(3*10^3000)
  164.  
  165. // Maximum: 1e1e1e3e3003 = 10^10^10^(3*10^3003)
  166. const MAX_ILLION = Decimal.pow(10, Decimal.pow(10, Decimal.pow(10, 3003).mul(3)));
  167.  
  168. // Get standard name for illion index 1-999
  169. function getStandardName(n) {
  170. if (n <= 0 || n > 999) return '';
  171. if (n < 10) return ONES_SINGLE[n];
  172.  
  173. const ones = n % 10;
  174. const tens = Math.floor(n / 10) % 10;
  175. const hundreds = Math.floor(n / 100) % 10;
  176.  
  177. return ONES[ones] + TENS[tens] + HUNDREDS[hundreds];
  178. }
  179.  
  180. // Get standard compound name for multipliers 2-999 (using U, D, T, De, Vi, Ce, etc.)
  181. function getStandardCompoundName(n) {
  182. if (n <= 1 || n > 999) return '';
  183. if (n < 10) return ONES[n];
  184.  
  185. const ones = n % 10;
  186. const tens = Math.floor(n / 10) % 10;
  187. const hundreds = Math.floor(n / 100) % 10;
  188.  
  189. return ONES[ones] + TENS[tens] + HUNDREDS[hundreds];
  190. }
  191.  
  192. // Get super illion suffix for indices 1-999 (within a mega tier)
  193. function getSuperIllionName(superIndex) {
  194. if (superIndex <= 0 || superIndex >= 1000) return '';
  195.  
  196. // Base tier (1-10): Mi, Mc, Na, Pi, Fe, At, Ze, Yc, Xn, Ve
  197. if (superIndex <= 10) {
  198. return BASE_SUPER_ILLIONS[superIndex];
  199. }
  200.  
  201. // 11-19: Me, Duc, Tec, Ttec, Pnec, Hxec, Hpec, Ocec, Enec
  202. if (superIndex <= 19) {
  203. return SUPER_ILLIONS_1[superIndex - 10];
  204. }
  205.  
  206. // 20+: Compound naming
  207. const ones = superIndex % 10;
  208. const tens = Math.floor(superIndex / 10) % 10;
  209. const hundreds = Math.floor(superIndex / 100) % 10;
  210.  
  211. let name = '';
  212.  
  213. if (ones > 0) {
  214. name += SUPER_ILLIONS_1[ones];
  215. }
  216.  
  217. if (tens >= 2) {
  218. name += SUPER_ILLIONS_2[tens - 1];
  219. }
  220.  
  221. if (hundreds > 0) {
  222. name += SUPER_ILLIONS_3[hundreds];
  223. }
  224.  
  225. return name;
  226. }
  227.  
  228. // Get super illion name with splice (after 100, use mod 100)
  229. function getSuperIllionNameSpliced(superIndex) {
  230. if (superIndex <= 0) return '';
  231.  
  232. // Splice: if >= 100, use mod 100
  233. if (superIndex >= SPLICE_THRESHOLD) {
  234. superIndex = superIndex % SPLICE_THRESHOLD;
  235. }
  236.  
  237. if (superIndex === 0) return '';
  238. if (superIndex >= 1000) return '';
  239.  
  240. return getSuperIllionName(superIndex);
  241. }
  242.  
  243. // Get giga tier compound name for multipliers 1-999
  244. function getGigaCompoundName(index) {
  245. if (index <= 0 || index > 999) return '';
  246.  
  247. // 1-9: Use GIGA_ILLIONS_1
  248. if (index <= 9) {
  249. return GIGA_ILLIONS_1[index] || '';
  250. }
  251.  
  252. const ones = index % 10;
  253. const tens = Math.floor(index / 10) % 10;
  254. const hundreds = Math.floor(index / 100);
  255.  
  256. let name = '';
  257.  
  258. // Ones (1-9) from GIGA_ILLIONS_1
  259. if (ones >= 1 && ones <= 9) {
  260. name += GIGA_ILLIONS_1[ones] || '';
  261. }
  262.  
  263. // Tens (1-9) from GIGA_ILLIONS_2
  264. if (tens >= 1 && tens <= 9) {
  265. name += GIGA_ILLIONS_2[tens] || '';
  266. }
  267.  
  268. // Hundreds (1-9) from GIGA_ILLIONS_3
  269. if (hundreds >= 1 && hundreds <= 9) {
  270. name += GIGA_ILLIONS_3[hundreds] || '';
  271. }
  272.  
  273. return name;
  274. }
  275.  
  276. // Cleanup tier overlap - use replace() to blank out lower tiers when higher tier starts
  277. function cleanupTierOverlap(name, parts) {
  278. const hasTera = parts.some(p => p.type === 'tera');
  279. const hasGiga = parts.some(p => p.type === 'giga');
  280.  
  281. let cleanedName = name;
  282. let cleanedParts = [...parts];
  283.  
  284. if (hasTera) {
  285. // Use replace() to remove giga and mega text from name
  286. for (const part of parts) {
  287. if (part.type === 'mega' || part.type === 'giga') {
  288. cleanedName = cleanedName.replace(part.text, '');
  289. }
  290. }
  291. // Filter out mega and giga parts
  292. cleanedParts = parts.filter(p => p.type !== 'mega' && p.type !== 'giga');
  293. } else if (hasGiga) {
  294. // Use replace() to remove mega text from name
  295. for (const part of parts) {
  296. if (part.type === 'mega') {
  297. cleanedName = cleanedName.replace(part.text, '');
  298. }
  299. }
  300. // Filter out mega parts
  301. cleanedParts = parts.filter(p => p.type !== 'mega');
  302. }
  303.  
  304. return { name: cleanedName, parts: cleanedParts, isMega: true };
  305. }
  306.  
  307. // Get mega illion suffix for a given super index (Decimal)
  308. function getMegaIllionSuffix(superIndex) {
  309. if (!(superIndex instanceof Decimal)) {
  310. superIndex = new Decimal(superIndex);
  311. }
  312.  
  313. if (superIndex.lt(1000)) {
  314. return { name: '', parts: [], isMega: false };
  315. }
  316.  
  317. let parts = [];
  318. let name = '';
  319.  
  320. // Check for Tera tier first (highest)
  321. if (superIndex.gte(TERA_THRESHOLD)) {
  322. const teraPower = superIndex.div(TERA_THRESHOLD).floor();
  323. const teraRemainder = superIndex.mod(TERA_THRESHOLD);
  324.  
  325. // Get the remainder first (lower tiers) - will be cleaned up later
  326. if (teraRemainder.gte(1000)) {
  327. const remResult = getMegaIllionSuffixRaw(teraRemainder);
  328. if (remResult.name) {
  329. name += remResult.name;
  330. parts = [...parts, ...remResult.parts];
  331. }
  332. } else if (teraRemainder.gte(1)) {
  333. const splicedRemainder = teraRemainder.toNumber() % SPLICE_THRESHOLD;
  334. if (splicedRemainder > 0) {
  335. const superName = getSuperIllionName(splicedRemainder);
  336. if (superName) {
  337. name += superName;
  338. parts.push({ text: superName, type: 'super' });
  339. }
  340. }
  341. }
  342.  
  343. // Add Tera suffix
  344. if (teraPower.eq(1)) {
  345. name += KIV;
  346. parts.push({ text: KIV, type: 'tera' });
  347. } else if (teraPower.lt(1000)) {
  348. const multiplier = getGigaCompoundName(teraPower.toNumber());
  349. const kivText = multiplier + KIV;
  350. name += kivText;
  351. parts.push({ text: kivText, type: 'tera' });
  352. } else {
  353. const multResult = getMegaIllionSuffixRaw(teraPower);
  354. if (multResult.name) {
  355. name += multResult.name;
  356. parts = [...parts, ...multResult.parts];
  357. }
  358. name += KIV;
  359. parts.push({ text: KIV, type: 'tera' });
  360. }
  361.  
  362. // Apply tier cleanup using replace()
  363. return cleanupTierOverlap(name, parts);
  364. }
  365.  
  366. // Check for Giga tier
  367. if (superIndex.gte(GIGA_THRESHOLD)) {
  368. const gigaPower = superIndex.div(GIGA_THRESHOLD).floor();
  369. const gigaRemainder = superIndex.mod(GIGA_THRESHOLD);
  370.  
  371. // Get the remainder first (lower mega tiers) - will be cleaned up later
  372. if (gigaRemainder.gte(1000)) {
  373. const remResult = getMegaIllionSuffixRaw(gigaRemainder);
  374. if (remResult.name) {
  375. name += remResult.name;
  376. parts = [...parts, ...remResult.parts];
  377. }
  378. } else if (gigaRemainder.gte(1)) {
  379. const splicedRemainder = gigaRemainder.toNumber() % SPLICE_THRESHOLD;
  380. if (splicedRemainder > 0) {
  381. const superName = getSuperIllionName(splicedRemainder);
  382. if (superName) {
  383. name += superName;
  384. parts.push({ text: superName, type: 'super' });
  385. }
  386. }
  387. }
  388.  
  389. // Get giga name
  390. if (gigaPower.eq(1)) {
  391. const gigaName = GIGA_ILLIONS_1[1]; // Mij
  392. name += gigaName;
  393. parts.push({ text: gigaName, type: 'giga' });
  394. } else if (gigaPower.lt(1000)) {
  395. const gigaName = getGigaCompoundName(gigaPower.toNumber());
  396. name += gigaName;
  397. parts.push({ text: gigaName, type: 'giga' });
  398. } else {
  399. const gigaResult = getMegaIllionSuffixRaw(gigaPower);
  400. if (gigaResult.name) {
  401. name += gigaResult.name;
  402. parts = [...parts, ...gigaResult.parts];
  403. }
  404. const gigaBase = GIGA_ILLIONS_1[1];
  405. name += gigaBase;
  406. parts.push({ text: gigaBase, type: 'giga' });
  407. }
  408.  
  409. // Apply tier cleanup using replace()
  410. return cleanupTierOverlap(name, parts);
  411. }
  412.  
  413. // Mega tier (1000 to 10^3000-1)
  414. return getMegaIllionSuffixRaw(superIndex);
  415. }
  416.  
  417. // Raw mega suffix without tier cleanup (for recursion)
  418. function getMegaIllionSuffixRaw(superIndex) {
  419. if (!(superIndex instanceof Decimal)) {
  420. superIndex = new Decimal(superIndex);
  421. }
  422.  
  423. if (superIndex.lt(1000)) {
  424. return { name: '', parts: [], isMega: false };
  425. }
  426.  
  427. let parts = [];
  428. let name = '';
  429.  
  430. // Check for Giga tier
  431. if (superIndex.gte(GIGA_THRESHOLD)) {
  432. const gigaPower = superIndex.div(GIGA_THRESHOLD).floor();
  433. const gigaRemainder = superIndex.mod(GIGA_THRESHOLD);
  434.  
  435. if (gigaRemainder.gte(1000)) {
  436. const remResult = getMegaIllionSuffixRaw(gigaRemainder);
  437. if (remResult.name) {
  438. name += remResult.name;
  439. parts = [...parts, ...remResult.parts];
  440. }
  441. } else if (gigaRemainder.gte(1)) {
  442. const splicedRemainder = gigaRemainder.toNumber() % SPLICE_THRESHOLD;
  443. if (splicedRemainder > 0) {
  444. const superName = getSuperIllionName(splicedRemainder);
  445. if (superName) {
  446. name += superName;
  447. parts.push({ text: superName, type: 'super' });
  448. }
  449. }
  450. }
  451.  
  452. if (gigaPower.eq(1)) {
  453. const gigaName = GIGA_ILLIONS_1[1];
  454. name += gigaName;
  455. parts.push({ text: gigaName, type: 'giga' });
  456. } else if (gigaPower.lt(1000)) {
  457. const gigaName = getGigaCompoundName(gigaPower.toNumber());
  458. name += gigaName;
  459. parts.push({ text: gigaName, type: 'giga' });
  460. } else {
  461. const gigaResult = getMegaIllionSuffixRaw(gigaPower);
  462. if (gigaResult.name) {
  463. name += gigaResult.name;
  464. parts = [...parts, ...gigaResult.parts];
  465. }
  466. const gigaBase = GIGA_ILLIONS_1[1];
  467. name += gigaBase;
  468. parts.push({ text: gigaBase, type: 'giga' });
  469. }
  470.  
  471. return { name, parts, isMega: true };
  472. }
  473.  
  474. // Mega tier (1000 to 10^3000-1)
  475. const log10Val = superIndex.log10().toNumber();
  476. let megaTier = Math.floor(log10Val / 3);
  477.  
  478. if (megaTier > 10) megaTier = 10;
  479. if (megaTier < 1) megaTier = 1;
  480.  
  481. const tierBase = Decimal.pow(10, megaTier * 3);
  482. const tierMultiplier = superIndex.div(tierBase).floor();
  483. const tierRemainder = superIndex.mod(tierBase);
  484.  
  485. const hasRemainder = tierRemainder.gte(1);
  486.  
  487. // Handle the remainder first (lower tiers + super)
  488. if (tierRemainder.gte(1000)) {
  489. const remResult = getMegaIllionSuffixRaw(tierRemainder);
  490. if (remResult.name) {
  491. name += remResult.name;
  492. parts = [...parts, ...remResult.parts];
  493. }
  494. } else if (tierRemainder.gte(1)) {
  495. // Apply splice: if >= 100, use mod 100
  496. const splicedRemainder = tierRemainder.toNumber() % SPLICE_THRESHOLD;
  497. if (splicedRemainder > 0) {
  498. const superName = getSuperIllionName(splicedRemainder);
  499. if (superName) {
  500. name += superName;
  501. parts.push({ text: superName, type: 'super' });
  502. }
  503. }
  504. }
  505.  
  506. // Get the appropriate mega base name (Kil->Kia when has remainder)
  507. const megaBaseName = hasRemainder
  508. ? (MEGA_ILLIONS_1_REM[megaTier] || MEGA_ILLIONS_1[megaTier])
  509. : MEGA_ILLIONS_1[megaTier];
  510.  
  511. if (!megaBaseName) {
  512. return { name, parts, isMega: true };
  513. }
  514.  
  515. if (tierMultiplier.eq(1)) {
  516. name += megaBaseName;
  517. parts.push({ text: megaBaseName, type: 'mega' });
  518. } else if (tierMultiplier.lt(1000)) {
  519. const multiplier = getStandardCompoundName(tierMultiplier.toNumber());
  520. const fullName = multiplier + megaBaseName;
  521. name += fullName;
  522. parts.push({ text: fullName, type: 'mega' });
  523. } else {
  524. const multResult = getMegaIllionSuffixRaw(tierMultiplier);
  525. if (multResult.name) {
  526. name += multResult.name;
  527. parts = [...parts, ...multResult.parts];
  528. }
  529. name += megaBaseName;
  530. parts.push({ text: megaBaseName, type: 'mega' });
  531. }
  532.  
  533. return { name, parts, isMega: true };
  534. }
  535.  
  536. // Get complete suffix with proper type info for a super index
  537. function getSuperIllionSuffix(superIndex) {
  538. if (!(superIndex instanceof Decimal)) {
  539. superIndex = new Decimal(superIndex);
  540. }
  541.  
  542. if (superIndex.lte(0)) return { name: '', isSuper: false, isMega: false, parts: [] };
  543.  
  544. // Handle mega tier (1000+)
  545. if (superIndex.gte(1000)) {
  546. const megaResult = getMegaIllionSuffix(superIndex);
  547. return {
  548. name: megaResult.name,
  549. isSuper: true,
  550. isMega: true,
  551. parts: megaResult.parts
  552. };
  553. }
  554.  
  555. // Pure super tier (1-999) - apply splice
  556. const splicedIndex = superIndex.toNumber() % SPLICE_THRESHOLD;
  557. if (splicedIndex === 0) return { name: '', isSuper: false, isMega: false, parts: [] };
  558.  
  559. const superName = getSuperIllionName(splicedIndex);
  560. return {
  561. name: superName,
  562. isSuper: true,
  563. isMega: false,
  564. parts: [{ text: superName, type: 'super' }]
  565. };
  566. }
  567.  
  568. // Main illion naming function
  569. function getIllionName(illionIndex) {
  570. let num;
  571.  
  572. if (illionIndex instanceof Decimal) {
  573. num = illionIndex;
  574. } else {
  575. num = new Decimal(illionIndex);
  576. }
  577.  
  578. if (num.gte(MAX_ILLION)) return null;
  579. if (num.lte(0)) return { name: '', parts: [] };
  580.  
  581. // Simple names for 1-9
  582. if (num.lt(10)) {
  583. return {
  584. name: ONES_SINGLE[num.toNumber()],
  585. parts: [{ text: ONES_SINGLE[num.toNumber()], type: 'normal' }]
  586. };
  587. }
  588.  
  589. // Standard names for 10-999
  590. if (num.lt(1000)) {
  591. const name = getStandardName(num.toNumber());
  592. return { name, parts: [{ text: name, type: 'normal' }] };
  593. }
  594.  
  595. // Extended: 1000+ illion index
  596. const groups = [];
  597. let remaining = num;
  598. let groupIndex = new Decimal(0);
  599.  
  600. while (remaining.gte(1)) {
  601. groups.push({
  602. value: remaining.mod(1000).floor().toNumber(),
  603. index: groupIndex
  604. });
  605. remaining = remaining.div(1000).floor();
  606. groupIndex = groupIndex.add(1);
  607. }
  608.  
  609. let name = '';
  610. let parts = [];
  611.  
  612. for (let i = groups.length - 1; i >= 0; i--) {
  613. const group = groups[i];
  614.  
  615. if (group.value === 0) continue;
  616.  
  617. // Check if this group's index is >= 1001 (MiKia and above)
  618. const isInHighMegaTier = group.index.gte(SKIP_NORMAL_THRESHOLD);
  619.  
  620. if (!isInHighMegaTier) {
  621. let groupName;
  622. if (i === groups.length - 1 && group.value < 10) {
  623. groupName = ONES_SINGLE[group.value];
  624. } else {
  625. groupName = getStandardName(group.value);
  626. }
  627.  
  628. if (groupName) {
  629. parts.push({ text: groupName, type: 'normal' });
  630. name += groupName;
  631. }
  632. }
  633.  
  634. // Add super/mega suffix for non-zero group index
  635. if (group.index.gt(0)) {
  636. const suffix = getSuperIllionSuffix(group.index);
  637. if (suffix.name) {
  638. parts = [...parts, ...suffix.parts];
  639. name += suffix.name;
  640. }
  641. }
  642. }
  643.  
  644. return { name, parts };
  645. }
  646.  
  647. // ═══════════════════════════════════════════════════════════════
  648. // ILLION CONVERTER
  649. // ═══════════════════════════════════════════════════════════════
  650.  
  651. function parseIllionName(input) {
  652. input = input.trim();
  653.  
  654. if (!input) return null;
  655. if (/^\d+$/.test(input)) return new Decimal(input);
  656.  
  657. for (let i = 1; i <= 9; i++) {
  658. if (input === ONES_SINGLE[i]) return new Decimal(i);
  659. }
  660.  
  661. return null;
  662. }
  663.  
  664. function illionToScientific(illionIndex) {
  665. if (!(illionIndex instanceof Decimal)) {
  666. illionIndex = new Decimal(illionIndex);
  667. }
  668.  
  669. const exponent = illionIndex.mul(3).add(3);
  670.  
  671. if (exponent.lt(1e6)) {
  672. return `1e${exponent.toFixed(0)}`;
  673. } else if (exponent.lt(1e15)) {
  674. return `1e${exponent.toPrecision(6)}`;
  675. } else {
  676. const expLog = exponent.log10();
  677. if (expLog.lt(1e15)) {
  678. return `10^10^${expLog.toFixed(3)}`;
  679. } else {
  680. const expLogLog = expLog.log10();
  681. return `10^10^10^${expLogLog.toFixed(3)}`;
  682. }
  683. }
  684. }
  685.  
  686. // ═══════════════════════════════════════════════════════════════
  687. // OUTPUT FUNCTIONS
  688. // ═══════════════════════════════════════════════════════════════
  689.  
  690. function buildChatMessage(prefix, parts) {
  691. let message = prefix;
  692.  
  693. for (const part of parts) {
  694. if (part.type === 'super') {
  695. message += `<start ${CONFIG.superColorHex}>${part.text}<end>`;
  696. } else if (part.type === 'mega') {
  697. message += `<start ${CONFIG.megaColorHex}>${part.text}<end>`;
  698. } else if (part.type === 'giga') {
  699. message += `<start ${CONFIG.gigaColorHex}>${part.text}<end>`;
  700. } else if (part.type === 'tera') {
  701. message += `<start ${CONFIG.teraColorHex}>${part.text}<end>`;
  702. } else {
  703. message += part.text;
  704. }
  705. }
  706.  
  707. return message;
  708. }
  709.  
  710. function buildPlainMessage(prefix, parts) {
  711. let message = prefix;
  712. for (const part of parts) {
  713. message += part.text;
  714. }
  715. return message;
  716. }
  717.  
  718. async function typeText(text, colorCID = CONFIG.normalColorCID) {
  719. try {
  720. w.changeColor(colorCID);
  721. } catch (e) {}
  722.  
  723. for (let i = 0; i < text.length; i++) {
  724. try {
  725. w.typeChar(text[i], 1);
  726. } catch (e) {}
  727. await sleep(CONFIG.typingDelay);
  728. }
  729. }
  730.  
  731. async function typeColoredOutput(parts) {
  732. for (const part of parts) {
  733. let colorCID = CONFIG.normalColorCID;
  734.  
  735. if (part.type === 'super') {
  736. colorCID = CONFIG.superColorCID;
  737. } else if (part.type === 'mega') {
  738. colorCID = CONFIG.megaColorCID;
  739. } else if (part.type === 'giga') {
  740. colorCID = CONFIG.gigaColorCID;
  741. } else if (part.type === 'tera') {
  742. colorCID = CONFIG.teraColorCID;
  743. }
  744.  
  745. await typeText(part.text, colorCID);
  746. }
  747.  
  748. try {
  749. w.changeColor(CONFIG.normalColorCID);
  750. w.typeChar('\n', 1);
  751. } catch (e) {}
  752. }
  753.  
  754. async function forceSendToChat(message) {
  755. try {
  756. const result = w.chat.send(message);
  757. if (result !== false) {
  758. log("Force sent:", message);
  759. return true;
  760. }
  761. } catch (e) {
  762. log("Force send failed:", e);
  763. }
  764. return false;
  765. }
  766.  
  767. async function sendOutput(prefix, parts = []) {
  768. const plainMessage = buildPlainMessage(prefix, parts);
  769. const coloredMessage = buildChatMessage(prefix, parts);
  770.  
  771. if (CONFIG.typeModeEnabled) {
  772. log("TypeMode: typing output...");
  773. const contentParts = [{ text: prefix.replace(CONFIG.botTag + ' ', ''), type: 'normal' }, ...parts];
  774. await typeColoredOutput(contentParts);
  775. return true;
  776. }
  777.  
  778. if (plainMessage.length > CONFIG.maxChatLength) {
  779. log("Message too long, typing instead...");
  780. const contentParts = [{ text: prefix.replace(CONFIG.botTag + ' ', ''), type: 'normal' }, ...parts];
  781. await typeColoredOutput(contentParts);
  782. return true;
  783. }
  784.  
  785. try {
  786. const result = w.chat.send(coloredMessage);
  787. if (result !== false) {
  788. log("Sent:", plainMessage);
  789. return true;
  790. }
  791. } catch (e) {
  792. log("Chat failed, typing instead...");
  793. }
  794.  
  795. const contentParts = [{ text: prefix.replace(CONFIG.botTag + ' ', ''), type: 'normal' }, ...parts];
  796. await typeColoredOutput(contentParts);
  797. return true;
  798. }
  799.  
  800. async function sendSimpleOutput(message) {
  801. if (CONFIG.typeModeEnabled) {
  802. log("TypeMode: typing output...");
  803. const content = message.replace(CONFIG.botTag + ' ', '');
  804. await typeText(content, CONFIG.normalColorCID);
  805. try { w.typeChar('\n', 1); } catch (e) {}
  806. return true;
  807. }
  808.  
  809. if (message.length > CONFIG.maxChatLength) {
  810. log("Message too long, typing instead...");
  811. const content = message.replace(CONFIG.botTag + ' ', '');
  812. await typeText(content, CONFIG.normalColorCID);
  813. try { w.typeChar('\n', 1); } catch (e) {}
  814. return true;
  815. }
  816.  
  817. try {
  818. const result = w.chat.send(message);
  819. if (result !== false) {
  820. log("Sent:", message);
  821. return true;
  822. }
  823. } catch (e) {}
  824.  
  825. const content = message.replace(CONFIG.botTag + ' ', '');
  826. await typeText(content, CONFIG.normalColorCID);
  827. try { w.typeChar('\n', 1); } catch (e) {}
  828. return true;
  829. }
  830.  
  831. function formatLogMode(num) {
  832. if (!(num instanceof Decimal)) {
  833. num = new Decimal(num);
  834. }
  835.  
  836. if (isDecimalNaN(num)) return 'NaN';
  837. if (!isDecimalFinite(num)) return isDecimalPositive(num) ? 'Infinity' : '-Infinity';
  838.  
  839. const isNeg = num.lt(0);
  840. num = num.abs();
  841. const prefix = isNeg ? '-' : '';
  842.  
  843. if (num.eq(0)) return '0';
  844. if (num.lt(1e-6) || num.gte(1e6)) {
  845. const log10 = num.log10();
  846. const exp = log10.floor();
  847. const mantissa = num.div(Decimal.pow(10, exp));
  848. return `${prefix}${mantissa.toFixed(6)} * 10^${exp.toFixed(0)}`;
  849. }
  850.  
  851. return prefix + num.toFixed(6);
  852. }
  853.  
  854. function formatNumber(num) {
  855. if (!(num instanceof Decimal)) {
  856. try {
  857. num = new Decimal(num);
  858. } catch (e) {
  859. return { text: 'Invalid Number', parts: [{ text: 'Invalid Number', type: 'normal' }] };
  860. }
  861. }
  862.  
  863. if (isDecimalNaN(num)) {
  864. return { text: 'NaN', parts: [{ text: 'NaN', type: 'normal' }] };
  865. }
  866.  
  867. if (!isDecimalFinite(num)) {
  868. const text = isDecimalPositive(num) ? 'Infinity' : '-Infinity';
  869. return { text, parts: [{ text, type: 'normal' }] };
  870. }
  871.  
  872. if (CONFIG.logModeEnabled) {
  873. const text = formatLogMode(num);
  874. return { text, parts: [{ text, type: 'normal' }] };
  875. }
  876.  
  877. const isNeg = num.lt(0);
  878. num = num.abs();
  879. const prefix = isNeg ? '-' : '';
  880.  
  881. if (num.lt(1000)) {
  882. const text = prefix + num.toFixed(3);
  883. return { text, parts: [{ text, type: 'normal' }] };
  884. }
  885. if (num.lt(1e6)) {
  886. const text = prefix + num.toFixed(0);
  887. return { text, parts: [{ text, type: 'normal' }] };
  888. }
  889.  
  890. const log10 = num.log10();
  891. if (log10.lt(6)) {
  892. const text = prefix + num.toPrecision(6);
  893. return { text, parts: [{ text, type: 'normal' }] };
  894. }
  895.  
  896. const illionIndex = log10.sub(3).div(3).floor();
  897. const exponent = illionIndex.mul(3).add(3);
  898. const mantissa = num.div(Decimal.pow(10, exponent));
  899.  
  900. const illionResult = getIllionName(illionIndex);
  901.  
  902. if (illionResult === null) {
  903. return {
  904. text: "Too Big to Calculate.",
  905. parts: [{ text: "Too Big to Calculate.", type: 'normal' }]
  906. };
  907. }
  908.  
  909. const mantissaText = prefix + mantissa.toFixed(3) + ' ';
  910. const parts = [{ text: mantissaText, type: 'normal' }, ...illionResult.parts];
  911.  
  912. return { text: mantissaText + illionResult.name, parts };
  913. }
  914.  
  915. // ═══════════════════════════════════════════════════════════════
  916. // EXPRESSION PARSER
  917. // ═══════════════════════════════════════════════════════════════
  918.  
  919. function isValidExpression(expr) {
  920. if (!expr || expr.trim().length === 0) return false;
  921. return /\d/.test(expr) && /^[\d\s+\-*/^().eE]+$/.test(expr);
  922. }
  923.  
  924. function tokenize(expr) {
  925. const tokens = [];
  926. let current = '';
  927. let lastWasOp = true;
  928.  
  929. for (let i = 0; i < expr.length; i++) {
  930. const char = expr[i];
  931.  
  932. if (/[\d.]/.test(char)) {
  933. current += char;
  934. lastWasOp = false;
  935. } else if (/[eE]/.test(char) && current.length > 0) {
  936. current += char;
  937. } else if (/[+-]/.test(char) && current.match(/[eE]$/)) {
  938. current += char;
  939. } else if (/[+-]/.test(char) && lastWasOp) {
  940. current += char;
  941. } else if (/[+\-*/^()]/.test(char)) {
  942. if (current) {
  943. tokens.push({ type: 'num', value: current });
  944. current = '';
  945. }
  946. tokens.push({ type: 'op', value: char });
  947. lastWasOp = char !== ')';
  948. } else if (char === ' ') {
  949. if (current) {
  950. tokens.push({ type: 'num', value: current });
  951. current = '';
  952. }
  953. }
  954. }
  955. if (current) tokens.push({ type: 'num', value: current });
  956. return tokens;
  957. }
  958.  
  959. function evaluateExpression(expr) {
  960. expr = expr.trim().replace(/\s+/g, ' ').replace(/×/g, '*').replace(/÷/g, '/').replace(/\*\*/g, '^');
  961.  
  962. if (!isValidExpression(expr)) {
  963. return { success: false, error: 'Invalid Operation.' };
  964. }
  965.  
  966. try {
  967. const tokens = tokenize(expr);
  968. if (tokens.length === 0) return { success: false, error: 'Invalid Operation.' };
  969.  
  970. const outputQueue = [];
  971. const operatorStack = [];
  972. const precedence = { '+': 1, '-': 1, '*': 2, '/': 2, '^': 3 };
  973. const rightAssoc = { '^': true };
  974.  
  975. for (const token of tokens) {
  976. if (token.type === 'num') {
  977. try {
  978. outputQueue.push(new Decimal(token.value));
  979. } catch (e) {
  980. return { success: false, error: `Invalid number: ${token.value}` };
  981. }
  982. } else if (token.value === '(') {
  983. operatorStack.push(token);
  984. } else if (token.value === ')') {
  985. while (operatorStack.length && operatorStack[operatorStack.length - 1].value !== '(') {
  986. outputQueue.push(operatorStack.pop());
  987. }
  988. if (operatorStack.length) operatorStack.pop();
  989. } else if (precedence[token.value] !== undefined) {
  990. while (
  991. operatorStack.length &&
  992. operatorStack[operatorStack.length - 1].value !== '(' &&
  993. precedence[operatorStack[operatorStack.length - 1].value] !== undefined &&
  994. (precedence[operatorStack[operatorStack.length - 1].value] > precedence[token.value] ||
  995. (precedence[operatorStack[operatorStack.length - 1].value] === precedence[token.value] &&
  996. !rightAssoc[token.value]))
  997. ) {
  998. outputQueue.push(operatorStack.pop());
  999. }
  1000. operatorStack.push(token);
  1001. }
  1002. }
  1003.  
  1004. while (operatorStack.length) outputQueue.push(operatorStack.pop());
  1005.  
  1006. const evalStack = [];
  1007. for (const item of outputQueue) {
  1008. if (item instanceof Decimal) {
  1009. evalStack.push(item);
  1010. } else if (item.type === 'op') {
  1011. if (evalStack.length < 2) {
  1012. if (evalStack.length === 1) continue;
  1013. return { success: false, error: 'Invalid Operation.' };
  1014. }
  1015. const b = evalStack.pop();
  1016. const a = evalStack.pop();
  1017.  
  1018. switch (item.value) {
  1019. case '+': evalStack.push(a.add(b)); break;
  1020. case '-': evalStack.push(a.sub(b)); break;
  1021. case '*': evalStack.push(a.mul(b)); break;
  1022. case '/': evalStack.push(a.div(b)); break;
  1023. case '^': evalStack.push(a.pow(b)); break;
  1024. }
  1025. }
  1026. }
  1027.  
  1028. return evalStack.length === 1
  1029. ? { success: true, result: evalStack[0] }
  1030. : { success: false, error: 'Invalid Operation.' };
  1031. } catch (e) {
  1032. return { success: false, error: e.message || 'Unknown error' };
  1033. }
  1034. }
  1035.  
  1036. // ═══════════════════════════════════════════════════════════════
  1037. // COMMAND HANDLERS
  1038. // ═══════════════════════════════════════════════════════════════
  1039.  
  1040. async function handleInfo() {
  1041. const logModeStatus = CONFIG.logModeEnabled ? 'ON' : 'OFF';
  1042. const typeModeStatus = CONFIG.typeModeEnabled ? 'ON' : 'OFF';
  1043. await sendSimpleOutput(`${CONFIG.botTag} Version: ${CONFIG.version} | Ops: ${SUPPORTED_OPS} | LogMode: ${logModeStatus} | TypeMode: ${typeModeStatus}`);
  1044. }
  1045.  
  1046. async function handleHelp() {
  1047. 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`);
  1048. }
  1049.  
  1050. async function handleLogMode() {
  1051. CONFIG.logModeEnabled = !CONFIG.logModeEnabled;
  1052. const status = CONFIG.logModeEnabled ? 'ENABLED' : 'DISABLED';
  1053. await sendSimpleOutput(`${CONFIG.botTag} Log mode ${status}`);
  1054. log(`Log mode: ${status}`);
  1055. }
  1056.  
  1057. async function handleTypeMode() {
  1058. const newStatus = !CONFIG.typeModeEnabled;
  1059. const statusText = newStatus ? 'ENABLED' : 'DISABLED';
  1060.  
  1061. await forceSendToChat(`${CONFIG.botTag} Type mode ${statusText} - output will be typed instead of sent to chat`);
  1062.  
  1063. CONFIG.typeModeEnabled = newStatus;
  1064. log(`Type mode: ${statusText}`);
  1065. }
  1066.  
  1067. async function handleSetNum(args) {
  1068. const parts = args.trim().split(/\s+/);
  1069.  
  1070. if (parts.length < 2 || !parts[0] || !parts[1]) {
  1071. await sendSimpleOutput(`${CONFIG.botTag} Usage: ${CONFIG.prefix}setnum <mantissa> <exponent>`);
  1072. return;
  1073. }
  1074.  
  1075. const mantissa = parseFloat(parts[0]);
  1076. const exponent = parseFloat(parts[1]);
  1077.  
  1078. if (Number.isNaN(mantissa)) {
  1079. await sendSimpleOutput(`${CONFIG.botTag} Invalid mantissa: ${parts[0]}`);
  1080. return;
  1081. }
  1082.  
  1083. if (Number.isNaN(exponent)) {
  1084. await sendSimpleOutput(`${CONFIG.botTag} Invalid exponent: ${parts[1]}`);
  1085. return;
  1086. }
  1087.  
  1088. try {
  1089. const num = new Decimal(mantissa).mul(Decimal.pow(10, exponent));
  1090. const formatted = formatNumber(num);
  1091.  
  1092. const prefix = `${CONFIG.botTag} ${mantissa}e${exponent} = `;
  1093. await sendOutput(prefix, formatted.parts);
  1094. } catch (e) {
  1095. await sendSimpleOutput(`${CONFIG.botTag} Error: ${e.message}`);
  1096. }
  1097. }
  1098.  
  1099. async function handleInput(args) {
  1100. if (!args || !args.trim()) {
  1101. await sendSimpleOutput(`${CONFIG.botTag} Usage: ${CONFIG.prefix}input <expression>`);
  1102. return;
  1103. }
  1104.  
  1105. const expr = args.trim();
  1106.  
  1107. if (!isValidExpression(expr)) {
  1108. await sendSimpleOutput(`${CONFIG.botTag} Invalid Operation.`);
  1109. return;
  1110. }
  1111.  
  1112. const evalResult = evaluateExpression(expr);
  1113.  
  1114. if (evalResult.success) {
  1115. const formatted = formatNumber(evalResult.result);
  1116. const prefix = `${CONFIG.botTag} ${expr} = `;
  1117. await sendOutput(prefix, formatted.parts);
  1118. } else {
  1119. await sendSimpleOutput(`${CONFIG.botTag} Error: ${evalResult.error}`);
  1120. }
  1121. }
  1122.  
  1123. async function handleConvert(args) {
  1124. if (!args || !args.trim()) {
  1125. await sendSimpleOutput(`${CONFIG.botTag} Usage: ${CONFIG.prefix}convert <illion name or index>`);
  1126. return;
  1127. }
  1128.  
  1129. const input = args.trim();
  1130. let illionIndex = parseIllionName(input);
  1131.  
  1132. if (illionIndex === null) {
  1133. try {
  1134. illionIndex = new Decimal(input);
  1135. } catch (e) {
  1136. await sendSimpleOutput(`${CONFIG.botTag} Invalid illion: ${input}`);
  1137. return;
  1138. }
  1139. }
  1140.  
  1141. try {
  1142. const illionResult = getIllionName(illionIndex);
  1143. const scientific = illionToScientific(illionIndex);
  1144.  
  1145. if (illionResult === null) {
  1146. await sendSimpleOutput(`${CONFIG.botTag} Illion too large to name.`);
  1147. return;
  1148. }
  1149.  
  1150. const prefix = `${CONFIG.botTag} `;
  1151. const suffix = ` (index ${illionIndex.toString()}) = ${scientific}`;
  1152. const allParts = [
  1153. ...illionResult.parts,
  1154. { text: suffix, type: 'normal' }
  1155. ];
  1156.  
  1157. await sendOutput(prefix, allParts);
  1158. } catch (e) {
  1159. await sendSimpleOutput(`${CONFIG.botTag} Error: ${e.message}`);
  1160. }
  1161. }
  1162.  
  1163. async function handleExpression(expr) {
  1164. if (!expr || !expr.trim()) return;
  1165.  
  1166. const expression = expr.trim();
  1167.  
  1168. if (!isValidExpression(expression)) {
  1169. await sendSimpleOutput(`${CONFIG.botTag} Invalid Operation.`);
  1170. return;
  1171. }
  1172.  
  1173. const evalResult = evaluateExpression(expression);
  1174.  
  1175. if (evalResult.success) {
  1176. const formatted = formatNumber(evalResult.result);
  1177. const prefix = `${CONFIG.botTag} ${expression} = `;
  1178. await sendOutput(prefix, formatted.parts);
  1179. } else {
  1180. await sendSimpleOutput(`${CONFIG.botTag} Error: ${evalResult.error}`);
  1181. }
  1182. }
  1183.  
  1184. // ═══════════════════════════════════════════════════════════════
  1185. // COMMAND PROCESSOR
  1186. // ═══════════════════════════════════════════════════════════════
  1187.  
  1188. let processedCommands = new Map();
  1189.  
  1190. async function processCommand(fullCommand) {
  1191. if (!fullCommand || typeof fullCommand !== 'string') return;
  1192.  
  1193. const cmd = fullCommand.trim();
  1194. if (!cmd) return;
  1195.  
  1196. const now = Date.now();
  1197. const lastTime = processedCommands.get(cmd);
  1198. if (lastTime && (now - lastTime) < CONFIG.commandCooldown) return;
  1199. processedCommands.set(cmd, now);
  1200.  
  1201. if (processedCommands.size > 100) {
  1202. processedCommands = new Map(Array.from(processedCommands.entries()).slice(-50));
  1203. }
  1204.  
  1205. log("Processing:", cmd);
  1206.  
  1207. const spaceIndex = cmd.indexOf(' ');
  1208. const cmdName = spaceIndex > -1 ? cmd.slice(0, spaceIndex).toLowerCase() : cmd.toLowerCase();
  1209. const cmdArgs = spaceIndex > -1 ? cmd.slice(spaceIndex + 1) : '';
  1210.  
  1211. switch (cmdName) {
  1212. case 'info': await handleInfo(); return;
  1213. case 'help': await handleHelp(); return;
  1214. case 'setnum': await handleSetNum(cmdArgs); return;
  1215. case 'input': await handleInput(cmdArgs); return;
  1216. case 'convert': await handleConvert(cmdArgs); return;
  1217. case 'logmode': await handleLogMode(); return;
  1218. case 'typemode': await handleTypeMode(); return;
  1219. }
  1220.  
  1221. if (/^[a-zA-Z]+$/.test(cmdName) && !VALID_COMMANDS.includes(cmdName)) {
  1222. await sendSimpleOutput(`${CONFIG.botTag} Invalid Command.`);
  1223. return;
  1224. }
  1225.  
  1226. if (/[\d]/.test(cmd)) {
  1227. await handleExpression(cmd);
  1228. } else {
  1229. await sendSimpleOutput(`${CONFIG.botTag} Invalid Command.`);
  1230. }
  1231. }
  1232.  
  1233. // ═══════════════════════════════════════════════════════════════
  1234. // MESSAGE & EVENT SYSTEM
  1235. // ═══════════════════════════════════════════════════════════════
  1236.  
  1237. function extractMessageText(data) {
  1238. if (!data) return null;
  1239. if (typeof data === 'string') return data.trim();
  1240. if (typeof data === 'object') {
  1241. for (const prop of ['message', 'msg', 'text', 'content', 'chat', 'data', 'body', 'value', 'payload']) {
  1242. if (data[prop]) {
  1243. const extracted = extractMessageText(data[prop]);
  1244. if (extracted) return extracted;
  1245. }
  1246. }
  1247. }
  1248. return null;
  1249. }
  1250.  
  1251. function isBotMessage(text) {
  1252. return !text || text.includes(CONFIG.botTag);
  1253. }
  1254.  
  1255. function extractCommands(text) {
  1256. const commands = [];
  1257. if (!text || typeof text !== 'string' || isBotMessage(text)) return commands;
  1258.  
  1259. let pos = 0;
  1260. while (pos < text.length) {
  1261. const prefixIdx = text.indexOf(CONFIG.prefix, pos);
  1262. if (prefixIdx === -1) break;
  1263.  
  1264. let cmdEnd = text.indexOf('\n', prefixIdx);
  1265. if (cmdEnd === -1) cmdEnd = text.length;
  1266.  
  1267. let cmd = text.slice(prefixIdx + CONFIG.prefix.length, cmdEnd).trim();
  1268.  
  1269. for (const sep of [' - ', ' | ', ' = ', ': ']) {
  1270. const idx = cmd.indexOf(sep);
  1271. if (idx > 0) cmd = cmd.slice(0, idx).trim();
  1272. }
  1273.  
  1274. if (cmd) commands.push(cmd);
  1275. pos = prefixIdx + 1;
  1276. }
  1277.  
  1278. return commands;
  1279. }
  1280.  
  1281. let registeredEvents = [];
  1282.  
  1283. function handleEventData(eventName, data) {
  1284. try {
  1285. const text = extractMessageText(data);
  1286. if (!text || isBotMessage(text) || !text.includes(CONFIG.prefix)) return;
  1287.  
  1288. log(`Event [${eventName}]:`, text.slice(0, 50));
  1289.  
  1290. for (const cmd of extractCommands(text)) {
  1291. processCommand(cmd);
  1292. }
  1293. } catch (e) {
  1294. logError("Event handler error:", e);
  1295. }
  1296. }
  1297.  
  1298. function registerEvent(eventName) {
  1299. try {
  1300. w.on(eventName, (data) => handleEventData(eventName, data));
  1301. registeredEvents.push(eventName);
  1302. log("Registered event:", eventName);
  1303. return true;
  1304. } catch (e) {
  1305. return false;
  1306. }
  1307. }
  1308.  
  1309. function discoverAndRegisterEvents() {
  1310. const chatEvents = [
  1311. 'chat', 'chatMessage', 'chat_message', 'message', 'msg',
  1312. 'receive', 'receiveMessage', 'receive_message', 'messageReceive',
  1313. 'newMessage', 'new_message', 'newChat', 'new_chat',
  1314. 'data', 'text', 'incoming', 'incomingMessage',
  1315. 'chatReceive', 'chat_receive', 'onMessage', 'onChat',
  1316. 'messageEvent', 'chatEvent'
  1317. ];
  1318.  
  1319. log("Discovering events...");
  1320. let successCount = 0;
  1321.  
  1322. for (const e of chatEvents) if (registerEvent(e)) successCount++;
  1323.  
  1324. try { if (w?.events) for (const e of Object.keys(w.events)) if (!registeredEvents.includes(e) && registerEvent(e)) successCount++; } catch (e) {}
  1325. try { if (w?._events) for (const e of Object.keys(w._events)) if (!registeredEvents.includes(e) && registerEvent(e)) successCount++; } catch (e) {}
  1326. try { if (typeof w?.eventNames === 'function') for (const e of w.eventNames()) if (!registeredEvents.includes(e) && registerEvent(e)) successCount++; } catch (e) {}
  1327.  
  1328. log(`Registered ${successCount} events`);
  1329. return successCount > 0;
  1330. }
  1331.  
  1332. // ═══════════════════════════════════════════════════════════════
  1333. // INITIALIZATION
  1334. // ═══════════════════════════════════════════════════════════════
  1335.  
  1336. async function initialize() {
  1337. log("Initializing...");
  1338.  
  1339. if (!w || typeof w.on !== 'function') {
  1340. logError("w.on() not available!");
  1341. return false;
  1342. }
  1343.  
  1344. if (!discoverAndRegisterEvents()) {
  1345. logError("No events registered!");
  1346. return false;
  1347. }
  1348.  
  1349. await sleep(CONFIG.startupDelay);
  1350.  
  1351. if (CONFIG.announceOnStart) {
  1352. await forceSendToChat(`${CONFIG.botTag} Illion Calc ${CONFIG.version} online! Commands: ${CONFIG.prefix}help`);
  1353. }
  1354.  
  1355. log("Ready!");
  1356. return true;
  1357. }
  1358.  
  1359. // ═══════════════════════════════════════════════════════════════
  1360. // START
  1361. // ═══════════════════════════════════════════════════════════════
  1362.  
  1363. console.log("═══════════════════════════════════════════════════════════");
  1364. console.log(`[illion calc] Illion Calc ${CONFIG.version}`);
  1365. console.log("═══════════════════════════════════════════════════════════");
  1366.  
  1367. window.illionCalcConfig = CONFIG;
  1368. window.illionCalc = {
  1369. config: CONFIG,
  1370. registeredEvents: () => registeredEvents,
  1371. processCommand, formatNumber, evaluate: evaluateExpression,
  1372. getIllionName, parseIllionName, illionToScientific,
  1373. getSuperIllionSuffix, getSuperIllionName, getSuperIllionNameSpliced,
  1374. getMegaIllionSuffix, getMegaIllionSuffixRaw,
  1375. getStandardCompoundName, getGigaCompoundName, cleanupTierOverlap,
  1376. sendOutput, sendSimpleOutput, forceSendToChat,
  1377. BASE_SUPER_ILLIONS, SUPER_ILLIONS_1, SUPER_ILLIONS_2, SUPER_ILLIONS_3,
  1378. MEGA_ILLIONS_1, MEGA_ILLIONS_1_REM,
  1379. GIGA_ILLIONS_1, GIGA_ILLIONS_2, GIGA_ILLIONS_3, KIV
  1380. };
  1381.  
  1382. try {
  1383. if (!(await initialize())) logError("Initialization failed!");
  1384. } catch (e) {
  1385. logError("Init error:", e);
  1386. }
  1387.  
  1388. })();
Advertisement
Add Comment
Please, Sign In to add comment