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, InventoryModel, ItemsModel, StolenCardsModel, WorldModel, PropertyModel, AFKPropertyModel, BusinessModel, BlockModel, EnterpriseModel, WarehouseModel, TruckModel, ResourcePriceModel, SkillsModel, DailyModel } = global.config const rpg = new Composer(); rpg.use(async (ctx, next) => { let id = ctx.from.id; let username = ctx.from.username; if (username == null) username = ctx.from.id; const currentTime = utils.getCurrentTime(); switch (ctx.updateType) { case 'message': console.log(`${currentTime}: [RPG] ${username}: ${ctx.update.message.text}`); break; case 'callback_query': console.log(`${currentTime}: [RPG] ${username}: ${ctx.update.callback_query.data}`); break; case 'edited_message': console.log(`${currentTime}: [RPG] ${username} edited: ${ctx.update.edited_message.text}`); break; default: console.log(`${currentTime}: [RPG] Unknown update type:`, ctx.update); } await next(); // Передаем управление следующему middleware }); 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.editMessageText(profile.trim(), Markup.inlineKeyboard([ [Markup.button.callback('💳 Карточки', 'view_cards')], [Markup.button.callback('🎒 Инвентарь', 'inventory')], [Markup.button.callback('🔙 В меню', 'crime_menu')], ])); }); 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) && character.level === 1){ // Если пользователь вводит команду впервые 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('💰 Магазин', 'shop')], ]) ); } }); 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}`) Markup.button.callback('🔙 В меню', 'crime_menu'), ]); }); // Отправляем сообщение с кнопками 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.InventoryModel.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); // Ищем карточку в базе данных const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } }); // Загружаем предметы из инвентаря if (!card) { return ctx.answerCbQuery('Карточка не найдена.'); } // Проверяем наличие "Эмулятора картридера" в инвентаре const emulator = inventory.find((item) => item.text_id === 'cardreader_emulator'); if (!emulator) { return ctx.reply('Для запуска брутфорса вам нужен "Эмулятор картридера".'); } // Удаляем "Эмулятор картридера" из инвентаря await InventoryModel.destroy({ where: { id: emulator.id } }); const buttonsCount = 10; // Количество кнопок const winButton = utils.rand(1, buttonsCount); // Выбираем случайную кнопку для успешного пина const maxAttempts = 3; // Максимальное количество попыток // Если у пользователя нет записей о попытках, создаем их if (!attempts[ctx.from.id]) { attempts[ctx.from.id] = 0; } // Генерация кнопок const buttons = []; let fakePin = 1234 for (let i = 1; i <= buttonsCount; i++) { if (i === winButton) { // Если это победная кнопка (правильный ПИН) buttons.push({ text: `${card.pin}`, callback_data: `brute_success_${cardId}` }); } else { fakePin = faker.finance.pin() // Если это неудачная кнопка (случайный ПИН) buttons.push({ text: `${fakePin}`, callback_data: `brute_fail_${cardId}_${i}` }); } } // Разбиваем кнопки на строки по 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 ━━━━━━━━━━━━━━━━━━━━ ${card.bankName.toUpperCase()} ━━━━━━━━━━━━━━━━━━━━ Номер: ${card.cardNumber} CVV: ${card.cvv} Владелец: ${card.holderName.toUpperCase()} Срок действия: ${card.expiresDate} ━━━━━━━━━━━━━━━━━━━━ Попробуйте подобрать правильный ПИН-код. У вас есть ${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 = []; let fakePin = 1234 for (let i = 1; i <= buttonsCount; i++) { fakePin = faker.finance.pin() if (i === winButton) { buttons.push({ text: `${card.pin}`, callback_data: `brute_success_${cardId}` }); } else { buttons.push({ text: `${fakePin}`, callback_data: `brute_fail_${cardId}_${i}` }); } } 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 ━━━━━━━━━━━━━━━━━━━━ ${card.bankName.toUpperCase()} ━━━━━━━━━━━━━━━━━━━━ Номер: ${card.cardNumber} CVV: ${card.cvv} Владелец: ${card.holderName.toUpperCase()} Срок действия: ${card.expiresDate} ━━━━━━━━━━━━━━━━━━━━ Попробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`, keyboard ); }); // Обработка успешной попытки взлома rpg.action(/brute_success_/, async (ctx) => { const cardId = ctx.match.input.split('_')[2]; const card = await StolenCardsModel.findByPk(cardId); 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( `💳 Брутфорс карты\n ━━━━━━━━━━━━━━━━━━━━ ${card.bankName.toUpperCase()} ━━━━━━━━━━━━━━━━━━━━ Номер: ${card.cardNumber} CVV: ${card.cvv} Владелец: ${card.holderName.toUpperCase()} Срок действия: ${card.expiresDate} ━━━━━━━━━━━━━━━━━━━━ ✅ Взлом успешен! Вы получили Ð${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: '🔙 В меню', 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) { let dirtyMoney = Math.round(phones[randPhone].price/100*70) 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('📊 Профиль', 'rpg_profile')], [Markup.button.callback('💰 Магазин', 'shop')], ]) ); }); 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 = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } }); if (inventory.length === 0) { return ctx.reply('Ваш инвентарь пуст.'); } let message = '*Ваш инвентарь:*\n\n'; // Группируем предметы по их состоянию (снаряженные/обычные) const equippedItems = inventory.filter((item) => item.equipped); const unequippedItems = inventory.filter((item) => !item.equipped); if (equippedItems.length > 0) { message += '🛡️ Снаряженные предметы:\n'; equippedItems.forEach((item) => { message += `- ${item.name} (${item.type})\n`; }); message += '\n'; } if (unequippedItems.length > 0) { message += '🎒 Предметы в инвентаре:\n'; unequippedItems.forEach((item) => { message += `- ${item.name} (${item.type})\n`; }); message += '\n'; } // Кнопки для взаимодействия const buttons = [ ...unequippedItems.map((item) => Markup.button.callback(`🔎 ${item.name}`, `view_item_${item.id}`) ), ...equippedItems.map((item) => Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`) ), ]; buttons.push(Markup.button.callback('🔙 В меню', 'crime_menu')); await ctx.editMessageText(message, Markup.inlineKeyboard(buttons, { columns: 2 })); } catch (error) { console.error('Ошибка при выводе инвентаря:', error); await ctx.reply('Произошла ошибка при отображении вашего инвентаря.'); } }); rpg.action(/view_item_(\d+)/, async (ctx) => { const itemId = parseInt(ctx.match[1], 10); const item = await InventoryModel.findByPk(itemId); if (!item || item.telegram_id != ctx.from.id) { return ctx.reply('Этот предмет не найден в вашем инвентаре.'); } const character = await CharacterModel.findByPk(ctx.from.id); if (!character) { return ctx.reply('Персонаж не найден.'); } if (item.equipped) { return ctx.reply(`${item.name} уже снаряжен.`); } const buttons = [] let message = `ℹ️ ${item.name}\n` message += ` 📜 ${item.description}\n\n 〰️Редкость: ${item.rarity}\n 🔤Тип: ${item.type}` if (!item.equipped){ buttons.push([Markup.button.callback(`🎯 Использовать ${item.name}`, `use_item_${item.id}`)]); } if (item.equipped && item.canBeEquipped) { buttons.push([Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`)]); } await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 })); }); rpg.action(/use_item_(\d+)/, async (ctx) => { const itemId = parseInt(ctx.match[1], 10); const item = await InventoryModel.findByPk(itemId); if (!item || item.telegram_id != ctx.from.id) { return ctx.reply('Этот предмет не найден в вашем инвентаре.'); } const character = await CharacterModel.findByPk(ctx.from.id); if (!character) { return ctx.reply('Персонаж не найден.'); } if (item.equipped) { return ctx.reply(`${item.name} уже снаряжен.`); } if (!item.canBeEquipped) { return ctx.answerCbQuery(`🚫 ${item.name} нельзя сейчас использовать.`); } // Применяем эффекты предмета if (item.effectData) { const resultMessages = processEffects(character, item.effectData, true); await ctx.answerCbQuery(resultMessages, {show_alert: true}); } if (item.canBeEquipped && item.type != 'consumable') { item.equipped = true; await item.save(); ctx.reply(`Вы снарядили ${item.name}.`); } if (item.canBeEquipped && item.type == 'consumable') { await InventoryModel.destroy({ where: { id: item.id } }); ctx.reply(`Вы использовали ${item.name}.`); } }); rpg.action(/unequip_item_(\d+)/, async (ctx) => { const itemId = parseInt(ctx.match[1], 10); const character = await CharacterModel.findByPk(ctx.from.id); const item = await InventoryModel.findByPk(itemId); if (!item || item.telegram_id != ctx.from.id) { return ctx.answerCbQuery('Этот предмет не найден в вашем инвентаре.'); } if (!item.equipped) { return ctx.answerCbQuery(`${item.name} не снаряжен.`); } if (item.effectData) { const resultMessages = processEffects(character, item.effectData, false); await ctx.editMessageText(resultMessages); } item.equipped = false; await item.save(); ctx.answerCbQuery(`Вы успешно сняли ${item.name}.`); }); rpg.action('shop', async (ctx) => { // Получаем текущую запись мира const world = await WorldModel.findOne({ where: { id: 1 } }); if (!world) { return ctx.reply('Магазин недоступен.'); } // Получаем ID предметов, доступных в магазине const { itemsInCrimeShop } = world; if (!itemsInCrimeShop || itemsInCrimeShop.length === 0) { return ctx.reply('Магазин пуст!'); } // Загружаем только те предметы, ID которых есть в массиве const items = await ItemsModel.findAll({ where: { id: itemsInCrimeShop } }); if (items.length === 0) { return ctx.reply('Магазин пуст!'); } let message = 'Добро пожаловать в магазин! Здесь вы можете купить предметы:\n\n'; // Генерируем кнопки, каждая кнопка будет в отдельной строке const buttons = items.map((item) => [ Markup.button.callback(`${item.name} - ${item.price}₽`, `buy_item_${item.id}`) ]); buttons.push([Markup.button.callback('🔙 В меню', 'crime_menu')]); // Отправляем сообщение с клавиатурой await ctx.editMessageText(message, Markup.inlineKeyboard(buttons)); }); rpg.action(/buy_item_(\d+)/, async (ctx) => { const itemId = parseInt(ctx.match[1], 10); const item = await ItemsModel.findByPk(itemId); const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } }); if (inventory.length >= 15) { return ctx.answerCbQuery('Инвентарь полон.', {show_alert: true}); } if (!item) { return ctx.reply('Предмет не найден.'); } const character = await CharacterModel.findByPk(ctx.from.id); if (!character) { return ctx.reply('Персонаж не найден.'); } if (character.balance < item.price) { return ctx.answerCbQuery('У вас недостаточно средств для покупки этого предмета.', {show_alert: true}); } // Снимаем деньги с баланса character.dirtymoney -= item.price; // Добавляем предмет в инвентарь await InventoryModel.create({ telegram_id: ctx.from.id, name: item.name, text_id: item.text_id, description: item.description, effectData: item.effectData, price: item.price, rarity: item.rarity, type: item.type, duration: item.duration, canBeEquipped: item.canBeEquipped, equipped: false }); await character.save(); ctx.answerCbQuery(`Вы успешно купили ${item.name} за ${item.price}₽!`, {show_alert: true}); }); //////////////////////////////////////////////////////////////////////////////////////////// CharacterModel.prototype.addEquippedItem = async function (item) { // Проверяем, находится ли предмет в инвентаре персонажа const inventoryItem = await InventoryModel.findOne({ where: { telegram_id: this.telegram_id, id: item.id }, }); if (!inventoryItem) { throw new Error('Предмет не найден в вашем инвентаре.'); } // Проверяем, не снаряжен ли уже этот предмет if (inventoryItem.equipped) { throw new Error('Этот предмет уже снаряжен.'); } // Снаряжаем предмет inventoryItem.equipped = true; await inventoryItem.save(); // Применяем эффекты предмета let resultMessages = []; if (inventoryItem.effectData) { resultMessages = processEffects(this, inventoryItem.effectData, true); await this.save(); // Сохраняем изменения в характеристиках персонажа } return resultMessages; }; CharacterModel.prototype.removeEquippedItem = async function (item) { // Проверяем, находится ли предмет в инвентаре персонажа const inventoryItem = await InventoryModel.findOne({ where: { telegram_id: this.telegram_id, id: item.id }, }); if (!inventoryItem || !inventoryItem.equipped) { throw new Error('Этот предмет не снаряжен.'); } // Снимаем предмет inventoryItem.equipped = false; await inventoryItem.save(); // Убираем эффекты предмета let resultMessages = []; if (inventoryItem.effectData) { resultMessages = processEffects(this, inventoryItem.effectData, false); await this.save(); // Сохраняем изменения в характеристиках персонажа } return resultMessages; }; const processEffects = (character, effects, isEquipping) => { let messages = []; effects.forEach((effect) => { if (!isEquipping) { // Снимаем эффекты switch (effect.type) { case 'damage_boost': character.force = Math.max(0, character.force - effect.amount); character.save() messages.push(`Ваш урон уменьшен на ${effect.amount}.`); break; case 'max_health_boost': character.max_hp = Math.max(1, character.max_hp - effect.amount); character.save() messages.push(`Ваше максимальное здоровье уменьшено на ${effect.amount}.`); break; case 'stamina_penalty': character.max_stamina += effect.amount; character.save() messages.push(`Ваша выносливость увеличена на ${effect.amount}.`); break; case 'intelligence_boost': character.intelligence -= Math.max(0, character.intelligence - effect.amount); character.save() messages.push(`Ваш интеллект уменьшена на ${effect.amount}.`); break; default: messages.push('Неизвестный эффект при снятии.'); } } else { // Применяем эффекты switch (effect.type) { case 'heal': character.hp = Math.min(character.max_hp, character.hp + effect.amount); character.save() messages.push(`Вы восстановили ${effect.amount} HP.`); break; case 'damage_boost': character.force += effect.amount; character.save() messages.push(`Ваша сила увеличена на ${effect.amount}.`); break; case 'max_health_boost': character.max_hp += effect.amount; character.save() messages.push(`Ваше максимальное здоровье увеличено на ${effect.amount}.`); break; case 'stamina_penalty': character.max_stamina -= effect.amount; character.save() messages.push(`Ваша выносливость уменьшена на ${effect.amount}.`); break; case 'stamina_recover': character.stamina = Math.min(character.max_stamina, character.stamina + effect.amount); character.save() messages.push(`Вы восстановили ${effect.amount} стамины.`); break; case 'intelligence_boost': character.intelligence += effect.amount; character.save() 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.name} успешно обновлены.`); } } console.log('Карточки всех игроков успешно обновлены.'); } catch (error) { console.error('Ошибка при обновлении карточек:', error); } }; async function generateCard(userId, 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;