const { Telegraf, Scenes, session, Markup, Stage, Composer } = require('telegraf'); const schedule = require('node-schedule'); const { faker, fakerRU } = require('@faker-js/faker'); // Подключаем необходимые библиотеки const { Op } = require('sequelize'); const sequelize = require('./db'); // Подключение базы данных // Подключаем обработчики const utils = require('./utils'); const handlers = require('./handlers'); const { phones, expToUp, UserModel, CharacterModel, ItemsModel, StolenCardsModel, WorldModel, PropertyModel, AFKPropertyModel, BusinessModel, BlockModel, EnterpriseModel, WarehouseModel, TruckModel, ResourcePriceModel, SkillsModel, DailyModel } = global.config const rpg = new Composer(); rpg.hears('RPG', async (ctx) => { let message = `Меню:\n`; const buttons = []; buttons.push([{ text: 'Мой Персонаж', callback_data: 'rpg_profile' }]); return await ctx.reply(message, Markup.inlineKeyboard(buttons).resize()); }); rpg.action('rpg_profile', async (ctx) => { const telegramId = ctx.from.id; // Ищем персонажа const character = await CharacterModel.findOne({ where: { telegram_id: telegramId } }); const stolenCards = await StolenCardsModel.findAll({ where: { userId: character.telegram_id } }); if (!character) { return ctx.reply('Персонаж не найден. Создайте нового персонажа, чтобы начать игру!'); } // Формируем профиль const profile = ` 🎭 Профиль персонажа: 👤 Имя: ${character.name || 'Не указано'} 🏆 Уровень: ${character.level} (${character.exp}/${utils.spaces(expToUp[character.level])}) ❤️ Здоровье: ${character.hp}/${character.max_hp} 💪 Сила (F): ${character.force} 🧠 Интеллект (I): ${character.intelligence} 🛡️ Устойчивость (R): ${character.resilience} 🔋 Выносливость (E): ${character.endurance} 🔥 Стамина: ${character.stamina}/${character.max_stamina} 💰 Грязные деньги: ${utils.spaces(character.dirtymoney)} 🃏 Карточки: ${stolenCards.length} `; // Отправляем сообщение ctx.reply(profile.trim(), Markup.inlineKeyboard([ [Markup.button.callback('💼 Задачи', 'crime_missions')], ])); }); const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // Хранилище для отслеживания пользователей, которые уже прошли ввод const usersCrimeNet = new Set(); rpg.hears('CampFireGG.Crime', async (ctx) => { const userId = ctx.from.id; const character = await CharacterModel.findOne({ where: { telegram_id: userId } }); if (!usersCrimeNet.has(userId) && userId != 275416286){ // Если пользователь вводит команду впервые usersCrimeNet.add(userId); const username = ctx.from.username || 'User'; const randomServer = `secure.net-${Math.floor(Math.random() * 99 + 1)}.campfiregg.crime`; const sshCommand = `ssh ${username}@${randomServer}`; // Сообщение для симуляции const lines = [ `${sshCommand}`, `> Connecting to secure servers with RSA key...`, `> Authentication in progress...`, `> User "${username}" identified.`, `> Accessing CampFireGG.Crime...`, `> Connection established. Welcome, ${username}.`, ]; // Отправляем первое сообщение let sentMessage = await ctx.reply('> Initializing CampFireGG.Crime...'); // Симуляция показа строки ssh блоками let currentText = ''; let index = 0; while (index < lines[0].length) { const blockSize = Math.floor(Math.random() * 3) + 2; // Генерируем блок от 2 до 4 символов currentText += lines[0].slice(index, index + blockSize); // Добавляем блок текста index += blockSize; // Увеличиваем индекс await ctx.telegram.editMessageText(sentMessage.chat.id, sentMessage.message_id, undefined, currentText); await delay(100); // Задержка между блоками } // Последующие строки добавляются полностью, по одной for (let i = 1; i < lines.length; i++) { await delay(1500); // Задержка между строками currentText += `\n${lines[i]}`; await ctx.telegram.editMessageText(sentMessage.chat.id, sentMessage.message_id, undefined, currentText); } // Финальное меню после задержки await delay(2000); const buttons = [ [Markup.button.callback('💼 Задачи', 'crime_missions')], [Markup.button.callback('📊 Профиль', 'rpg_profile')], ]; //buttons.push([Markup.button.callback('💳 Карточки', 'view_cards')]); // Добавляем кнопку сообщения, если уровень персонажа равен 1 if (character && character.level === 1) { buttons.push([Markup.button.callback('📩 (1) Сообщение', '1st_message')]); } await ctx.telegram.editMessageText( sentMessage.chat.id, sentMessage.message_id, undefined, `🚨 Добро пожаловать в CampFireGG.Crime 🚨\n\n`, Markup.inlineKeyboard(buttons) )} else { // Показываем только меню, если команда уже была введена await ctx.reply( `🚨 Добро пожаловать в CampFireGG.Crime 🚨\n\n`, Markup.inlineKeyboard([ [Markup.button.callback('💼 Задачи', 'crime_missions')], [Markup.button.callback('📊 Профиль', 'rpg_profile')], //[Markup.button.callback('💳 Карточки', 'view_cards')], [Markup.button.callback('💰 Инвентарь', 'inventory')], ]) ); } }); rpg.action('1st_message', async (ctx) => { await ctx.answerCbQuery(); const message = `👤 Сообщение от неизвестного пользователя: \`\`\` "Добро пожаловать в CampFireGG.Crime. Если ты здесь, значит, у тебя есть вопросы. Забудь о них. Просто слушай." 🔥 F.I.R.E — твой путь к успеху: "Каждый из нас что-то может. Кто-то силён, кто-то вынослив, а кто-то дохуя умный. В мире CampFireGG.Crime это называется F.I.R.E. Запомни эти буквы — от них зависит твоя жизнь здесь." Force: Твоя мощь. Определяет, сколько импакта ты можешь внести. Чем выше, тем проще ликвидировать цель. Intelligence: Твой интеллект. Чем ты умнее, тем больше шансов, что операция пройдет гладко. А ещё мозги ускоряют твое обучение. Resilience: Твоя стойкость. Сколько времени тебе нужно, чтобы встать на ноги после провала? Чем выше этот параметр, тем быстрее ты восстанавливаешься. Endurance: Твоя выносливость. Без неё ты не сможешь много работать, а значит, и много зарабатывать. 💰 Деньги? Грязные. Иначе здесь не бывает. "Всё, что ты заработаешь здесь, будет грязным. Потратить можно только здесь, но есть способ отмыть деньги и перенести их на свой основной счёт. Всё зависит от твоего желания и возможностей." 💳 Карты? Да, их можно обналичить. "Карточки — это всегда плюс. Взломал, достал, получил деньги. Всё просто. Главное — не профукай их." 🕶️ Последний совет: "Каждое действие — это риск. Чем больше ты идёшь на риск, тем больше получаешь. Но если ошибёшься, можешь встрять. Так что думай." "Добро пожаловать. Удачи тебе, новобранец." \`\`\` `; await ctx.replyWithMarkdownV2(message, { disable_web_page_preview: true }); }); rpg.action('view_cards', async (ctx) => { try { // Получаем пользователя по Telegram ID const character = await CharacterModel.findByPk(ctx.from.id); if (!character) { return ctx.reply('Персонаж не найден!'); } // Получаем все украденные карточки для этого пользователя const stolenCards = await StolenCardsModel.findAll({ where: { userId: character.telegram_id } }); if (stolenCards.length === 0) { return ctx.reply('У вас нет украденных карточек.'); } const buttons = []; let message = 'Ваши украденные карты:\n\n'; stolenCards.forEach(card => { const lastFourDigits = card.cardNumber.slice(-4); // Берем последние 4 цифры карточки message += `🔒 Карта: *${lastFourDigits}\n`; // Генерация кнопок для брутфорса и покупки за лимит buttons.push([ Markup.button.callback(`💳 *${lastFourDigits}`, `brutecard_${card.id}`), //Markup.button.callback(`💰 *${lastFourDigits}`, `limitbuy_${card.id}`) ]); }); // Отправляем сообщение с кнопками await ctx.reply(message, Markup.inlineKeyboard(buttons)); } catch (error) { console.error('Ошибка при выводе карточек:', error); await ctx.reply('Произошла ошибка при получении ваших карточек.'); } }); rpg.action(/limitbuy_/, async (ctx) => { try { const cardId = ctx.match.input.split('_')[1]; // ID карточки const card = await StolenCardsModel.findByPk(cardId); // Получаем карточку if (!card) { return ctx.answerCbQuery('Карточка не найдена.'); } const character = await CharacterModel.findByPk(ctx.from.id); // Получаем персонажа if (!character) { return ctx.answerCbQuery('Персонаж не найден.'); } // Получаем 10 случайных предметов из базы const items = await ItemsModel.findAll({ limit: 10 }); // Если у пользователя нет записей о попытках, создаем их if (!attempts[ctx.from.id]) { attempts[ctx.from.id] = 0; } // Генерация кнопок с предметами const buttons = []; items.forEach(item => { const buttonText = `${item.name} - ¥${item.price}`; buttons.push([Markup.button.callback(buttonText, `purchase_${item.id}_${card.id}`)]); }); await ctx.reply( 'Выберите товар для покупки:\nПопробуйте угадать лимит карты.\n\n', Markup.inlineKeyboard(buttons) ); } catch (error) { console.error('Ошибка при обработке покупки через лимит:', error); } }); rpg.action(/purchase_/, async (ctx) => { try { const [_, itemId, cardId] = ctx.match.input.split('_'); const item = await ItemsModel.findByPk(itemId); const card = await StolenCardsModel.findByPk(cardId); const character = await CharacterModel.findByPk(ctx.from.id); if (!item || !card || !character) { return ctx.answerCbQuery('Ошибка при обработке покупки.'); } // Проверяем, не исчерпаны ли попытки if (attempts[ctx.from.id] >= 3) { // Сбрасываем попытки и уничтожаем карточку delete attempts[ctx.from.id]; await StolenCardsModel.destroy({ where: { id: cardId } }); return ctx.editMessageText( '❌ Все попытки исчерпаны! Карточка стала недействительной.' ); } // Если баланс карты меньше, чем цена товара, увеличиваем количество попыток if (card.balance < item.price) { attempts[ctx.from.id]++; await ctx.answerCbQuery(`Недостаточно средств! Попыток осталось: ${3 - ctx.session.attempts}`); return ctx.editMessageText(`Вы выбрали товар за ¥${item.price}, но у вас недостаточно средств.`); } // Если баланс карты достаточно для покупки, добавляем предмет в инвентарь character.inventory.push(item.id); await character.save(); // Если товар электронный, начисляем процент от стоимости на счет if (item.type === 'digital') { const profit = Math.round(item.price * 0.2); // 20% от стоимости товара character.dirtymoney += profit; await character.save(); await ctx.answerCbQuery(`Вы приобрели ${item.name} и перепродали за ¥${profit}.`); } else { await ctx.answerCbQuery(`Вы купили ${item.name}.`); } // Блокируем карту после покупки card.destroy({ where: { id: cardId } }); await card.save(); // Оповещаем пользователя await ctx.editMessageText(`${item.name} успешно куплен! Карта заблокирована.`); } catch (error) { console.error('Ошибка при обработке покупки:', error); } }); rpg.action(/purchase_fail_/, async (ctx) => { try { const [_, itemId, cardId] = ctx.match.input.split('_'); const item = await ItemsModel.findByPk(itemId); const card = await StolenCardsModel.findByPk(cardId); if (!item || !card) { return ctx.answerCbQuery('Ошибка при проверке предмета или карты.'); } await ctx.answerCbQuery('Недостаточно средств для покупки.'); } catch (error) { console.error('Ошибка при обработке неудачной покупки:', error); } }); // Обработка попытки взлома карточки rpg.action(/brutecard_/, async (ctx) => { const cardId = ctx.match.input.split('_')[1]; // Получаем ID карточки из callback_data const card = await StolenCardsModel.findByPk(cardId); // Ищем карточку в базе данных if (!card) { return ctx.answerCbQuery('Карточка не найдена.'); } const buttonsCount = 10; // Количество кнопок const winButton = utils.rand(1, buttonsCount); // Выбираем случайную кнопку для успешного пина const maxAttempts = 3; // Максимальное количество попыток // Если у пользователя нет записей о попытках, создаем их if (!attempts[ctx.from.id]) { attempts[ctx.from.id] = 0; } // Генерация кнопок const buttons = []; for (let i = 1; i <= buttonsCount; i++) { if (i === winButton) { // Если это победная кнопка (правильный ПИН) buttons.push({ text: `${card.pin}`, callback_data: `brute_success_${cardId}` }); } else { // Если это неудачная кнопка (случайный ПИН) buttons.push({ text: `${faker.finance.pin()}`, callback_data: `brute_fail_${cardId}` }); } } // Разбиваем кнопки на строки по 5 кнопок const rows = []; while (buttons.length > 0) { rows.push(buttons.splice(0, 5)); // Разбиваем на подмассивы по 5 кнопок } // Сортируем кнопки случайным образом const keyboard = Markup.inlineKeyboard( rows.sort(() => Math.random() - 0.5).map((row) => row) // Сортируем строки кнопок случайным образом ); // Отправляем сообщение с клавиатурой await ctx.reply( `💳 Брутфорс карты\n\nПопробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`, keyboard ); }); // Обработка неудачной попытки взлома rpg.action(/brute_fail_/, async (ctx) => { const cardId = ctx.match.input.split('_')[2]; const maxAttempts = 3; // Максимальное количество попыток // Увеличиваем количество попыток attempts[ctx.from.id]++; // Проверяем, не исчерпаны ли попытки if (attempts[ctx.from.id] >= maxAttempts) { // Сбрасываем попытки и уничтожаем карточку delete attempts[ctx.from.id]; await StolenCardsModel.destroy({ where: { id: cardId } }); return ctx.editMessageText( '❌ Все попытки исчерпаны! Карточка стала недействительной.' ); } // Ответ на нажатие кнопки ctx.answerCbQuery(`❌ Неправильный ПИН. Попыток осталось: ${maxAttempts - attempts[ctx.from.id]}`); // Обновляем клавиатуру const card = await StolenCardsModel.findByPk(cardId); const buttonsCount = 10; const winButton = utils.rand(1, buttonsCount); const buttons = []; for (let i = 1; i <= buttonsCount; i++) { if (i === winButton) { buttons.push({ text: `${card.pin}`, callback_data: `brute_success_${cardId}` }); } else { buttons.push({ text: `${faker.finance.pin()}`, callback_data: `brute_fail_${cardId}` }); } } const rows = []; while (buttons.length > 0) { rows.push(buttons.splice(0, 5)); } const keyboard = Markup.inlineKeyboard( rows.sort(() => Math.random() - 0.5).map((row) => row) ); // Обновляем сообщение с клавиатурой await ctx.editMessageText( `💳 Взлом карточки\n\nПопробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`, keyboard ); }); // Обработка успешной попытки взлома rpg.action(/brute_success_/, async (ctx) => { const cardId = ctx.match.input.split('_')[2]; console.log(cardId) const card = await StolenCardsModel.findByPk(cardId); console.log(card) if (!card) { return ctx.answerCbQuery('Карточка не найдена.'); } delete attempts[ctx.from.id]; const amount = card.balance; // Сумма денег за карточку const character = await CharacterModel.findByPk(ctx.from.id); // Увеличиваем грязные деньги пользователя character.dirtymoney += amount; await character.save(); // Удаляем карточку await card.destroy(); // Отправляем сообщение о выигрыше await ctx.editMessageText( `✅ Взлом успешен! Вы получили Ð${amount} грязных денег.` ); }); // Обработчики кнопок rpg.action('crime_missions', async (ctx) => { await ctx.answerCbQuery(); await ctx.editMessageText(`💼 **Задачи:**\n Для карманных краж тебе не нужно ничего, главное не попадись.\n А вот после ограбления магазина в переулке не спрячешься, без тачки на миссию нельзя.`, Markup.inlineKeyboard([ [{text: 'Карманные кражи [1 lvl.]', callback_data: `POCKET_ACTION`}], [{text: 'Магазин [5 lvl.]', callback_data: `SHOP_ACTION`}], //[{text: 'Банкомат', callback_data: `WIP`}], // [{text: 'Банковское отделение', callback_data: `WIP`}], //[{text: 'Угон', callback_data: `WIP`}], // [{text: 'Ювелирка', callback_data: `WIP`}], //[{text: 'Банк', callback_data: `WIP`}], [{text: '🔙 Back to Menu', callback_data: `crime_menu`}] ]), ); }); rpg.action(`POCKET_ACTION`, async (ctx) => { let user = await UserModel.findByPk(ctx.from.id) let character = await CharacterModel.findByPk(ctx.from.id); let pocketsteal = character.pocketstealcd if(character.level < 1) return ctx.editMessageText('Доступно с 1 уровня!') if(character.stamina < 10) return ctx.editMessageText('Вы устали!') let cooldown = utils.setCooldown(character, 3600, pocketsteal) if (character.pocketstealcd > cooldown.currentTime) return ctx.editMessageText(`📛 Данное действие будет доступно через ${cooldown.timeLeftInMinutes} мин.`); character.pocketstealcd = cooldown.endTime character.stamina -= 10 character.save() ctx.editMessageText('Выберите объект', Markup.inlineKeyboard([ [ {text: 'Карман', callback_data: `POCKET_TARGET`}, {text: 'Бумажник', callback_data: `POCKET_WALLET`}, {text: 'Сумка', callback_data: `POCKET_BAG`} ] ])) }); rpg.action(`POCKET_TARGET`, async (ctx) => { ctx.editMessageText('В кармане обнаружено', Markup.inlineKeyboard([ [ {text: 'Деньги', callback_data: `MONEY_IN_POCKET`}, {text: 'Телефон', callback_data: `PHONE`} ] ])) }); rpg.action(`MONEY_IN_POCKET`, async (ctx) => { // Получаем пользователя и его персонажа //let user = await UserModel.findByPk(ctx.from.id); let character = await CharacterModel.findByPk(ctx.from.id); if (!character) { return ctx.editMessageText('У вас нет персонажа. Создайте его перед началом.'); } // Расчёт шанса на успешную кражу let baseChance = 40; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 if (randomRoll > chance) { Exp(ctx, character, 1) return ctx.editMessageText('Вы были замечены во время кражи.'); } // Успешная кража let moneyIn = utils.rand(5, 1000); Exp(ctx, character, character.intelligence + 3) character.dirtymoney += moneyIn; await character.save(); return ctx.editMessageText(`Вы успешно украли Ð${utils.spaces(moneyIn)} из кармана.`); }); rpg.action(`PHONE`, async (ctx) => { let character = await CharacterModel.findByPk(ctx.from.id); //let user = await UserModel.findByPk(ctx.from.id) let property = await PropertyModel.findByPk(ctx.from.id); // Расчёт шанса на успешную кражу let baseChance = 20; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 if(chance < randomRoll) { Exp(ctx, character, 1) return ctx.editMessageText('Вы были замечены во время кражи.') } let randPhone = utils.rand(1,10) if (property.mobile.name) { console.log(Math.round(phones[randPhone].price/100*70)) let dirtyMoney = Math.round(phones[randPhone].price/100*70) console.log(character.intelligence + 10) Exp(ctx, character, character.intelligence + 10) character.dirtymoney += dirtyMoney return await ctx.reply(`Вы сбыли украденный ${phones[randPhone].name} за Ð${utils.spaces(dirtyMoney)}`) } property.mobile = phones[randPhone] await character.save() await property.save() return ctx.editMessageText(`Вы успешно украли ${phones[randPhone].name} из кармана.`) }); rpg.action(`POCKET_WALLET`, async (ctx) => { ctx.editMessageText('В бумажнике обнаружено', Markup.inlineKeyboard([ [ {text: 'Деньги', callback_data: `MONEY_IN_WALLET`}, {text: 'Карточка', callback_data: `CARD_IN_WALLET`} ] ])) }); rpg.action(`MONEY_IN_WALLET`, async (ctx) => { //let user = await UserModel.findByPk(ctx.from.id) let character = await CharacterModel.findByPk(ctx.from.id); // Расчёт шанса на успешную кражу let baseChance = 35; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 if(chance < randomRoll) { Exp(ctx, character, 1) return ctx.editMessageText('Вы были замечены во время кражи.') } let moneyIn = utils.rand(1000, 10000) Exp(ctx, character, character.intelligence + 5) character.dirtymoney += moneyIn character.save() return ctx.editMessageText(`Вы успешно украли Ð${utils.spaces(moneyIn)} из бумажника.`) }); rpg.action(`CARD_IN_WALLET`, async (ctx) => { //let user = await UserModel.findByPk(ctx.from.id) let character = await CharacterModel.findByPk(ctx.from.id); let baseChance = 20; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 if(chance < randomRoll) { Exp(ctx, character, 2) return ctx.editMessageText('Вы были замечены во время кражи.') } Exp(ctx, character, character.intelligence + 7) generateCard(ctx.from.id) character.save() return ctx.editMessageText(`Вы успешно украли 💳 из бумажника.`) }); rpg.action(`POCKET_BAG`, async (ctx) => { //let user = await UserModel.findByPk(ctx.from.id) let character = await CharacterModel.findByPk(ctx.from.id); let baseChance = 20; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 if(chance < randomRoll) { Exp(ctx, character, 1) return ctx.editMessageText('Вы были замечены во время кражи.') } let times = utils.rand(2,20) let moneyIn = 0 let text = `` let values = 0 for(i=1; i<=times; i++){ randomize = utils.rand(1,100) switch(randomize) { case 2: values = utils.rand(10000, 50000) moneyIn += values text += `+ Ð${utils.spaces(values)}\n` break; case 7: values = utils.rand(10000, 100000) moneyIn += values text += `+ Ð${utils.spaces(values)}\n` break; default: values = utils.rand(100, 3000) moneyIn += values text += `+ Ð${utils.spaces(values)}\n` break; } } Exp(ctx, character, character.intelligence + times) character.dirtymoney += moneyIn character.save() return ctx.editMessageText(`Вы успешно украли сумку и сбыли все ценности из нее:\n${text}\nОбщий куш: Ð${utils.spaces(moneyIn)}`) }); rpg.action('crime_menu', async (ctx) => { await ctx.answerCbQuery(); await ctx.editMessageText( `💻 CampFireGG.Crime Menu`, Markup.inlineKeyboard([ [Markup.button.callback('💼 Задачи', 'crime_missions')], [Markup.button.callback('📊 Профиль', 'crime_stats')], [Markup.button.callback('💰 ...', 'crime_market')], ]) ); }); rpg.action('SHOP_ACTION', async (ctx) => { let user = await UserModel.findByPk(ctx.from.id) let character = await CharacterModel.findByPk(ctx.from.id); let property = await PropertyModel.findByPk(ctx.from.id); if(character.level < 5) return ctx.editMessageText('Доступно с 5 уровня!') if(property.car1 == 0) return ctx.editMessageText('Для данного задания нужна тачка.') if(character.stamina < 25) return ctx.editMessageText('Вы устали!') let shoprobcd = character.shoprobcd let cooldown = utils.setCooldown(character, 3600, shoprobcd) if (character.shoprobcd > cooldown.currentTime) return ctx.editMessageText(`📛 Данное действие будет доступно через ${cooldown.timeLeftInMinutes} мин.`); character.shoprobcd = cooldown.endTime character.stamina -= 25 character.save() return ctx.editMessageText('Стадии:', Markup.inlineKeyboard([ [{text: 'Взлом кассы', callback_data: `SHOP_CASH_BREAK`}], [{text: 'Разбить кассу', callback_data: `SHOP_CASH_SMASH`}] ])) }); rpg.action(`SHOP_CASH_BREAK`, async (ctx) => { let character = await CharacterModel.findByPk(ctx.from.id); let baseChance = 20; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 let cashIn = utils.rand(1000, 10000) let timer = 1000 if(chance < randomRoll) { const keyboard = generateKeyboard(); ctx.deleteMessage() return ctx.reply('Касса закрыта, вы начали взлом замка:', keyboard); //ctx.editMessageText('Вы начали взлом кассы.'); //return ctx.scene.enter('LOCKPICK') } for(i=0; i { cashIn += utils.rand(1000, 10000) ctx.editMessageText(`⏏️ Вы достали из кассы: Ð${utils.spaces(cashIn)}`) }, timer) timer += 500 } setTimeout(() => { Exp(ctx, character, character.intelligence + 25) character.dirtymoney += cashIn character.save() return ctx.editMessageText(`Вы достали из кассы Ð${utils.spaces(cashIn)}, пора валить.`, Markup.inlineKeyboard([ [{text: 'Завершить ограбление', callback_data: `SHOP_END`}] ])) }, timer+300) }); rpg.action(`SHOP_CASH_SMASH`, async (ctx) => { let character = await CharacterModel.findByPk(ctx.from.id); let baseChance = 20; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 let cashIn = utils.rand(1000, 10000) let timer = 1000 if(chance < randomRoll) { Exp(ctx, character, 1) return ctx.editMessageText('Вы разбили кассовый аппарат, и сработала сигнализация. Вы сбежали.') } ctx.editMessageText('Вы разбили кассовый аппарат, и сработала сигнализация.') for(i=0; i { cashIn += utils.rand(500, 5000) ctx.editMessageText(`⏏️ Вы в спешке достали из кассы: Ð${utils.spaces(cashIn)}`) }, timer) timer += 500 } setTimeout(() => { Exp(ctx, character, character.intelligence + 10) character.dirtymoney += cashIn character.save() return ctx.editMessageText(`Вы в спешке достали из кассы Ð${utils.spaces(cashIn)}, пора валить.`, Markup.inlineKeyboard([ [{text: 'Завершить ограбление', callback_data: `SHOP_END`}] ])) }, timer+300) }); rpg.action(`SHOP_CASH_BREAK_SUCCESS`, async (ctx) => { let user = await UserModel.findByPk(ctx.from.id) let character = await CharacterModel.findByPk(ctx.from.id); delete attempts[ctx.from.id]; let cashIn = utils.rand(1000, 10000) let timer = 100 for(i=0; i { cashIn += utils.rand(3000, 10000) ctx.editMessageText(`⏏️ Вы достали из кассы: Ð${utils.spaces(cashIn)}`) }, timer) timer += 500 } setTimeout(() => { Exp(ctx, character, character.intelligence + 30) character.dirtymoney += cashIn character.save() return ctx.editMessageText(`Вы достали из кассы Ð${utils.spaces(cashIn)}, пора валить.`, Markup.inlineKeyboard([ [{text: 'Завершить ограбление', callback_data: `SHOP_END`}] ])) }, timer+300) }); rpg.action(`SHOP_END`, async (ctx) => { return ctx.editMessageText('Ограбление завершено!') }); const attempts = {}; // Храним количество попыток взлома для каждого пользователя rpg.action(/lock_*/, async (ctx) => { const userId = ctx.from.id; const buttonId = ctx.update.callback_query.data; // Если пользователя нет в списке попыток, добавляем его if (!attempts[userId]) { attempts[userId] = 0; } // Увеличиваем количество попыток attempts[userId] += 1; // Проверяем, не исчерпаны ли попытки if (attempts[userId] >= 5) { delete attempts[userId]; // Сбрасываем попытки после провала return ctx.editMessageText('Взлом провалился. Замок остается нетронутым.'); } // Ответ на нажатие кнопки ctx.answerCbQuery(`Штифт не сдвинулся. Попыток осталось: ${5 - attempts[userId]}`); removeButton(ctx, buttonId); }); rpg.action('inventory', async (ctx) => { try { const character = await CharacterModel.findByPk(ctx.from.id); if (!character) { return ctx.reply('Персонаж не найден!'); } const inventory = character.inventory || []; const equippedItems = character.equippedItems || []; // Если инвентарь пустой if (inventory.length === 0 && equippedItems.length === 0) { return ctx.reply('Ваш инвентарь пуст.'); } let message = '*Ваш инвентарь:*\n\n'; // Снаряженные предметы if (equippedItems.length > 0) { message += '🛡️ *Снаряженные предметы:*\n'; for (const item of equippedItems) { if (item) { message += `- ${item.name} (${item.type})\n`; } } message += '\n'; } // Предметы в инвентаре if (inventory.length > 0) { message += '🎒 *Предметы в инвентаре:*\n'; for (const item of inventory) { if (item) { message += `- ${item.name} (${item.type})\n`; } } message += '\n'; } // Кнопки для взаимодействия const buttons = []; for (const item of inventory) { if (item) { buttons.push( Markup.button.callback(`🎯 Использовать ${item.name}`, `use_item_${item.id}`) ); } } for (const item of equippedItems) { if (item) { buttons.push( Markup.button.callback(`🚫 Снять ${item.name}`, `use_item_${item.id}`) ); } } await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 })); } catch (error) { console.error('Ошибка при выводе инвентаря:', error); await ctx.reply('Произошла ошибка при отображении вашего инвентаря.'); } }); rpg.action(/use_item_(\d+)/, async (ctx) => { const itemId = parseInt(ctx.match[1], 10); const character = await CharacterModel.findByPk(ctx.from.id); const item = await ItemsModel.findByPk(itemId); const inventory = character.inventory || []; const isEquipped = character.equippedItems.some((equippedItem) => equippedItem.id === itemId); // Проверяем, снаряжен ли предмет // Проверка наличия предмета в инвентаре if (!inventory.some((invItem) => invItem.id === itemId) && !isEquipped) { return ctx.reply('У вас нет этого предмета.'); } // Если предмет уже снаряжен if (isEquipped) { // Снимаем предмет const resultMessages = await character.removeEquippedItem(item); // Убираем предмет из снаряженных return ctx.reply(`Вы сняли ${item.name}. ${resultMessages}`); } // Если предмет имеет временный эффект и уже активен if ( item.effectData && Array.isArray(item.effectData) && item.effectData.some((effect) => character.activeEffects.some((activeEffect) => activeEffect.type === effect.type) ) ) { return ctx.reply(`Эффект от ${item.name} уже активен.`); } // Обработка эффектов предмета if (item.effectData && Array.isArray(item.effectData)) { const resultMessages = processEffects(character, item.effectData, true); // true, так как мы снаряжаем предмет // Удаляем предмет из инвентаря, если он одноразовый if (item.type === 'consumable') { await character.removeItemFromInventory(item); } // Если предмет не одноразовый, снаряжаем его else { await character.addEquippedItem(item); // Добавляем предмет в снаряженные } await character.save(); // Явно сохраняем изменения в базе данных return ctx.reply(resultMessages); } ctx.reply('Этот предмет нельзя использовать.'); }); rpg.command('shop', async (ctx) => { const character = await CharacterModel.findByPk(ctx.from.id); if (!character) { return ctx.reply('Персонаж не найден!'); } const items = await ItemsModel.findAll(); if (items.length === 0) { return ctx.reply('Магазин пуст!'); } let message = 'Добро пожаловать в магазин! Здесь вы можете купить предметы:\n\n'; const buttons = items.map((item) => { return [Markup.button.callback(`${item.name} - ${item.price}₽`, `buy_item_${item.id}`)]; }); await ctx.reply(message, Markup.inlineKeyboard(buttons)); }); rpg.action(/buy_item_(\d+)/, async (ctx) => { const itemId = parseInt(ctx.match[1], 10); const character = await CharacterModel.findByPk(ctx.from.id); const item = await ItemsModel.findByPk(itemId); if (!character || !item) { return ctx.reply('Ошибка: Персонаж или предмет не найдены.'); } if (character.balance < item.price) { return ctx.reply('У вас недостаточно средств для покупки этого предмета.'); } // Снимаем деньги с баланса персонажа character.balance -= item.price; // Добавляем предмет в инвентарь (в массив) character.inventory = [...character.inventory, item]; await character.save(); // Отправляем сообщение об успешной покупке await ctx.reply(`Вы успешно купили ${item.name} за ${item.price}₽!`); // Можно добавить сюда логику для применения эффекта, если он есть }); //////////////////////////////////////////////////////////////////////////////////////////// CharacterModel.prototype.addEquippedItem = async function(item) { // Проверяем, есть ли уже предмет в инвентаре const isInInventory = this.inventory.some((invItem) => invItem.id === item.id); if (!isInInventory) { return; // Предмет должен быть в инвентаре } // Проверяем, есть ли уже этот предмет в снаряженных if (!this.equippedItems.some((equippedItem) => equippedItem.id === item.id)) { this.equippedItems.push(item.id); // Добавляем только ID предмета this.changed('equippedItems', true); // Помечаем, что поле изменилось await this.save(); // Сохраняем изменения в базе данных } }; CharacterModel.prototype.removeEquippedItem = async function(item) { // Проверяем, снаряжен ли предмет if (this.equippedItems.some((equippedItem) => equippedItem.id === item.id)) { // Убираем эффект, если он связан с данным предметом if (item.effectData && Array.isArray(item.effectData)) { const resultMessages = processEffects(this, item.effectData, false); // false, так как мы снимаем this.changed('equippedItems', true); // Помечаем изменение массива снаряженных await this.save(); return resultMessages; } // Удаляем предмет из снаряженных this.equippedItems = this.equippedItems.filter((equippedItem) => equippedItem.id !== item.id); this.changed('equippedItems', true); // Помечаем изменение массива снаряженных await this.save(); // Сохраняем изменения в базе данных } return null; }; const processEffects = (character, effects, isEquipping) => { let messages = []; effects.forEach((effect) => { // Если предмет снимается (isEquipping = false), эффекты снимаются if (!isEquipping) { switch (effect.type) { case 'damage_boost': character.force -= effect.amount; messages.push(`Ваш урон уменьшен на ${effect.amount}.`); break; case 'max_health_boost': character.max_hp -= effect.amount; messages.push(`Ваше максимальное здоровье уменьшено на ${effect.amount}.`); break; case 'stamina_penalty': character.max_stamina += effect.amount; messages.push(`Ваша выносливость увеличена на ${effect.amount}.`); break; default: messages.push('Эффект не распознан при снятии.'); } } else { // Применяем эффект при снаряжении switch (effect.type) { case 'heal': const maxHp = character.maxHp || 100; character.hp = Math.min(maxHp, character.hp + effect.amount); messages.push(`Вы восстановили ${effect.amount} HP.`); break; case 'damage_boost': character.force += effect.amount; messages.push(`Ваш урон увеличен на ${effect.amount}.`); break; case 'max_health_boost': character.max_hp += effect.amount; messages.push(`Ваше максимальное здоровье увеличено на ${effect.amount}.`); break; case 'stamina_penalty': character.max_stamina -= effect.amount; messages.push(`Ваша выносливость уменьшена на ${effect.amount}.`); break; default: messages.push('Эффект не распознан при надевании.'); } } }); return messages.join('\n'); }; function generateKeyboard() { const buttonsCount = 10; const buttons = []; const winButton = utils.rand(1, 10); for (let i = 1; i <= buttonsCount; i++) { if (i === winButton) { buttons.push({ text: `🔒`, callback_data: `SHOP_CASH_BREAK_SUCCESS` }); } else { buttons.push({ text: `🔒`, callback_data: `lock_${i}` }); } } const rows = []; while (buttons.length > 0) { rows.push(buttons.splice(0, 5)); // Разбиваем на подмассивы по 5 кнопок } console.log(rows) return { reply_markup: { inline_keyboard: rows, }, }; } function removeButton(ctx, buttonId) { const keyboard = ctx.update.callback_query.message.reply_markup.inline_keyboard; for (let row of keyboard) { for (let i = 0; i < row.length; i++) { if (row[i].callback_data === buttonId) { row[i].text = `🔓`; break; } } } ctx.editMessageText('Взлом замка:', Markup.inlineKeyboard(keyboard).resize()); } // Восстановление здоровья (HP) async function recoverHealth() { const characters = await CharacterModel.findAll({ where: { hp: { [Op.lt]: 100, // Восстанавливаем только тем, у кого HP меньше 100 }, }, }); for (const character of characters) { const recoveryRate = character.resilience; // Восстановление 10 HP за интервал character.hp = Math.min(character.hp + recoveryRate, 100); // Не превышаем максимум await character.save(); } } // Восстановление выносливости (стамины) async function recoverStamina() { const characters = await CharacterModel.findAll({ where: { stamina: { [Op.lt]: 100, // Восстанавливаем только тем, у кого стамина меньше 100 }, }, }); for (const character of characters) { const recoveryRate = character.endurance; // Восстановление 5 стамины за интервал character.stamina = Math.min(character.stamina + recoveryRate, 100); // Не превышаем максимум await character.save(); } } const reduceStealedCards = async () => { try { const characters = await CharacterModel.findAll(); for (const character of characters) { const stolenCards = await StolenCardsModel.findAll({ where: { userId: character.telegram_id } }); if (stolenCards.length > 0) { // Для каждой карточки уменьшаем баланс на половину for (const card of stolenCards) { card.balance = Math.ceil(card.balance / 2); // Баланс делим на 2 и округляем вверх await card.save(); // Сохраняем изменения карточки } // Удаляем половину карточек const cardsToDelete = Math.ceil(stolenCards.length / 2); const cardsToRemove = stolenCards.slice(0, cardsToDelete); for (const card of cardsToRemove) { await card.destroy(); // Удаляем карточки } console.log(`Карточки для персонажа ${character.id} успешно обновлены.`); } } console.log('Карточки всех игроков успешно обновлены.'); } catch (error) { console.error('Ошибка при обновлении карточек:', error); } }; async function generateCard(userId, balance) { console.log(balance) if(!Number(balance)){ balance = faker.finance.amount({dec: 0})*100 console.log('Random balance: ' + balance) }else{ balance = Math.floor(balance); console.log('Set balance: ' + balance) } const cardNumber = `${faker.finance.creditCardNumber()}`; // Генерация номера карты const pin = `${faker.finance.pin()}`; // Четырехзначный ПИН const cvv = `${faker.finance.creditCardCVV()}`; // Трехзначный CVV const holderName = `${faker.person.firstName()} ${faker.person.lastName()}`; // Имя и фамилия const bankName = faker.company.name(); // Название банка const expiresDate = `${Math.floor(Math.random() * 12) + 1}/${2025 + Math.floor(Math.random() * 5)}`; // Срок действия await StolenCardsModel.create({ userId, balance, cardNumber, pin, cvv, holderName, bankName, expiresDate, }); } async function Exp(ctx, character, experience) { character.exp += experience await ctx.sendMessage(`❇️ +${experience} exp.`) await character.save() for(i in expToUp){ if (character.exp >= expToUp[character.level]) { character.exp -= expToUp[character.level] character.level += 1 await character.save() await ctx.sendMessage(`⤴️ Уровень вашего персонажа повысился до ${character.level}!`)} } } // Периодическое выполнение задач function startRecoveryIntervals() { const interval = 5 * 1000; // Интервал в миллисекундах (например, 1 минута) setInterval(recoverHealth, interval); setInterval(recoverStamina, interval); } // Планируем выполнение задачи каждый день в 12 ночи schedule.scheduleJob('0 0 * * *', reduceStealedCards); rpg.command('force_reduce', async (ctx) => { reduceStealedCards() return await ctx.reply(`Принудительно`) }) rpg.command('steal_card', async (ctx) => { await generateCard(ctx.from.id) ctx.reply('💳 Вы украли новую карточку! Проверьте её в вашем инвентаре.'); }); startRecoveryIntervals() const fillItemsTable = async () => { try { const items = []; // Генерируем 10 случайных предметов for (let i = 0; i < 10; i++) { const item = { name: fakerRU.commerce.productName(), // Название товара description: fakerRU.lorem.sentence(), // Описание товара price: fakerRU.commerce.price({ dec: 0 }), // Цена товара rarity: 1, // Редкость (от 1 до 5) type: 'other', // Тип предмета }; items.push(item); } // Вставляем все 10 предметов в таблицу await ItemsModel.bulkCreate(items); console.log('Таблица предметов успешно заполнена!'); } catch (error) { console.error('Ошибка при заполнении таблицы предметов:', error); } }; // Запускаем функцию //fillItemsTable(); module.exports = rpg;