Guest User

Untitled

a guest
Jan 15th, 2025
45
-1
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 66.94 KB | None | 0 1
  1.  
  2. (async () => {
  3. const { Client, GatewayIntentBits, Partials, Options, Collection, ChannelType, PermissionsBitField, VoiceConnectionStatus , InteractionType } = require('discord.js')
  4. const { ActionRowBuilder, StringSelectMenuOptionBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder,StringSelectMenuBuilder, ModalBuilder, TextInputBuilder, TextInputStyle, ComponentType } = require('discord.js');
  5. // const { addDeletedMessage, deleteOldMessages } = require('./database');
  6. const { connectToDatabase, getCollections } = require('./database/connection');
  7.  
  8. await connectToDatabase();
  9. const {
  10. channelsCollection,
  11. usersCollection,
  12. gamesCollection,
  13. rankingsCollection,
  14. prefixesCollection,
  15. commandStatusCollection,
  16. loveDataCollection,
  17. wordchainChannelsCollection,
  18. wordchainRoundsCollection,
  19. wordchainWordsCollection,
  20. toggleStatesCollection,
  21. countChannelsCollection,
  22. romanCountChannelsCollection,
  23. restrictionsCollection,
  24. afkUsersCollection,
  25. afkTagsCollection,
  26. } = getCollections();
  27. const chokidar = require('chokidar');
  28. const path = require('path');
  29. const config = require('./config.json');
  30. const defaultPrefix = config.prefix;
  31. const fs = require('fs');
  32. const NodeCache = require('node-cache');
  33. const wordsE = fs.readFileSync(path.resolve(__dirname, './data/wordsE.txt'), 'utf-8').split('\n').map(word => word.trim().toLowerCase());
  34. const dataPath = path.resolve(__dirname, './data/data.json')
  35. const wordDataPath = path.resolve(__dirname, './data/word-data.json')
  36. const queryPath = path.resolve(__dirname, './data/query.txt')
  37. const wordPlayedPath = path.resolve(__dirname, './data/word-played.txt')
  38. const roundPlayedPath = path.resolve(__dirname, './data/round-played.txt')
  39. const wordDataUrl = 'https://edit.thanhxuan.xyz/words.txt'
  40. const wordDatabasePath = path.resolve(__dirname, './data/words.txt')
  41. const rankingPath = path.resolve(__dirname, './data/ranking.json')
  42. const reportWordsPath = path.resolve(__dirname, './data/report-words.txt')
  43. const officalWordsPath = path.resolve(__dirname, './data/official-words.txt')
  44. const axios = require('axios')
  45. const dictionary = require('./utils/dictionary')
  46. const stats = require('./utils/stats')
  47. if (!fs.existsSync(dataPath)) {fs.writeFileSync(dataPath, JSON.stringify(emptyData))} else {}
  48. if (!fs.existsSync(wordDataPath)) {fs.writeFileSync(wordDataPath, JSON.stringify(emptyData))} else {}
  49. if (!fs.existsSync(queryPath)) {fs.writeFileSync(queryPath, '0')} else {}
  50. if (!fs.existsSync(rankingPath)) {fs.writeFileSync(rankingPath, JSON.stringify(emptyData))} else {}
  51. if (!fs.existsSync(reportWordsPath)) {fs.writeFileSync(reportWordsPath, '')} else {}
  52. if (!fs.existsSync(officalWordsPath)) {fs.writeFileSync(officalWordsPath, '')} else {}
  53. if (!fs.existsSync(wordPlayedPath)) {fs.writeFileSync(wordPlayedPath, '0')} else {}
  54. if (!fs.existsSync(roundPlayedPath)) {fs.writeFileSync(roundPlayedPath, '0')} else {}
  55. const numberEmojis = [
  56. '<:0_:1257549818553827348>',
  57. '<:1_:1257549823767216178>',
  58. '<:2_:1257549815773003859>',
  59. '<:3_:1257549813730250913>',
  60. '<:4_:1257549811524308992>',
  61. '<:5_:1257549809091608586>',
  62. '<:6_:1257549806717370379>',
  63. '<:7_:1257549804582473828>',
  64. '<:8_:1257549802468802691>',
  65. '<:9_:1257549800069533818>',
  66. ];
  67. // Bắt các lỗi Promise chưa được xử lý trên toàn bộ quá trình
  68. process.on('unhandledRejection', (reason, promise) => {
  69. console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  70. });
  71.  
  72. const client = new Client({
  73. intents: [
  74. GatewayIntentBits.GuildMembers,
  75. GatewayIntentBits.Guilds,
  76. GatewayIntentBits.GuildMessages,
  77. GatewayIntentBits.MessageContent, // Lấy nội dung tin nhắn
  78. // GatewayIntentBits.DirectMessages,
  79. GatewayIntentBits.GuildVoiceStates,
  80. GatewayIntentBits.GuildMessageReactions
  81. ]
  82. // ,partials: [
  83. // Partials.Message,
  84. // Partials.Channel,
  85. // Partials.Reaction,
  86. // Partials.GuildMember,
  87. // Partials.User,
  88. // Partials.GuildScheduledEvent
  89. // ],
  90. // makeCache: Options.cacheWithLimits({
  91. // MessageManager: 300,
  92. // PresenceManager: 0,
  93. // GuildMemberManager: 200,
  94. // UserManager: 200
  95. // }),
  96. // restTimeOffset: 250,
  97. });
  98.  
  99. // client.on('debug', console.log);
  100. // client.rest.on('rateLimited', console.log);
  101. // load word data
  102. if (!fs.existsSync(wordDatabasePath)) {
  103. axios.get(wordDataUrl)
  104. .then(async res => {
  105. const lines = res.data.trim().split('\n')
  106. const wordsdb = lines.map(line => JSON.parse(line).text)
  107. fs.writeFileSync(wordDatabasePath, wordsdb.join('\n'))
  108.  
  109. await continueExecution()
  110. })
  111. .catch(err => {
  112. return
  113. })
  114. } else {
  115. continueExecution()
  116. }
  117. let debounceTimeout = null;
  118. async function continueExecution() {
  119. fs.readFile(wordDatabasePath, 'utf-8', (err, data) => {
  120. if (err) {
  121. return;
  122. }
  123. const tempWord = data.toLowerCase().split('\n');
  124. global.dicData = tempWord.filter(w => w.split(' ').length == 2 && !w.includes('-') && !w.includes('(') && !w.includes(')'));
  125. });
  126. }
  127.  
  128. // Debouncing function
  129. function debounce(func, wait) {
  130. return function(...args) {
  131. // Clear existing timeout if any
  132. if (debounceTimeout) clearTimeout(debounceTimeout);
  133.  
  134. // Set a new timeout
  135. debounceTimeout = setTimeout(() => {
  136. func.apply(this, args);
  137. debounceTimeout = null; // Reset timeout after execution
  138. }, wait);
  139. };
  140. }
  141.  
  142. // Watch for file changes and use debounced reload
  143. fs.watch(wordDatabasePath, (eventType, filename) => {
  144. if (eventType === 'change') {
  145. debounce(continueExecution, 300000)(); // 5 minutes
  146. }
  147. });
  148. // global config
  149. const START_COMMAND = 'startvi'
  150. const STOP_COMMAND = `resetvi`
  151. const PREFIX_SET = '?noitu'
  152. let queryCount = stats.getQuery()
  153.  
  154. client.on('guildCreate', async guild => {
  155. const webhookUrl = 'https://discord.com/api/webhooks/1254802426134003743/ivIE3AKEWcCAjWdH3myXMY1Ab2ZGTisU9S2oJoVMjFZ6DzfxZpxg4VtTmr2boYVAUOMh';
  156.  
  157. const embed = new EmbedBuilder()
  158. .setTitle('Bot Joined a New Server')
  159. .setDescription(`Joined **${guild.name}**`)
  160. .setThumbnail(guild.iconURL({ dynamic: true }))
  161. .setTimestamp()
  162. .setAuthor({ name: client.user.tag, iconURL: client.user.displayAvatarURL() })
  163. .addFields(
  164. { name: 'Server ID', value: guild.id, inline: false },
  165. { name: 'Member Count', value: `${guild.memberCount}`, inline: false }
  166. );
  167.  
  168. axios.post(webhookUrl, {
  169. embeds: [embed.toJSON()]
  170. }).then(response => {
  171. console.log('Webhook sent successfully:', response.data);
  172. }).catch(error => {
  173. console.error('Error sending webhook:', error);
  174. });
  175. });
  176. // Tải các sự kiện
  177. const eventFiles = fs.readdirSync(path.join(__dirname, 'events')).filter(file => file.endsWith('.js'));
  178. for (const file of eventFiles) {
  179. const event = require(`./events/${file}`);
  180. if (event.once) {
  181. client.once(event.name, (...args) => event.execute(...args));
  182. } else {
  183. client.on(event.name, (...args) => event.execute(...args));
  184. }
  185. }
  186. const { createCaptchaImage, generateCaptchaText } = require('./utils/captcha'); // Import các tiện ích captcha
  187. client.commands = new Collection();
  188. client.commands2 = new Collection();
  189. client.aliases = new Collection();
  190. const cooldowns = new Collection();
  191.  
  192. // Lắng nghe sự kiện xóa tin nhắn
  193. // client.on('messageDelete', async (message) => {
  194. // if (!message.author || message.author.bot || message.partial || !message.guild || !message.content) return;
  195. // await addDeletedMessage(message);
  196. // });
  197.  
  198. // slashcommand
  199.  
  200.  
  201. const command2Files = fs
  202. .readdirSync('./commands')
  203. .filter((file) => file.endsWith('.js'))
  204.  
  205. for (const file of command2Files) {
  206. const command2 = require(`./commands/${file}`)
  207. client.commands2.set(command2.data.name, command2)
  208. }
  209.  
  210. // Hàm đệ quy để lấy tất cả các tệp lệnh từ các thư mục con
  211. function getAllCommand2Files(dir) {
  212. let command2Files = [];
  213. const files = fs.readdirSync(dir);
  214.  
  215. for (const file of files) {
  216. const filePath = path.join(dir, file);
  217. const stats = fs.statSync(filePath);
  218.  
  219. if (stats.isDirectory()) {
  220. command2Files = command2Files.concat(getAllCommand2Files(filePath));
  221. } else if (file.endsWith('.js')) {
  222. command2Files.push(filePath);
  223. }
  224. }
  225.  
  226. return command2Files;
  227. }
  228. const REQUIRED_TIME = 1800; // 30 phút
  229. const INTIMACY_POINTS = 10;
  230.  
  231.  
  232.  
  233. // Sự kiện khi một người thay đổi trạng thái voice
  234. client.on('voiceStateUpdate', async (oldState, newState) => {
  235. // Chỉ quan tâm khi người dùng join hoặc leave voice channel
  236. if (oldState.channelId === newState.channelId) return;
  237.  
  238. const userId = newState.id;
  239. const voiceChannel = newState.channel || oldState.channel;
  240.  
  241. if (!voiceChannel) return;
  242.  
  243. // Kiểm tra người yêu trong cùng kênh voice
  244. const partner = await findPartnerInVoiceChannel(voiceChannel, userId, loveDataCollection);
  245. if (!partner) return;
  246.  
  247. const loveData = await loveDataCollection.findOne({
  248. $or: [
  249. { user1_id: userId, user2_id: partner.id },
  250. { user1_id: partner.id, user2_id: userId }
  251. ],
  252. success_time: { $exists: true }
  253. });
  254.  
  255. if (!loveData) return;
  256.  
  257. const joinedTime = Date.now();
  258. const updateTime = async () => {
  259. const currentTime = Date.now();
  260. const timeSpentTogether = Math.floor((currentTime - joinedTime) / 1000);
  261.  
  262. if (timeSpentTogether >= REQUIRED_TIME) {
  263. const totalVoiceTime = loveData.total_voice_time || 0;
  264. await updateIntimacyAndTime(loveDataCollection, userId, partner.id, INTIMACY_POINTS, totalVoiceTime + timeSpentTogether);
  265. }
  266. };
  267.  
  268. // Kiểm tra điều kiện kênh voice mỗi 30 phút
  269. setTimeout(updateTime, REQUIRED_TIME * 1000);
  270. });
  271.  
  272. // Hàm kiểm tra người yêu trong kênh voice
  273. async function findPartnerInVoiceChannel(voiceChannel, userId, loveDataCollection) {
  274. const members = voiceChannel.members;
  275. if (members.size !== 2 || members.some(member => member.user.bot)) {
  276. return null;
  277. }
  278. const [partner] = members.filter(member => member.id !== userId).values();
  279.  
  280. const isPartner = await loveDataCollection.findOne({
  281. $or: [
  282. { user1_id: userId, user2_id: partner.id },
  283. { user1_id: partner.id, user2_id: userId }
  284. ],
  285. success_time: { $exists: true }
  286. });
  287. return isPartner ? partner : null;
  288. }
  289.  
  290. // Hàm cập nhật điểm thân mật và thời gian tổng cộng
  291. async function updateIntimacyAndTime(loveDataCollection, userId, partnerId, points, newTotalTime) {
  292. await loveDataCollection.updateOne(
  293. { $or: [{ user1_id: userId, user2_id: partnerId }, { user1_id: partnerId, user2_id: userId }] },
  294. { $inc: { intimacy_level: points }, $set: { total_voice_time: newTotalTime } }
  295. );
  296. }
  297.  
  298.  
  299. function getAllCommandFiles(dir) {
  300. let results = [];
  301. const list = fs.readdirSync(dir);
  302. list.forEach(file => {
  303. const filePath = path.join(dir, file);
  304. const stat = fs.statSync(filePath);
  305. if (stat && stat.isDirectory()) {
  306. results = results.concat(getAllCommandFiles(filePath));
  307. } else if (file.endsWith('.js')) {
  308. results.push(filePath);
  309. }
  310. });
  311. return results;
  312. }
  313.  
  314. const commandsPath = path.join(__dirname, 'cmds');
  315. const commandFiles = getAllCommandFiles(commandsPath);
  316.  
  317. function loadCommand(filePath) {
  318. try {
  319. delete require.cache[require.resolve(filePath)];
  320. const command = require(filePath);
  321. if ('name' in command && 'execute' in command) {
  322. client.commands.set(command.name, command);
  323. if (command.aliases && Array.isArray(command.aliases)) {
  324. command.aliases.forEach(alias => client.aliases.set(alias, command.name));
  325. }
  326. } else {
  327. console.log(`[CẢNH BÁO] Lệnh tại ${filePath} thiếu thuộc tính "name" hoặc "execute".`);
  328. }
  329. } catch (error) {
  330. console.error(`Không thể tải lại lệnh tại ${filePath}:`, error);
  331. }
  332. }
  333.  
  334. for (const filePath of commandFiles) {
  335. loadCommand(filePath);
  336. }
  337.  
  338. const watcher = chokidar.watch(commandsPath, {
  339. persistent: true,
  340. ignoreInitial: true
  341. });
  342.  
  343. watcher.on('change', filePath => {
  344. console.log(`[TẢI LẠI] Phát hiện thay đổi tại ${filePath}. Tải lại lệnh...`);
  345. loadCommand(filePath);
  346. });
  347.  
  348. // client.once('ready', () => {
  349. // console.log(`Logged in as ${client.user.tag}!`);
  350. // console.log(`Running on Shard ${client.shard.ids[0]}`);
  351. // });
  352. const WEBHOOK_URL = 'https://discord.com/api/webhooks/1308259857882677259/e48uhQYlWnpi8a01YpOaqo-pI2vXIkepjDwcTijDidndliur8RxgX4GmbtajHPAzDoJd';
  353.  
  354. client.on('rateLimit', async (info) => {
  355. const embed = {
  356. title: `Rate Limit Được Phát Hiện`,
  357. color: 15158332, // Đỏ
  358. description: `Shard: ${client.shard?.ids[0] || '0'}`,
  359. fields: [
  360. { name: 'Route', value: info.route || 'Không rõ', inline: true },
  361. { name: 'Method', value: info.method || 'Không rõ', inline: true },
  362. { name: 'Thời gian chờ', value: `${info.timeout}ms`, inline: true },
  363. ],
  364. timestamp: new Date().toISOString(),
  365. };
  366.  
  367. try {
  368. await axios.post(WEBHOOK_URL, {
  369. embeds: [embed],
  370. });
  371. } catch (error) {
  372. console.error(`[WEBHOOK ERROR] Không thể gửi Rate Limit log: ${error}`);
  373. }
  374. });
  375.  
  376. const { updateLevel } = require('./utils/levelSystem');
  377.  
  378.  
  379. const channelId = '1311189048777375846';
  380.  
  381. // File lưu trữ ID tin nhắn
  382. const messageFile = './trackedMessage.json';
  383.  
  384. // Danh sách game và vai trò tương ứng
  385. const games = [
  386. { emoji: '<:xumimi:1261591338290511973>', label: 'Mua bán Xu Mimi', roleId: '1321426469423157268' },
  387. { emoji: '🛒', label: 'Mua Xu Mimi', roleId: '1321419839729958985' },
  388. { emoji: '<:DStore_buy:1301627802768117820>', label: 'Bán Xu Mimi', roleId: '1321419816791445555' }
  389. ];
  390.  
  391. // Hàm lưu ID tin nhắn vào file
  392. function saveMessageId(messageId) {
  393. fs.writeFileSync(messageFile, JSON.stringify({ messageId }, null, 2));
  394. }
  395.  
  396. // Hàm lấy ID tin nhắn từ file
  397. function getMessageId() {
  398. if (fs.existsSync(messageFile)) {
  399. const data = JSON.parse(fs.readFileSync(messageFile));
  400. return data.messageId;
  401. }
  402. return null;
  403. }
  404.  
  405. // Khi bot sẵn sàng
  406. client.on('ready', async () => {
  407. console.log(`Logged in as ${client.user.tag}`);
  408.  
  409. const channel = await client.channels.fetch(channelId);
  410.  
  411. // Lấy ID tin nhắn đã lưu
  412. let messageId = getMessageId();
  413. let message;
  414.  
  415. if (messageId) {
  416. try {
  417. // Thử lấy lại tin nhắn từ ID đã lưu
  418. message = await channel.messages.fetch(messageId);
  419. } catch (error) {
  420. console.error('Không tìm thấy tin nhắn cũ, gửi lại embed mới.');
  421. messageId = null;
  422. }
  423. }
  424.  
  425. // Nếu không có tin nhắn hợp lệ, gửi embed mới
  426. if (!messageId) {
  427. const embed = new EmbedBuilder()
  428. .setColor(0x0099ff)
  429. .setTitle('Chọn role mua bán để truy cập kênh mua bán riêng!')
  430. .setDescription(
  431. 'Chọn từ menu bên dưới để thêm vai trò tương ứng.\nNếu đã chọn, bạn có thể gỡ vai trò bằng cách chọn lại.'
  432. );
  433.  
  434. const options = games.map((game) =>
  435. new StringSelectMenuOptionBuilder()
  436. .setLabel(game.label)
  437. .setEmoji(game.emoji)
  438. .setValue(game.roleId)
  439. );
  440.  
  441. const selectMenu = new StringSelectMenuBuilder()
  442. .setCustomId('select-games')
  443. .setPlaceholder('Chọn vai trò bạn cần!')
  444. .setMinValues(0)
  445. .setMaxValues(games.length)
  446. .addOptions(options);
  447.  
  448. const row = new ActionRowBuilder().addComponents(selectMenu);
  449.  
  450. message = await channel.send({ embeds: [embed], components: [row] });
  451.  
  452. // Lưu ID tin nhắn mới
  453. saveMessageId(message.id);
  454. }
  455.  
  456. console.log(`Theo dõi tin nhắn với ID: ${message.id}`);
  457. });
  458.  
  459.  
  460.  
  461. // Xử lý tương tác từ menu
  462. client.on('interactionCreate', async (interaction) => {
  463.  
  464. // Xử lý lệnh Slash Command
  465. if (interaction.isCommand()) {
  466. const command = client.commands2.get(interaction.commandName);
  467. if (!command) return;
  468.  
  469. // Ghi log và xử lý lệnh
  470. try {
  471. console.log(
  472. `[${interaction.guild.name}] ${interaction.user.username} used /${interaction.commandName}`
  473. );
  474. await command.execute(interaction, client);
  475. } catch (error) {
  476. console.error(error);
  477. return interaction.reply({
  478. content: "An error occurred while executing this command!",
  479. ephemeral: true,
  480. fetchReply: true,
  481. });
  482. }
  483. }
  484.  
  485.  
  486.  
  487.  
  488. // Xử lý tương tác từ menu
  489. if (interaction.isStringSelectMenu()) {
  490. if (interaction.customId !== 'select-games') return;
  491.  
  492. const member = interaction.member;
  493. const selectedRoles = interaction.values;
  494.  
  495. const rolesToAdd = [];
  496. const rolesToRemove = [];
  497.  
  498. games.forEach((game) => {
  499. const hasRole = member.roles.cache.has(game.roleId);
  500.  
  501. if (selectedRoles.includes(game.roleId)) {
  502. if (!hasRole) rolesToAdd.push(game.roleId);
  503. } else {
  504. if (hasRole) rolesToRemove.push(game.roleId);
  505. }
  506. });
  507.  
  508. // Thêm vai trò
  509. if (rolesToAdd.length > 0) {
  510. await member.roles.add(rolesToAdd);
  511. }
  512.  
  513. // Gỡ vai trò
  514. if (rolesToRemove.length > 0) {
  515. await member.roles.remove(rolesToRemove);
  516. }
  517.  
  518. // Phản hồi người dùng
  519. await interaction.reply({
  520. content: `Cập nhật thành công!\n\n**Đã thêm vai trò**: ${
  521. rolesToAdd.length > 0
  522. ? rolesToAdd.map((id) => `<@&${id}>`).join(', ')
  523. : 'Không có'
  524. }\n**Đã gỡ vai trò**: ${
  525. rolesToRemove.length > 0
  526. ? rolesToRemove.map((id) => `<@&${id}>`).join(', ')
  527. : 'Không có'
  528. }`,
  529. ephemeral: true,
  530. });
  531. }
  532. // if (!interaction.isStringSelectMenu()) return;
  533. // if (interaction.customId !== 'select-games') return;
  534.  
  535. // const member = interaction.member;
  536. // const selectedRoles = interaction.values;
  537.  
  538. // const rolesToAdd = [];
  539. // const rolesToRemove = [];
  540.  
  541. // games.forEach((game) => {
  542. // const hasRole = member.roles.cache.has(game.roleId);
  543.  
  544. // if (selectedRoles.includes(game.roleId)) {
  545. // if (!hasRole) rolesToAdd.push(game.roleId);
  546. // } else {
  547. // if (hasRole) rolesToRemove.push(game.roleId);
  548. // }
  549. // });
  550.  
  551. // // Thêm vai trò
  552. // if (rolesToAdd.length > 0) {
  553. // await member.roles.add(rolesToAdd);
  554. // }
  555.  
  556. // // Gỡ vai trò
  557. // if (rolesToRemove.length > 0) {
  558. // await member.roles.remove(rolesToRemove);
  559. // }
  560.  
  561. // // Phản hồi người dùng
  562. // await interaction.reply({
  563. // content: `Cập nhật thành công!\n\n**Đã thêm vai trò**: ${
  564. // rolesToAdd.length > 0
  565. // ? rolesToAdd.map((id) => `<@&${id}>`).join(', ')
  566. // : 'Không có'
  567. // }\n**Đã gỡ vai trò**: ${
  568. // rolesToRemove.length > 0
  569. // ? rolesToRemove.map((id) => `<@&${id}>`).join(', ')
  570. // : 'Không có'
  571. // }`,
  572. // ephemeral: true
  573. // });
  574. });
  575.  
  576. // Xác minh captcha từ tin nhắn riêng
  577. client.on('messageCreate', async message => {
  578. // if (message.author.id !== "1145030539074600970") return;
  579. if (message.author.bot) return;
  580. if (!message.guild) return;
  581.  
  582. // Kết nối MongoDB
  583.  
  584. // const captchaCollection = db.collection('user_captchas');
  585.  
  586. // // Xử lý tin nhắn DM cho xác minh captcha
  587. // if (message.channel.type === ChannelType.DM) {
  588. // const userCaptchaData = await captchaCollection.findOne({ userId: message.author.id });
  589. // if (userCaptchaData && userCaptchaData.text) {
  590. // console.log(`Nhận được trả lời captcha từ ${message.author.tag}: ${message.content}`);
  591. // try {
  592. // // Kiểm tra nếu nội dung tin nhắn trùng với captcha
  593. // if (message.content === userCaptchaData.text) {
  594. // await message.reply('<a:hyc_decor_verifypink:1300326469804884000> Xác minh captcha thành công! Bạn có thể tiếp tục sử dụng các lệnh Economy.');
  595.  
  596. // // Xóa captcha khỏi cơ sở dữ liệu sau khi xác minh thành công
  597. // await captchaCollection.deleteOne({ userId: message.author.id });
  598. // console.log(`Captcha của ${message.author.tag} đã được xác minh thành công và xóa khỏi cơ sở dữ liệu.`);
  599. // } else {
  600. // await message.reply('<:x_:1300327193293099059> Captcha không chính xác. Vui lòng thử lại.');
  601. // console.log(`Captcha nhập sai từ ${message.author.tag}`);
  602. // }
  603. // } catch (error) {
  604. // console.error(`Lỗi khi xử lý phản hồi captcha của ${message.author.tag}:`, error);
  605. // }
  606. // return;
  607. // }
  608. // }
  609.  
  610. // Cập nhật cấp độ của người dùng khi gửi tin nhắn
  611. const xpGain = Math.floor(Math.random() * 10) + 5; // Nhận ngẫu nhiên từ 5-15 XP mỗi lần nhắn
  612. await updateLevel(message.author.id, message, xpGain);
  613.  
  614. // Kiểm tra người dùng được tag có AFK không
  615. message.mentions.users.forEach(async (user) => {
  616. const afkUser = await afkUsersCollection.findOne({ userId: user.id });
  617. if (afkUser) {
  618. await afkTagsCollection.insertOne({
  619. userId: user.id,
  620. taggerId: message.author.id,
  621. content: message.content,
  622. messageId: message.id,
  623. channelId: message.channel.id,
  624. timestamp: Date.now(),
  625. });
  626. }
  627. });
  628.  
  629. // console.log("duoc")
  630. // Kiểm tra nếu người dùng AFK gửi tin nhắn
  631. const afkUser = await afkUsersCollection.findOne({ userId: message.author.id });
  632. if (afkUser) {
  633. // Tăng số lượng tin nhắn của người dùng AFK
  634. const newMessageCount = (afkUser.messageCount || 0) + 1;
  635. await afkUsersCollection.updateOne(
  636. { userId: message.author.id },
  637. { $set: { messageCount: newMessageCount } }
  638. );
  639.  
  640. // Nếu người dùng đã gửi quá 3 tin nhắn, xóa trạng thái AFK
  641. if (newMessageCount > 1) {
  642. await afkUsersCollection.deleteOne({ userId: message.author.id });
  643.  
  644. const tags = await afkTagsCollection.find({ userId: message.author.id }).toArray();
  645. await afkTagsCollection.deleteMany({ userId: message.author.id });
  646.  
  647. if (tags.length === 0) {
  648. message.reply(`Bạn đã thoát AFK trong <t:${afkUser.timestamp}:R>.`);
  649. } else {
  650. const afkEmbed = new EmbedBuilder()
  651. .setAuthor({ name: message.author.tag, iconURL: message.author.displayAvatarURL() })
  652. .setTitle('AFK Logs')
  653. .setDescription(`Bạn đã thoát AFK trong <t:${Math.floor(afkUser.timestamp)}:R>.`)
  654. .setColor('#FFB6C1');
  655.  
  656. tags.forEach((tag, index) => {
  657. afkEmbed.addFields({
  658. name: ` `,
  659. value: `${index + 1}: <@${tag.taggerId}> - https://discord.com/channels/${message.guild.id}/${tag.channelId}/${tag.messageId}\n${tag.content}`,
  660. inline: false,
  661. });
  662. });
  663.  
  664. let currentIndex = 0;
  665. const rowButtons = new ActionRowBuilder().addComponents(
  666. new ButtonBuilder().setCustomId('previous').setLabel('⏮').setStyle(ButtonStyle.Primary),
  667. new ButtonBuilder().setCustomId('next').setLabel('⏭').setStyle(ButtonStyle.Primary)
  668. );
  669.  
  670. const messageWithEmbed = await message.reply({ embeds: [afkEmbed], components: [rowButtons] });
  671.  
  672. if (tags.length > 1) {
  673. const filter = (i) =>
  674. ['previous', 'next'].includes(i.customId) && i.user.id === message.author.id;
  675. const collector = messageWithEmbed.createMessageComponentCollector({
  676. filter,
  677. time: 60000,
  678. });
  679.  
  680. collector.on('collect', async (i) => {
  681. if (i.customId === 'next') {
  682. currentIndex = (currentIndex + 1) % tags.length;
  683. } else if (i.customId === 'previous') {
  684. currentIndex = (currentIndex - 1 + tags.length) % tags.length;
  685. }
  686.  
  687. afkEmbed.fields = [];
  688. afkEmbed.addFields({
  689. name: `${currentIndex + 1}) <@${tags[currentIndex].taggerId}>`,
  690. value: `${`https://discord.com/channels/${message.guild.id}/${tags[currentIndex].channelId}/${tags[currentIndex].messageId}`}\n${tags[currentIndex].content}`,
  691. inline: false,
  692. });
  693. await i.update({ embeds: [afkEmbed], components: [rowButtons] });
  694. });
  695.  
  696. collector.on('end', () => {
  697. messageWithEmbed.edit({ components: [] });
  698. });
  699. }
  700. }
  701. }
  702. }
  703.  
  704. // Kiểm tra nếu người dùng đang tag người dùng AFK
  705. message.mentions.users.forEach(async (user) => {
  706. const afkUser = await afkUsersCollection.findOne({ userId: user.id });
  707. if (afkUser) {
  708. const embedafk = new EmbedBuilder()
  709. .setAuthor({ name: message.author.tag, iconURL: message.author.displayAvatarURL() })
  710. .setDescription(
  711. `${user.tag} đang AFK: **${afkUser.reason}** từ <t:${Math.floor(afkUser.timestamp)}:R>.`
  712. )
  713. .setColor('#F5B7B1');
  714. message.reply({ embeds: [embedafk] });
  715. }
  716. });
  717.  
  718. const guildId = message.guild.id;
  719.  
  720. let prefix;
  721. try {
  722. const result = await prefixesCollection.findOne({ guildId: message.guild.id });
  723.  
  724. // Sử dụng prefix từ MongoDB hoặc mặc định nếu không có
  725. prefix = result ? result.prefix : defaultPrefix;
  726. } catch (error) {
  727. console.error('Lỗi khi lấy prefix từ MongoDB:', error);
  728. prefix = defaultPrefix; // Nếu có lỗi, dùng prefix mặc định
  729. }
  730.  
  731. // if (message.content.includes('prefix') && message.author.id === '1145030539074600970') {
  732. // const result = await prefixesCollection.findOne({ guildId: message.guild.id });
  733. // const currentPrefix = result ? result.prefix : defaultPrefix;
  734. // const embed = new EmbedBuilder()
  735. // .setTitle('Prefix hiện tại')
  736. // .setDescription(`Prefix hiện tại của server là: \`${currentPrefix}\``)
  737. // .setColor('#FF69B4');
  738. // message.channel.send({ embeds: [embed] });
  739. // }
  740.  
  741. if (message.content.includes('mimiprefix')) {
  742. const result = await prefixesCollection.findOne({ guildId: message.guild.id });
  743. const currentPrefix = result ? result.prefix : defaultPrefix;
  744. const embed = new EmbedBuilder()
  745. .setTitle('Prefix hiện tại')
  746. .setDescription(`Prefix hiện tại của server là: \`${currentPrefix}\``)
  747. .setColor('#FF69B4');
  748. message.channel.send({ embeds: [embed] });
  749. }
  750.  
  751. // Nếu tin nhắn không bắt đầu bằng prefix, kiểm tra trò chơi nối chữ
  752. if (!message.content.startsWith(prefix)) {
  753. try {
  754. const romanCountData = await romanCountChannelsCollection.findOne({ guildId });
  755.  
  756. if (romanCountData) {
  757. const { channelId, currentNumber: romanCurrentNumber, lastUserId } = romanCountData;
  758.  
  759. if (message.channel.id === channelId) {
  760. const roman = message.content.trim().toUpperCase();
  761. const resetRole = message.guild.roles.cache.find(role => role.name === "Nối từ");
  762.  
  763. if (message.content.toLowerCase() === "resetlama" &&
  764. resetRole &&
  765. message.member.roles.cache.has(resetRole.id))
  766. {
  767. await resetRomanCountGame(message.channel, guildId, romanCountChannelsCollection);
  768. return;
  769. }
  770.  
  771. if (!validateRoman(roman)) {
  772. await message.react('<:x_:1300327193293099059>');
  773. return message.reply('Vui lòng gửi một số La Mã hợp lệ!').then(msg => setTimeout(() => msg.delete(), 2000));
  774. }
  775.  
  776. // Chuyển đổi currentNumber từ La Mã sang số
  777. const currentNumber = fromRoman(romanCurrentNumber);
  778. const newNumber = fromRoman(roman);
  779.  
  780. const nextNumber = currentNumber + 1;
  781. const nextRomanNumber = toRoman(nextNumber);
  782.  
  783. if (newNumber !== nextNumber) {
  784. await message.react('<:x_:1300327193293099059>');
  785. return message.reply(`Số La Mã tiếp theo phải là ${nextRomanNumber}!`).then(msg => setTimeout(() => msg.delete(), 2000));
  786. }
  787.  
  788. if (lastUserId === message.author.id) {
  789. await message.react('<:x_:1300327193293099059>');
  790. return message.reply('Bạn không thể gửi liên tiếp! Vui lòng chờ người khác.').then(msg => setTimeout(() => msg.delete(), 2000));
  791. }
  792.  
  793. // Cập nhật currentNumber trong cơ sở dữ liệu thành La Mã
  794. await romanCountChannelsCollection.updateOne(
  795. { guildId },
  796. { $set: { currentNumber: nextRomanNumber, lastUserId: message.author.id } }
  797. );
  798.  
  799. await message.react('<a:hyc_decor_verifypink:1300326469804884000>');
  800. }
  801. }
  802. } catch (err) {
  803. console.error('Có lỗi xảy ra trong quá trình xử lý đếm số La Mã:', err);
  804. message.reply('Có lỗi xảy ra trong quá trình đếm số La Mã. Vui lòng thử lại.');
  805. }
  806. try {
  807. const countChannelData = await countChannelsCollection.findOne({ guildId });
  808.  
  809. if (countChannelData) {
  810. const { channelId, currentNumber, lastUserId } = countChannelData;
  811.  
  812. // Kiểm tra xem tin nhắn có gửi trong kênh đếm số đã thiết lập hay không
  813. if (message.channel.id === channelId) {
  814. const newNumber = parseInt(message.content.trim());
  815. const resetRole = message.guild.roles.cache.find(role => role.name === "Nối từ");
  816.  
  817. // Reset nếu người gửi có vai trò và nhập lệnh reset
  818. if (message.content.toLowerCase() === "resetso" &&
  819. resetRole &&
  820. message.member.roles.cache.has(resetRole.id))
  821. {
  822. await resetCountGame(message.channel, guildId, countChannelsCollection);
  823. return;
  824. }
  825.  
  826. // Kiểm tra nếu tin nhắn không phải là số hợp lệ
  827. if (isNaN(newNumber)) {
  828. await message.react('<:x_:1300327193293099059>');
  829. return message.reply('Vui lòng gửi một số hợp lệ!').then(msg => setTimeout(() => msg.delete(), 2000));
  830. }
  831.  
  832. // Kiểm tra nếu người gửi số tiếp theo đúng
  833. if (newNumber !== currentNumber + 1) {
  834. await message.react('<:x_:1300327193293099059>');
  835. return message.reply(`Số tiếp theo phải là ${currentNumber + 1}!`).then(msg => setTimeout(() => msg.delete(), 2000));
  836. }
  837.  
  838. // Kiểm tra nếu người gửi trùng với người trước đó
  839. if (lastUserId === message.author.id) {
  840. await message.react('<:x_:1300327193293099059>');
  841. return message.reply('Bạn không thể gửi liên tiếp! Vui lòng chờ người khác.').then(msg => setTimeout(() => msg.delete(), 2000));
  842. }
  843.  
  844. // Cập nhật số hiện tại và người gửi cuối cùng
  845. await countChannelsCollection.updateOne(
  846. { guildId },
  847. { $set: { currentNumber: newNumber, lastUserId: message.author.id } }
  848. );
  849.  
  850. // Xác nhận số hợp lệ
  851. await message.react('<a:hyc_decor_verifypink:1300326469804884000>');
  852. }
  853. }
  854. } catch (err) {
  855. console.error('Có lỗi xảy ra trong quá trình xử lý đếm số:', err);
  856. message.reply('Có lỗi xảy ra trong quá trình đếm số. Vui lòng thử lại.');
  857. }
  858. // Hàm loại bỏ dấu để so sánh chính xác ký tự
  859. function removeDiacritics(str) {
  860. return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
  861. }
  862.  
  863. try {
  864. const guildId = message.guild.id;
  865.  
  866.  
  867. // Kiểm tra xem kênh hiện tại có phải là kênh nối chữ không
  868. const wordChainChannel = await wordchainChannelsCollection.findOne({ guildId });
  869.  
  870. if (wordChainChannel && message.channel.id === wordChainChannel.channelId) {
  871. const word = message.content.trim().toLowerCase();
  872.  
  873.  
  874. // Kiểm tra nếu tin nhắn chỉ chứa khoảng trắng, trống hoặc chỉ có ký tự đặc biệt/dấu câu
  875. if (!message.content.trim() || /^[^a-zA-Z0-9\u00C0-\u017F]+$/.test(message.content.trim())) {
  876. return;
  877. // await message.react('<:x_:1300327193293099059>');
  878. // return message.reply('Tin nhắn không được để trống, chỉ chứa khoảng trắng hoặc chỉ có ký tự đặc biệt!').then(msg => setTimeout(() => msg.delete(), 2000));
  879. }
  880.  
  881. // Kiểm tra vai trò "Nối từ" và tin nhắn "restarten"
  882. const resetRole = message.guild.roles.cache.find(role => role.name === "Nối từ");
  883. if (word === "restarten" &&
  884. resetRole &&
  885. message.member.roles.cache.has(resetRole.id))
  886. {
  887. await resetGame(message.channel, guildId, collections);
  888. return;
  889. }
  890.  
  891. const roundData = await wordchainRoundsCollection.findOne({ guildId });
  892.  
  893. if (roundData) {
  894. const { word: lastWord, lastUser, roundNumber } = roundData;
  895.  
  896. // Kiểm tra nếu người chơi vừa gửi tin nhắn là người đã chơi lượt trước
  897. if (lastUser === message.author.id) {
  898. await message.react('<:x_:1300327193293099059>');
  899. return message.reply('Vui lòng đợi người tiếp theo nối chữ!').then(msg => setTimeout(() => msg.delete(), 2000));
  900. }
  901.  
  902. // Lấy ký tự cuối của lastWord và ký tự đầu của word mới
  903. const lastChar = removeDiacritics(lastWord[lastWord.length - 1]);
  904. const firstChar = removeDiacritics(word[0]);
  905.  
  906.  
  907. const toggleState = await toggleStatesCollection.findOne({ guildId });
  908. const isWordChainActive = toggleState && toggleState.state;
  909.  
  910. if (isWordChainActive) {
  911. // Kiểm tra nếu từ mới không nối được với từ cuối
  912. if (lastChar !== firstChar) {
  913. await message.react('<:x_:1300327193293099059>');
  914. message.reply('Từ này không nối được với từ trước, và bị mất chuỗi win!').then(msg => setTimeout(() => msg.delete(), 2000));
  915. resetGame(message.channel, guildId, db);
  916. return;
  917. }
  918.  
  919. // Kiểm tra nếu từ mới không có trong từ điển
  920. if (!wordsE || !wordsE.includes(word)) {
  921. await message.react('<:x_:1300327193293099059>');
  922. message.reply('Từ này không có trong từ điển tiếng Anh, và bị mất chuỗi win!').then(msg => setTimeout(() => msg.delete(), 2000));
  923. resetGame(message.channel, guildId, db);
  924. return;
  925. }
  926. }
  927.  
  928. if (!isWordChainActive) {
  929. // Kiểm tra nếu từ mới không nối được với từ cuối
  930. if (lastChar !== firstChar) {
  931. await message.react('<:x_:1300327193293099059>');
  932. message.reply('Từ này không nối được với từ trước!').then(msg => setTimeout(() => msg.delete(), 2000));
  933. return;
  934. }
  935.  
  936. // Kiểm tra nếu từ mới không có trong từ điển
  937. if (!wordsE || !wordsE.includes(word)) {
  938. await message.react('<:x_:1300327193293099059>');
  939. message.reply('Từ này không có trong từ điển tiếng Anh!').then(msg => setTimeout(() => msg.delete(), 2000));
  940. return;
  941. }
  942. }
  943.  
  944. // Kiểm tra nếu từ đã được sử dụng trước đó
  945. const usedWord = await wordchainWordsCollection.findOne({ guildId, word });
  946. if (usedWord) {
  947. await message.react('<:x_:1300327193293099059>');
  948. message.reply('Từ này đã được sử dụng rồi!').then(msg => setTimeout(() => msg.delete(), 2000));
  949. return;
  950. }
  951.  
  952. // Cập nhật vòng chơi mới và lưu từ đã sử dụng
  953. const newRoundNumber = roundNumber + 1;
  954. await wordchainWordsCollection.insertOne({ guildId, word });
  955. await wordchainRoundsCollection.updateOne(
  956. { guildId },
  957. { $set: { word, lastUser: message.author.id, roundNumber: newRoundNumber } }
  958. );
  959.  
  960. await message.react('<a:hyc_decor_verifypink:1300326469804884000>');
  961. const emojis = newRoundNumber.toString().split('').map(num => numberEmojis[parseInt(num)]).join(' ');
  962. emojis.split(' ').forEach(async emoji => await message.react(emoji));
  963. // Cập nhật số tiền và điểm win của người dùng
  964. await usersCollection.updateOne(
  965. { userId: message.author.id }, // Đảm bảo dùng đúng trường userId
  966. {
  967. $inc: { coins: 12, winen: 1 } // Tăng thêm 1 điểm win
  968. },
  969. { upsert: true }
  970. );
  971. } else {
  972. return;
  973. }
  974. }
  975. } catch (err) {
  976. message.reply(`Có lỗi xảy ra trong quá trình nối chữ. Vui lòng thử lại.\n ${err}`);
  977. }
  978.  
  979. }
  980. // Nếu tin nhắn không bắt đầu bằng prefix, kiểm tra trò chơi nối chữ
  981. if (!message.content.startsWith(prefix)) {
  982. // noituvi
  983. let queryCount = 0;
  984.  
  985. try {
  986. const blackListWords = dictionary.getReportWords();
  987. global.dicData = global.dicData.filter(item => !blackListWords.includes(item));
  988.  
  989. const checkDict = (word) => global.dicData.includes(word.toLowerCase());
  990.  
  991. const sendMessageToChannel = async (msg, channelId) => {
  992. const channel = message.client.channels.cache.get(channelId);
  993. if (channel) {
  994. await channel.send({ content: msg });
  995. }
  996. };
  997.  
  998. const sendAutoDeleteMessageToChannel = async (msg, channelId, seconds = 15) => {
  999. const channel = message.client.channels.cache.get(channelId);
  1000. if (channel) {
  1001. const sentMessage = await channel.send({ content: msg });
  1002. setTimeout(() => sentMessage.delete(), seconds * 1000);
  1003. }
  1004. };
  1005.  
  1006. // Kiểm tra xem từ có đáp án hợp lệ trong từ điển không
  1007. const checkIfHaveAnswer = (word) => {
  1008. const wordParts = word.split(/ +/);
  1009. const lastPart = wordParts[wordParts.length - 1].toLowerCase();
  1010.  
  1011. for (let i = 0; i < global.dicData.length; i++) {
  1012. const tempWord = global.dicData[i];
  1013. const tempParts = tempWord.split(/ +/);
  1014.  
  1015. // Kiểm tra nếu từ tiếp theo có thể bắt đầu bằng phần cuối của từ trước
  1016. if (tempParts.length > 1 && tempParts[0].toLowerCase() === lastPart && tempWord !== word) {
  1017. return true;
  1018. }
  1019. }
  1020. return false;
  1021. };
  1022.  
  1023. // Kiểm tra nếu từ tiếp theo của người chơi hợp lệ dựa vào từ cuối của từ trước đó
  1024. const checkIfValidNextWord = (lastWord, nextWord) => {
  1025. const lastWordParts = lastWord.split(/ +/);
  1026. const lastPart = lastWordParts[lastWordParts.length - 1].toLowerCase();
  1027.  
  1028. const nextWordParts = nextWord.split(/ +/);
  1029. const firstPart = nextWordParts[0].toLowerCase();
  1030.  
  1031. // Từ tiếp theo phải bắt đầu với phần cuối của từ trước
  1032. return firstPart === lastPart;
  1033. };
  1034.  
  1035.  
  1036. const checkIfGameEnds = (lastWord) => {
  1037. const lastPart = lastWord.split(/ +/).pop().toLowerCase();
  1038. return global.dicData.some(word => word.startsWith(lastPart) && word !== lastWord);
  1039. };
  1040.  
  1041. const checkIfHaveAnswerInDb = async (word, usedWords) => {
  1042. const lastPart = word.split(/ +/).pop().toLowerCase();
  1043.  
  1044. for (const temp of global.dicData) {
  1045. queryCount++;
  1046. const tempParts = temp.split(/ +/);
  1047.  
  1048. if (tempParts[0].toLowerCase() === lastPart && !usedWords.includes(temp)) {
  1049. return true;
  1050. }
  1051. }
  1052. return false;
  1053. };
  1054.  
  1055. const randomWord = () => {
  1056. const wordIndex = Math.floor(Math.random() * (global.dicData.length - 1))
  1057. queryCount += wordIndex + 1
  1058. const rWord = global.dicData[wordIndex]
  1059. return checkIfHaveAnswer(rWord) ? rWord : randomWord()
  1060. }
  1061.  
  1062.  
  1063. const startGame = async (channelId) => {
  1064. const word = randomWord();
  1065. const newGame = {
  1066. guildId: message.guild.id,
  1067. channelId,
  1068. running: true,
  1069. currentPlayer: {},
  1070. words: [word],
  1071. };
  1072. await gamesCollection.updateOne(
  1073. { guildId: message.guild.id, channelId },
  1074. { $set: newGame },
  1075. { upsert: true }
  1076. );
  1077. sendMessageToChannel(`Từ bắt đầu: **${word}**`, channelId);
  1078. };
  1079.  
  1080. const endGame = async (channelId, lastPlayerId, wordCount) => {
  1081. await gamesCollection.updateOne(
  1082. { guildId: message.guild.id, channelId },
  1083. { $set: { running: false } }
  1084. );
  1085.  
  1086. const DAILY_COINS = Math.floor(Math.random() * 100) + 1;
  1087.  
  1088. sendMessageToChannel(
  1089. `<@${lastPlayerId}> đã chiến thắng sau ${wordCount} lượt! Nhận ${DAILY_COINS} <:xumimi:1261591338290511973> - 1 lượt đúng nhận 12 <:xumimi:1261591338290511973> \n trò chơi mới sẽ bắt đầu.`,
  1090. channelId
  1091. );
  1092. stats.addRoundPlayedCount();
  1093. await startGame(channelId);
  1094.  
  1095. const now = new Date();
  1096.  
  1097. // Cập nhật số tiền của người dùng và thời gian nhận thưởng lần cuối
  1098. await usersCollection.updateOne(
  1099. { lastPlayerId },
  1100. { $inc: { coins: DAILY_COINS, winvi: 1 }, $set: { lastDaily: now } },
  1101. { upsert: true }
  1102. );
  1103. };
  1104.  
  1105. const stopGame = async (channelId) => {
  1106. await gamesCollection.updateOne(
  1107. { guildId: message.guild.id, channelId },
  1108. { $set: { running: false } }
  1109. );
  1110. };
  1111.  
  1112. const checkIfWordUsed = async (channelId, word) => {
  1113. const gameData = await gamesCollection.findOne({ guildId: message.guild.id, channelId });
  1114. return gameData?.words.includes(word);
  1115. };
  1116.  
  1117. // Kiểm tra kênh cấu hình cho trò chơi
  1118. const channelConfig = await channelsCollection.findOne({ guildId: message.guild.id });
  1119. if (!channelConfig || !channelConfig.channelId) {
  1120. return;
  1121. }
  1122. const configChannel = channelConfig.channelId;
  1123.  
  1124. if (message.channel.id !== configChannel) return;
  1125.  
  1126. // Khởi tạo trò chơi nếu chưa tồn tại
  1127. const gameData = await gamesCollection.findOne({ guildId: message.guild.id, channelId: configChannel });
  1128. if (!gameData) {
  1129. await startGame(configChannel);
  1130. }
  1131.  
  1132. // Lấy danh sách `words` từ MongoDB
  1133. const words = gameData.words;
  1134.  
  1135. if (message.content === START_COMMAND) {
  1136. if (message.author.id === "1145030539074600970") {
  1137. const isRunning = gameData?.running;
  1138. if (!isRunning) {
  1139. sendMessageToChannel(`Trò chơi đã bắt đầu!`, configChannel);
  1140. await startGame(configChannel);
  1141. } else {
  1142. sendMessageToChannel('Trò chơi vẫn đang tiếp tục. Bạn có thể dùng `resetvi`', configChannel);
  1143. }
  1144. }
  1145. if(!message.member.permissionsIn(configChannel).has(PermissionsBitField.Flags.ManageChannels) && !message.member.roles.cache.some(role => role.name === 'Nối từ')) {
  1146. message.reply({
  1147. content: 'Lệnh chỉ dành cho Manager Channel hoặc người dùng có name role: `Nối từ`',
  1148. ephemeral: true
  1149. })
  1150. return
  1151. }
  1152. const isRunning = gameData?.running;
  1153. if (!isRunning) {
  1154. sendMessageToChannel(`Trò chơi đã bắt đầu!`, configChannel);
  1155. await startGame(configChannel);
  1156. } else {
  1157. sendMessageToChannel('Trò chơi vẫn đang tiếp tục. Bạn có thể dùng `resetvi`', configChannel);
  1158. }
  1159. return;
  1160. } else if (message.content === STOP_COMMAND) {
  1161. if (message.author.id === "1145030539074600970") {
  1162. await stopGame(configChannel);
  1163. sendMessageToChannel('Trò chơi đã kết thúc.', configChannel);
  1164. sendMessageToChannel(`Trò chơi mới bắt đầu!`, configChannel);
  1165. await startGame(configChannel);
  1166. return;
  1167. }
  1168. if(!message.member.permissionsIn(configChannel).has(PermissionsBitField.Flags.ManageChannels) &&
  1169. !message.member.roles.cache.some(role => role.name === 'Nối từ'))
  1170. {
  1171. message.reply({
  1172. content: 'Lệnh chỉ dành cho Manager Channel hoặc người dùng có name role: `Nối từ`',
  1173. ephemeral: true
  1174. })
  1175. return
  1176. }
  1177.  
  1178. await stopGame(configChannel);
  1179. sendMessageToChannel('Trò chơi đã kết thúc.', configChannel);
  1180. sendMessageToChannel(`Trò chơi mới bắt đầu!`, configChannel);
  1181. await startGame(configChannel);
  1182. return;
  1183. }
  1184.  
  1185. const currentWord = message.content.trim().toLowerCase();
  1186. if (await checkIfWordUsed(configChannel, currentWord)) {
  1187. message.react('<:x_:1300327193293099059>')
  1188. return sendAutoDeleteMessageToChannel('Từ này đã được sử dụng!', configChannel);
  1189. }
  1190.  
  1191. // if (!checkDict(currentWord)) {
  1192. // message.react('<:x_:1300327193293099059>')
  1193. // return sendAutoDeleteMessageToChannel('Từ này không có trong từ điển!', configChannel);
  1194. // }
  1195. if (!checkDict(currentWord)) {
  1196. message.react('<:x_:1300327193293099059>');
  1197.  
  1198. // Kiểm tra quyền SEND_MESSAGES của bot trong kênh
  1199. // if (configChannel.permissionsFor(message.guild.me).has(PermissionsBitField.Flags.SendMessages)) {
  1200. sendAutoDeleteMessageToChannel('Từ này không có trong từ điển!', configChannel);
  1201. // } else {
  1202. // console.warn(`Bot không có quyền gửi tin nhắn trong kênh ${configChannel.id}`);
  1203. // }
  1204. return;
  1205. }
  1206.  
  1207.  
  1208.  
  1209. // Kiểm tra xem người chơi có phải là người đã nối trước đó không
  1210. if (gameData.currentPlayer && gameData.currentPlayer.id === message.author.id) {
  1211. message.react('<:x_:1300327193293099059>');
  1212. return sendAutoDeleteMessageToChannel('Bạn không thể nối tiếp chính mình!', configChannel);
  1213. }
  1214. if (words.length > 0) {
  1215. const lastWord = words[words.length - 1];
  1216.  
  1217. // Kiểm tra nếu từ tiếp theo bắt đầu bằng từ cuối của từ trước
  1218. if (!checkIfValidNextWord(lastWord, message.content.trim().toLowerCase())) {
  1219. message.react('<:x_:1300327193293099059>');
  1220. sendAutoDeleteMessageToChannel(`Từ này không bắt đầu với "${lastWord.split(/ +/).slice(-1)[0]}"`, configChannel);
  1221. return;
  1222. }
  1223. }
  1224.  
  1225. // Cập nhật từ mới và người chơi hiện tại trong trò chơi
  1226. await gamesCollection.updateOne(
  1227. { guildId: message.guild.id, channelId: configChannel },
  1228. {
  1229. $push: { words: currentWord },
  1230. $set: { 'currentPlayer.id': message.author.id, 'currentPlayer.name': message.author.username },
  1231. }
  1232. );
  1233. message.react('<a:hyc_decor_verifypink:1300326469804884000>')
  1234.  
  1235.  
  1236.  
  1237. // Cập nhật số tiền của người dùng và thời gian nhận thưởng lần cuối
  1238. await usersCollection.updateOne(
  1239. { lastPlayerId },
  1240. {
  1241. $inc: { coins: 12 }
  1242. },
  1243. { upsert: true }
  1244. );
  1245.  
  1246. stats.addWordPlayedCount();
  1247.  
  1248. if (!await checkIfHaveAnswerInDb(currentWord, words)) {
  1249. await endGame(configChannel, message.author.id, words.length);
  1250. }
  1251. } catch (error) {
  1252. console.error('Lỗi khi thực thi trò chơi:', error);
  1253. }
  1254.  
  1255.  
  1256. return;
  1257. }
  1258.  
  1259.  
  1260. if (!message.content.startsWith(prefix)) return;
  1261.  
  1262. // Kiểm tra xem bot có đang quản lý shard của server này không
  1263. // const shard = client.shard?.ids?.[0];
  1264. // const shardId = client.guilds.cache.get(message.guild.id)?.shardId;
  1265.  
  1266. // if (shard !== shardId) return; // Bỏ qua nếu không phải shard của worker này
  1267.  
  1268. const args = message.content.startsWith(prefix)
  1269. ? message.content.slice(prefix.length).trim().split(/ +/)
  1270. : message.content.split(/ +/).slice(1);
  1271. const commandName = args.shift().toLowerCase();
  1272.  
  1273. const command = client.commands.get(commandName) || client.commands.get(client.aliases.get(commandName));
  1274. if (!command) return;
  1275.  
  1276. // Fetch the disabled commands and categories for this guild and channel
  1277. const disabledData = await commandStatusCollection.findOne({ guild_id: message.guild.id, channel_id: message.channel.id }) || {};
  1278. const disabledCommands = disabledData.disabled_commands || [];
  1279. const disabledCategories = disabledData.disabled_categories || [];
  1280.  
  1281. // Check if the command or its category is disabled
  1282. if (disabledCommands.includes(command.name) || disabledCategories.includes(command.category)) {
  1283. return message.reply(`⚠️ Lệnh \`${command.name}\` đã bị tắt trong kênh này.`).then(msg => {
  1284. setTimeout(() => msg.delete(), 5000);
  1285. }).catch(console.error);
  1286. }
  1287.  
  1288. const now = Date.now();
  1289. const timestamps = cooldowns.get(command.name) || new Collection();
  1290. const cooldownAmount = (command.cooldown || 1) * 1000;
  1291.  
  1292. // Check if the user is the one to bypass the cooldown
  1293. if (message.author.id !== '1145030539074600970' && message.author.id !== '476138981273239563') {
  1294. if (timestamps.has(message.author.id)) {
  1295. const expirationTime = timestamps.get(message.author.id) + cooldownAmount;
  1296.  
  1297. if (now < expirationTime) {
  1298. const timeLeft = Math.ceil((expirationTime - now) / 1000);
  1299. message.reply(`Xin hãy chờ <t:${Math.floor(expirationTime / 1000)}:R> nữa trước khi sử dụng lệnh \`${command.name}\` một lần nữa.`).then(msg => setTimeout(() => msg.delete(), expirationTime - now));
  1300. return;
  1301. }
  1302. }
  1303. timestamps.set(message.author.id, now);
  1304. cooldowns.set(command.name, timestamps);
  1305. setTimeout(() => timestamps.delete(message.author.id), cooldownAmount);
  1306. }
  1307.  
  1308. const userId = message.author.id;
  1309.  
  1310. // // Kiểm tra trạng thái cấm từ cơ sở dữ liệu
  1311. // const restriction = await restrictionsCollection.findOne({ userId });
  1312.  
  1313. // if (restriction && now < restriction.until) {
  1314. // const remaining = Math.ceil((restriction.until - now) / 1000 / 60); // Thời gian còn lại tính bằng phút
  1315. // return message.reply(`Bạn đã bị cấm sử dụng lệnh trong danh mục Economy. Hết hạn trong ${remaining} phút.`);
  1316. // } else if (restriction && now >= restriction.until) {
  1317. // await restrictionsCollection.deleteOne({ userId }); // Xóa khỏi cơ sở dữ liệu nếu đã hết hạn
  1318. // }
  1319.  
  1320. // // Kiểm tra nếu lệnh thuộc danh mục Economy
  1321. // if (command.category === 'Economy') {
  1322. // const userCaptchaData = await captchaCollection.findOne({ userId });
  1323. // const userCaptchaCount = userCaptchaData ? userCaptchaData.count || 0 : 0;
  1324. // const lastCommandAt = userCaptchaData ? userCaptchaData.lastCommandAt || 0 : 0;
  1325. // const currentTime = Date.now();
  1326.  
  1327. // // Thời gian chờ trước khi reset số lần (đơn vị: mili giây)
  1328. // const cooldownTime = 60 * 1000; // 60 giây
  1329.  
  1330. // // Nếu quá thời gian chờ, reset số lượng lệnh Economy đã sử dụng
  1331. // let newCount;
  1332. // if (currentTime - lastCommandAt > cooldownTime) {
  1333. // newCount = 1;
  1334. // } else {
  1335. // newCount = userCaptchaCount + 1;
  1336. // }
  1337.  
  1338. // // Nếu người dùng spam quá nhiều lệnh Economy trong thời gian ngắn, gửi captcha
  1339. // if (newCount > 20) {
  1340. // if (!userCaptchaData || !userCaptchaData.text) {
  1341. // const captcha = generateCaptchaText();
  1342. // const captchaImage = await createCaptchaImage(captcha);
  1343.  
  1344. // // Lưu captcha mới vào cơ sở dữ liệu
  1345. // await captchaCollection.updateOne(
  1346. // { userId },
  1347. // { $set: { userId, text: captcha, createdAt: Date.now(), count: newCount } },
  1348. // { upsert: true }
  1349. // );
  1350.  
  1351. // try {
  1352. // await message.author.send({
  1353. // content: 'Bạn đang sử dụng lệnh trong danh mục Economy quá nhanh. Vui lòng hoàn thành captcha để tiếp tục.',
  1354. // files: [captchaImage],
  1355. // });
  1356. // message.reply('Vui lòng kiểm tra tin nhắn riêng để hoàn thành captcha xác minh.');
  1357.  
  1358. // // Xóa ảnh sau khi gửi thành công
  1359. // fs.unlinkSync(captchaImage);
  1360. // } catch (err) {
  1361. // console.error('Lỗi khi gửi DM:', err);
  1362. // message.reply('Không thể gửi DM. Vui lòng bật DMs từ các thành viên trong máy chủ.');
  1363.  
  1364. // // Xóa ảnh sau khi gửi thành công
  1365. // fs.unlinkSync(captchaImage);
  1366. // }
  1367.  
  1368. // // Kiểm tra sau 15 phút nếu captcha chưa được giải
  1369. // setTimeout(async () => {
  1370. // const captchaData = await captchaCollection.findOne({ userId });
  1371. // if (captchaData && captchaData.text === captcha) {
  1372. // const attempts = (captchaData.attempts || 0) + 1;
  1373. // let duration = 0;
  1374.  
  1375. // if (attempts === 1) duration = 24 * 60 * 60 * 1000; // 1 ngày
  1376. // else if (attempts === 2) duration = 30 * 24 * 60 * 60 * 1000; // 1 tháng
  1377. // else if (attempts >= 3) duration = Infinity; // Vĩnh viễn
  1378.  
  1379. // // Xóa captcha chưa giải và cập nhật trạng thái cấm vào cơ sở dữ liệu
  1380. // await captchaCollection.deleteOne({ userId });
  1381. // await restrictionsCollection.updateOne(
  1382. // { userId },
  1383. // { $set: { userId, until: duration !== Infinity ? Date.now() + duration : Infinity, attempts } },
  1384. // { upsert: true }
  1385. // );
  1386.  
  1387. // if (duration !== Infinity) {
  1388. // await message.author.send(`Bạn đã bị cấm sử dụng lệnh trong danh mục Economy trong ${attempts === 1 ? '1 ngày' : '1 tháng'}.`);
  1389. // } else {
  1390. // await message.author.send('Bạn đã bị cấm sử dụng lệnh trong danh mục Economy vĩnh viễn.');
  1391. // }
  1392. // }
  1393. // }, 15 * 60 * 1000); // 15 phút
  1394. // }
  1395. // return;
  1396. // }
  1397.  
  1398. // // Cập nhật lại số lượng lệnh Economy đã sử dụng và thời gian thực hiện lệnh cuối
  1399. // await captchaCollection.updateOne(
  1400. // { userId },
  1401. // { $set: { userId, count: newCount, lastCommandAt: currentTime } },
  1402. // { upsert: true }
  1403. // );
  1404. // }
  1405.  
  1406.  
  1407. // // Kiểm tra nếu người dùng có captcha chưa hoàn thành trước khi cho phép thực thi lệnh
  1408. // const userCaptchaData = await captchaCollection.findOne({ userId });
  1409. // if (userCaptchaData && userCaptchaData.text) {
  1410. // return message.reply('Vui lòng hoàn thành captcha trong tin nhắn riêng để tiếp tục sử dụng các lệnh Economy.');
  1411. // }
  1412.  
  1413. try {
  1414. await command.execute(message, args, client, collections);
  1415. } catch (error) {
  1416. console.error(`Lỗi khi thực thi lệnh: ${commandName}`, error);
  1417.  
  1418. // Gửi lỗi đến kênh hoặc log ra console
  1419. // await message.reply('Đã xảy ra lỗi khi thực thi lệnh này!').catch(console.error);
  1420. // await message.channel.send(`Lỗi: \`\`\`${error.message}\`\`\``).catch(console.error);
  1421. // await message.channel.send(`Vị trí lỗi: \`\`\`${error.stack}\`\`\``).catch(console.error);
  1422. }
  1423.  
  1424.  
  1425. });
  1426.  
  1427.  
  1428. const WEBHOOK_URL2 = 'https://discord.com/api/webhooks/1316262829346521149/s3KnlNX8CykPxrcRnuHaTawd-BgiVzMDJTzIlNJSJF9LZRrmanNkjT382iiO6H59PCHh';
  1429.  
  1430. // Hàm gửi thông báo đến webhook
  1431. async function sendToWebhook(embed) {
  1432. try {
  1433. await axios.post(WEBHOOK_URL2, {
  1434. embeds: [embed],
  1435. });
  1436. } catch (error) {
  1437. console.error(`[WEBHOOK ERROR] Không thể gửi log đến webhook: ${error}`);
  1438. }
  1439. }
  1440.  
  1441. process.on('uncaughtException', (error) => {
  1442. const errorDetails = error.stack || 'Không thể lấy thông tin lỗi.';
  1443. sendToWebhook({
  1444. title: 'Lỗi chưa xử lý toàn cục',
  1445. description: `Đã xảy ra lỗi chưa xử lý trong ứng dụng.\n\n**Lỗi**:\n${error.message}\n\n**Chi tiết**:\n${errorDetails}`,
  1446. color: 16711680, // Màu đỏ để chỉ lỗi
  1447. timestamp: new Date().toISOString(),
  1448. });
  1449.  
  1450. // Ghi lỗi vào file log
  1451. const fs = require('fs');
  1452. fs.appendFileSync('error.log', `${new Date().toISOString()} - ${errorDetails}\n`);
  1453.  
  1454. // Nếu muốn dừng bot khi có lỗi không xử lý:
  1455. // process.exit(1);
  1456. });
  1457.  
  1458. // process.on('unhandledRejection', (reason, promise) => {
  1459. // sendToWebhook({
  1460. // title: 'Lỗi chưa xử lý Rejection',
  1461. // description: `Một Promise đã bị từ chối mà không có xử lý:\n\n**Lý do**:\n${reason}\n\n**Promise**:\n${JSON.stringify(promise)}`,
  1462. // color: 16711680, // Màu đỏ để chỉ lỗi
  1463. // timestamp: new Date().toISOString(),
  1464. // });
  1465. // });
  1466.  
  1467. process.on('unhandledRejection', (reason, promise) => {
  1468. let errorDetails;
  1469.  
  1470. if (reason instanceof Error) {
  1471. // Nếu lý do là một đối tượng lỗi (Error), lấy chi tiết stack
  1472. errorDetails = reason.stack;
  1473. } else {
  1474. // Nếu lý do không phải Error, chuyển đổi thành chuỗi để log
  1475. errorDetails = JSON.stringify(reason, null, 2);
  1476. }
  1477.  
  1478. console.error('Promise không được xử lý:', errorDetails);
  1479.  
  1480. // Gửi thông tin lỗi đến webhook hoặc ghi vào file
  1481. sendToWebhook({
  1482. title: 'Promise không được xử lý',
  1483. description: `Đã xảy ra lỗi trong Promise mà không được bắt.\n\n**Chi tiết lỗi:**\n\`\`\`${errorDetails}\`\`\``,
  1484. color: 16744448,
  1485. timestamp: new Date().toISOString(),
  1486. });
  1487.  
  1488. // Ghi lỗi vào file log
  1489. const fs = require('fs');
  1490. fs.appendFileSync('error.log', `${new Date().toISOString()} - Promise không được xử lý:\n${errorDetails}\n\n`);
  1491. });
  1492.  
  1493.  
  1494. client.login(config.token);
  1495.  
  1496.  
  1497.  
  1498. // Hàm resetGame để khởi động lại trò chơi
  1499. async function resetGame(channel, guildId, db) {
  1500. const wordsE = fs.readFileSync(path.resolve(__dirname, './data/wordsE.txt'), 'utf-8').split('\n').map(word => word.trim().toLowerCase());
  1501.  
  1502. const startingWord = wordsE[Math.floor(Math.random() * wordsE.length)];
  1503. await wordchainRoundsCollection.updateOne(
  1504. { guildId },
  1505. { $set: { word: startingWord, lastUser: '', roundNumber: 1 } },
  1506. { upsert: true }
  1507. );
  1508.  
  1509. await wordchainWordsCollection.deleteMany({ guildId });
  1510. await channel.send(`Trò chơi nối chữ bắt đầu lại với từ: **${startingWord}**`);
  1511. }
  1512.  
  1513. // Hàm để reset trò chơi đếm số
  1514. // async function resetCountGame(channel, guildId) {
  1515. // try {
  1516. // // Reset số về 0 và cập nhật cơ sở dữ liệu
  1517. // await dataBetaDev.query(
  1518. // `UPDATE count_channels SET current_number = 0, last_user_id = '' WHERE guild_id = ?`,
  1519. // [guildId]
  1520. // );
  1521.  
  1522. // channel.send('Trò chơi đếm số đã được khởi động lại. Con số bắt đầu là 0.');
  1523. // } catch (err) {
  1524. // console.error('Có lỗi khi reset trò chơi đếm số:', err);
  1525. // }
  1526. // }
  1527.  
  1528. // Hàm kiểm tra số La Mã hợp lệ
  1529. function validateRoman(roman) {
  1530. const romanRegex = /^(?=[MDCLXVI])(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/;
  1531. return romanRegex.test(roman);
  1532. }
  1533.  
  1534. // Hàm chuyển đổi số La Mã thành số nguyên
  1535. function fromRoman(roman) {
  1536. const romanMap = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 };
  1537. let num = 0;
  1538. let prev = 0;
  1539.  
  1540. for (let i = roman.length - 1; i >= 0; i--) {
  1541. const current = romanMap[roman[i]];
  1542.  
  1543. // Kiểm tra nếu ký tự không hợp lệ
  1544. if (!current) return NaN;
  1545.  
  1546. if (current < prev) {
  1547. num -= current;
  1548. } else {
  1549. num += current;
  1550. }
  1551. prev = current;
  1552. }
  1553.  
  1554. return num;
  1555. }
  1556.  
  1557. function toRoman(num) {
  1558. if (num <= 0) return ''; // Đảm bảo không tạo chuỗi rỗng cho số không hợp lệ
  1559.  
  1560. const romanNumerals = [
  1561. ["M", 1000],
  1562. ["CM", 900],
  1563. ["D", 500],
  1564. ["CD", 400],
  1565. ["C", 100],
  1566. ["XC", 90],
  1567. ["L", 50],
  1568. ["XL", 40],
  1569. ["X", 10],
  1570. ["IX", 9],
  1571. ["V", 5],
  1572. ["IV", 4],
  1573. ["I", 1]
  1574. ];
  1575.  
  1576. let roman = "";
  1577. for (const [letter, value] of romanNumerals) {
  1578. while (num >= value) {
  1579. roman += letter;
  1580. num -= value;
  1581. }
  1582. }
  1583. return roman;
  1584. }
  1585.  
  1586.  
  1587. // Hàm reset trò chơi đếm số La Mã
  1588. async function resetRomanCountGame(channel, guildId, romanCountChannelsCollection) {
  1589. await romanCountChannelsCollection.updateOne(
  1590. { guildId },
  1591. { $set: { currentNumber: 1, lastUserId: '' } }
  1592. );
  1593. channel.send('Trò chơi đếm số La Mã đã được reset! Con số bắt đầu là I.');
  1594. }
  1595.  
  1596. })();
Advertisement
Add Comment
Please, Sign In to add comment