From b51eebc623f0951d4e3e6614afe55117c277bdfd Mon Sep 17 00:00:00 2001 From: Degradin <42292046+Degradin@users.noreply.github.com> Date: Thu, 9 Jan 2025 20:06:02 +0300 Subject: [PATCH] v5.1 Crons, cards, no inventory --- bot.js | 10 +- config/index.js | 2 + models/character.model.js | 32 +- models/inventory.model.js | 41 ++ models/items.model.js | 40 ++ models/stolencards.model.js | 45 ++ package-lock.json | 65 +++ package.json | 2 + rpg.js | 890 ++++++++++++++++++++++++++++++++---- 9 files changed, 1019 insertions(+), 108 deletions(-) create mode 100644 models/inventory.model.js create mode 100644 models/items.model.js create mode 100644 models/stolencards.model.js diff --git a/bot.js b/bot.js index 6b079e5..c537876 100644 --- a/bot.js +++ b/bot.js @@ -1,6 +1,7 @@ // Подключаем необходимые библиотеки const { Telegraf, Scenes, session, Markup, Stage } = require('telegraf'); const { Op } = require('sequelize'); +const schedule = require('node-schedule'); const sequelize = require('./db'); // Подключение базы данных // Подключаем обработчики const commands = require('./commands'); @@ -1396,13 +1397,12 @@ resetCasinoFlag(); // Запускаем функцию updateResourcePricesMessage(); -// Запускаем процесс восстановления цен каждые 15 минут -setInterval(recoverResourcePrices, 15 * 60 * 1000); // Запускаем обновление каждые 15 минут -setInterval(updateResourcePricesMessage, 15 * 60 * 1000); +schedule.scheduleJob('*/15 * * * *', recoverResourcePrices); +schedule.scheduleJob('*/15 * * * *', updateResourcePricesMessage); // Запускаем процессы каждый час -setInterval(resourceProduction, 60 * 60 * 1000); -setInterval(resourceTransportation, 60 * 60 * 1000); +schedule.scheduleJob('0 * * * *', resourceProduction); // Каждый час в начале часа +schedule.scheduleJob('0 * * * *', resourceTransportation); // Каждый час bot.command('force_prod', async (ctx) => { diff --git a/config/index.js b/config/index.js index f3654b7..63bb6e7 100644 --- a/config/index.js +++ b/config/index.js @@ -10,6 +10,8 @@ module.exports = { equipment : require('../presets/equipment.json'), UserModel : require('../models/user.model'), CharacterModel : require('../models/character.model'), + ItemsModel : require('../models/items.model'), + StolenCardsModel : require('../models/stolencards.model'), WorldModel : require('../models/world.model'), JobModel : require('../models/job.model'), PropertyModel : require('../models/property.model'), diff --git a/models/character.model.js b/models/character.model.js index 0de23b7..6f1170a 100644 --- a/models/character.model.js +++ b/models/character.model.js @@ -24,59 +24,57 @@ const Character = sequelize.define('character', { hp: { type: DataTypes.INTEGER, defaultValue: 100 - }, // Текущее здоровье + }, max_hp: { type: DataTypes.INTEGER, defaultValue: 100 - }, // Максимальное здоровье + }, armor: { type: DataTypes.INTEGER, defaultValue: 0 - }, // Броня для уменьшения урона + }, stamina: { type: DataTypes.INTEGER, defaultValue: 100 - }, // Текущая выносливость + }, max_stamina: { type: DataTypes.INTEGER, defaultValue: 100 - }, // Максимальная выносливость + }, force: { type: DataTypes.INTEGER, defaultValue: 1 - }, // "F": физическая сила, влияет на урон + }, intelligence: { type: DataTypes.INTEGER, defaultValue: 1 - }, // "I": интеллект для исследований/крафта + }, resilience: { type: DataTypes.INTEGER, defaultValue: 1 - }, // "R": устойчивость, влияет на здоровье и защиту + }, endurance: { type: DataTypes.INTEGER, defaultValue: 1 - }, // "E": выносливость, влияет на количество выполняемых заданий + }, dirtymoney: { type: DataTypes.INTEGER, defaultValue: 0 - }, // Грязные деньги, заработанные нелегально + }, stealedcards: { type: DataTypes.INTEGER, defaultValue: 0 - }, // Украденные карточки + }, shoprobcd: { type: DataTypes.INTEGER, defaultValue: 0 - }, // КД на ограбление магазина + }, pocketstealcd: { type: DataTypes.INTEGER, defaultValue: 0 - }, // КД на кражу из кармана - inventory: { - type: DataTypes.JSON, - defaultValue: [] - }, // Инвентарь, где будут храниться предметы + }, + activeEffects: { type: DataTypes.JSON, allowNull: true, defaultValue: [] }, + equippedItems: { type: DataTypes.ARRAY(DataTypes.INTEGER), allowNull: true, defaultValue: [] }, }); module.exports = Character; diff --git a/models/inventory.model.js b/models/inventory.model.js new file mode 100644 index 0000000..d8435a6 --- /dev/null +++ b/models/inventory.model.js @@ -0,0 +1,41 @@ +const { DataTypes } = require('sequelize'); +const sequelize = require('../db'); + +const Inventory = sequelize.define('inventory', { + telegram_id: { + type: DataTypes.BIGINT, + primaryKey: true + }, + name: { + type: DataTypes.STRING, + allowNull: false, + }, + description: { + type: DataTypes.TEXT, + allowNull: false, + }, + effectData: { + type: DataTypes.JSON, + allowNull: true + }, + price: { + type: DataTypes.INTEGER, + allowNull: false, + }, + rarity: { + type: DataTypes.INTEGER, + allowNull: false, + }, + type: { + type: DataTypes.STRING, // Тип предмета (например, "инструмент", "ресурс") + allowNull: false, + }, + duration: { + type: DataTypes.INTEGER, + allowNull: true + }, // Длительность эффекта в секундах +}); + + + +module.exports = Inventory; diff --git a/models/items.model.js b/models/items.model.js new file mode 100644 index 0000000..7791bad --- /dev/null +++ b/models/items.model.js @@ -0,0 +1,40 @@ +const { DataTypes } = require('sequelize'); +const sequelize = require('../db'); + +const Item = sequelize.define('item', { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + name: { + type: DataTypes.STRING, + allowNull: false, + }, + description: { + type: DataTypes.TEXT, + allowNull: false, + }, + effectData: { + type: DataTypes.JSON, + allowNull: true + }, + price: { + type: DataTypes.INTEGER, + allowNull: false, + }, + rarity: { + type: DataTypes.INTEGER, + allowNull: false, + }, + type: { + type: DataTypes.STRING, // Тип предмета (например, "инструмент", "ресурс") + allowNull: false, + }, + duration: { + type: DataTypes.INTEGER, + allowNull: true + }, // Длительность эффекта в секундах +}); + +module.exports = Item; diff --git a/models/stolencards.model.js b/models/stolencards.model.js new file mode 100644 index 0000000..24d2b17 --- /dev/null +++ b/models/stolencards.model.js @@ -0,0 +1,45 @@ +const { DataTypes } = require('sequelize'); +const sequelize = require('../db'); + +const StolenCard = sequelize.define('stolencard', { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + userId: { + type: DataTypes.BIGINT, + allowNull: false, + }, + balance: { + type: DataTypes.INTEGER, + allowNull: false, + }, + cardNumber: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + pin: { + type: DataTypes.STRING, + allowNull: false, + }, + cvv: { + type: DataTypes.STRING, + allowNull: false, + }, + holderName: { + type: DataTypes.STRING, + allowNull: false, + }, + bankName: { + type: DataTypes.STRING, + allowNull: false, + }, + expiresDate: { + type: DataTypes.STRING, + allowNull: false, + }, +}); + +module.exports = StolenCard; diff --git a/package-lock.json b/package-lock.json index d7fc6c1..2b12458 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,11 @@ "version": "0.0.2", "license": "ISC", "dependencies": { + "@faker-js/faker": "^9.3.0", "dotenv": "^16.4.7", "error-stack-parser": "^2.1.4", "fs": "^0.0.1-security", + "node-schedule": "^2.1.1", "nodemon": "^3.0.1", "pg": "^8.6.0", "pg-hstore": "^2.3.3", @@ -23,6 +25,22 @@ "voucher-code-generator": "^1.3.0" } }, + "node_modules/@faker-js/faker": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.3.0.tgz", + "integrity": "sha512-r0tJ3ZOkMd9xsu3VRfqlFR6cz0V/jFYRswAIpC+m/DIfAUXq7g8N7wTAlhSANySXYGKzGryfDXwtwsY8TxEIDw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0.0", + "npm": ">=9.0.0" + } + }, "node_modules/@pm2/agent": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.4.tgz", @@ -574,6 +592,18 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "license": "MIT", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/croner": { "version": "4.1.97", "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", @@ -1078,6 +1108,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -1087,6 +1123,15 @@ "node": ">=12" } }, + "node_modules/luxon": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1220,6 +1265,20 @@ } } }, + "node_modules/node-schedule": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", + "license": "MIT", + "dependencies": { + "cron-parser": "^4.2.0", + "long-timeout": "0.1.1", + "sorted-array-functions": "^1.3.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/nodemon": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", @@ -1956,6 +2015,12 @@ "node": ">= 14" } }, + "node_modules/sorted-array-functions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", + "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==", + "license": "MIT" + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index 3b541bf..936d4a8 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,11 @@ "author": "Degradin", "license": "ISC", "dependencies": { + "@faker-js/faker": "^9.3.0", "dotenv": "^16.4.7", "error-stack-parser": "^2.1.4", "fs": "^0.0.1-security", + "node-schedule": "^2.1.1", "nodemon": "^3.0.1", "pg": "^8.6.0", "pg-hstore": "^2.3.3", diff --git a/rpg.js b/rpg.js index 727dbea..68fd69e 100644 --- a/rpg.js +++ b/rpg.js @@ -1,4 +1,6 @@ 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'); // Подключение базы данных @@ -6,66 +8,26 @@ const sequelize = require('./db'); // Подключение базы данны const utils = require('./utils'); const handlers = require('./handlers'); const { + phones, + expToUp, UserModel, CharacterModel, + ItemsModel, + StolenCardsModel, WorldModel, - JobModel, PropertyModel, AFKPropertyModel, BusinessModel, - ReportModel, BlockModel, - PromocodeModel, EnterpriseModel, WarehouseModel, TruckModel, - SaleModel, 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 - switch(ctx.updateType){ - case `message`: - console.log(utils.getCurrentTime() + `: ` + username + `: ` + ctx.update.message.text) - break; - case `callback_query`: - console.log(utils.getCurrentTime() + `: ${username}: ${ctx.update.callback_query.data}`) - break; - default: - console.log(ctx) - } - const start = Date.now() - const timeoutPromise = new Promise((resolve, reject) => { - - setTimeout(() => { - reject(new Error('timeout')) - }, 1000 * 5) - }) - - const nextPromise = next() - .then(() => { - const ms = Date.now() - start - }) - .catch((error) => { - handleError(error, ctx) - }) - - return Promise.race([timeoutPromise, nextPromise]) - .catch((error) => { - if (error.message === 'timeout') { - console.error('timeout', ctx.update) - return false - } - - return true - }) - }) rpg.hears('RPG', async (ctx) => { let message = `Меню:\n`; @@ -79,6 +41,9 @@ rpg.action('rpg_profile', async (ctx) => { // Ищем персонажа const character = await CharacterModel.findOne({ where: { telegram_id: telegramId } }); + const stolenCards = await StolenCardsModel.findAll({ + where: { userId: character.telegram_id } + }); if (!character) { return ctx.reply('Персонаж не найден. Создайте нового персонажа, чтобы начать игру!'); @@ -88,15 +53,15 @@ rpg.action('rpg_profile', async (ctx) => { const profile = ` 🎭 Профиль персонажа: 👤 Имя: ${character.name || 'Не указано'} -🏆 Уровень: ${character.level} (${character.exp}/${character.level * 100} опыта) +🏆 Уровень: ${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} -💰 Грязные деньги: ${character.dirtymoney} -🃏 Карточки: ${character.stealedcards} +💰 Грязные деньги: ${utils.spaces(character.dirtymoney)} +🃏 Карточки: ${stolenCards.length} 🎒 Инвентарь (${character.inventory.length}/10): ${character.inventory.map((item) => item.name).join(', ') || 'Пусто'} `; @@ -110,10 +75,10 @@ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // Хранилище для отслеживания пользователей, которые уже прошли ввод const usersCrimeNet = new Set(); -const usersLocks = 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); @@ -132,7 +97,7 @@ rpg.hears('CampFireGG.Crime', async (ctx) => { ]; // Отправляем первое сообщение - let sentMessage = await ctx.reply('> Initializing Crime.net...'); + let sentMessage = await ctx.reply('> Initializing CampFireGG.Crime...'); // Симуляция показа строки ssh блоками let currentText = ''; @@ -155,33 +120,356 @@ rpg.hears('CampFireGG.Crime', async (ctx) => { // Финальное меню после задержки await delay(2000); - await ctx.telegram.editMessageText( - sentMessage.chat.id, - sentMessage.message_id, - undefined, - `🚨 Добро пожаловать в CampFireGG.Crime 🚨\n\n`, - Markup.inlineKeyboard([ - [Markup.button.callback('💼 Задачи', 'crime_missions')], - [Markup.button.callback('📊 Профиль', 'rpg_profile')], - [Markup.button.callback('💰 ...', 'crime_market')], - ]) - )} else { - // Показываем только меню, если команда уже была введена - await ctx.reply( - `🚨 Добро пожаловать в CampFireGG.Crime 🚨\n\n`, - Markup.inlineKeyboard([ - [Markup.button.callback('💼 Задачи', 'crime_missions')], - [Markup.button.callback('📊 Профиль', 'rpg_profile')], - [Markup.button.callback('💰 ...', 'crime_market')], - ]) - ); + 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`, + await ctx.editMessageText(`💼 **Задачи:**\n Для карманных краж тебе не нужно ничего, главное не попадись.\n А вот после ограбления магазина в переулке не спрячешься, без тачки на миссию нельзя.`, Markup.inlineKeyboard([ [{text: 'Карманные кражи [1 lvl.]', callback_data: `POCKET_ACTION`}], [{text: 'Магазин [5 lvl.]', callback_data: `SHOP_ACTION`}], @@ -234,14 +522,16 @@ rpg.action(`MONEY_IN_POCKET`, async (ctx) => { } // Расчёт шанса на успешную кражу - let baseChance = 20; // Базовый шанс + 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)} из кармана.`); @@ -256,10 +546,16 @@ rpg.action(`PHONE`, async (ctx) => { let baseChance = 20; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 - if(chance < randomRoll) return ctx.editMessageText('Вы были замечены во время кражи.'); + 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)}`) } @@ -282,11 +578,15 @@ 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 = 20; // Базовый шанс + let baseChance = 35; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 - if(chance < randomRoll) return ctx.editMessageText('Вы были замечены во время кражи.'); + 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)} из бумажника.`) @@ -298,8 +598,12 @@ rpg.action(`CARD_IN_WALLET`, async (ctx) => { let baseChance = 20; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 - if(chance < randomRoll) return ctx.editMessageText('Вы были замечены во время кражи.'); - character.stealedcards += 1 + 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(`Вы успешно украли 💳 из бумажника.`) }); @@ -310,7 +614,10 @@ rpg.action(`POCKET_BAG`, async (ctx) => { let baseChance = 20; // Базовый шанс let chance = baseChance + character.intelligence * 2; // Увеличиваем шанс на 2% за каждый пункт "Разума". let randomRoll = utils.rand(0, 100); // Случайное число от 0 до 100 - if(chance < randomRoll) return ctx.editMessageText('Вы были замечены во время кражи.'); + if(chance < randomRoll) { + Exp(ctx, character, 1) + return ctx.editMessageText('Вы были замечены во время кражи.') + } let times = utils.rand(2,20) let moneyIn = 0 let text = `` @@ -336,6 +643,7 @@ rpg.action(`POCKET_BAG`, async (ctx) => { break; } } + Exp(ctx, character, character.intelligence + times) character.dirtymoney += moneyIn character.save() return ctx.editMessageText(`Вы успешно украли сумку и сбыли все ценности из нее:\n${text}\nОбщий куш: Ð${utils.spaces(moneyIn)}`) @@ -344,7 +652,7 @@ rpg.action(`POCKET_BAG`, async (ctx) => { rpg.action('crime_menu', async (ctx) => { await ctx.answerCbQuery(); await ctx.editMessageText( - `💻 **Crime.net Menu**`, + `💻 CampFireGG.Crime Menu`, Markup.inlineKeyboard([ [Markup.button.callback('💼 Задачи', 'crime_missions')], [Markup.button.callback('📊 Профиль', 'crime_stats')], @@ -354,12 +662,11 @@ rpg.action('crime_menu', async (ctx) => { }); rpg.action('SHOP_ACTION', async (ctx) => { - console.log('1') 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.weapon == 0) return ctx.editMessageText('Для данного задания нужен ствол.') + 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) @@ -387,7 +694,7 @@ rpg.action(`SHOP_CASH_BREAK`, async (ctx) => { //ctx.editMessageText('Вы начали взлом кассы.'); //return ctx.scene.enter('LOCKPICK') } - for(i=0; i { cashIn += utils.rand(1000, 10000) ctx.editMessageText(`⏏️ Вы достали из кассы: Ð${utils.spaces(cashIn)}`) @@ -395,6 +702,7 @@ rpg.action(`SHOP_CASH_BREAK`, async (ctx) => { timer += 500 } setTimeout(() => { + Exp(ctx, character, character.intelligence + 25) character.dirtymoney += cashIn character.save() return ctx.editMessageText(`Вы достали из кассы Ð${utils.spaces(cashIn)}, пора валить.`, Markup.inlineKeyboard([ @@ -411,10 +719,11 @@ rpg.action(`SHOP_CASH_SMASH`, async (ctx) => { 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)}`) @@ -422,6 +731,7 @@ rpg.action(`SHOP_CASH_SMASH`, async (ctx) => { timer += 500 } setTimeout(() => { + Exp(ctx, character, character.intelligence + 10) character.dirtymoney += cashIn character.save() return ctx.editMessageText(`Вы в спешке достали из кассы Ð${utils.spaces(cashIn)}, пора валить.`, Markup.inlineKeyboard([ @@ -436,7 +746,7 @@ rpg.action(`SHOP_CASH_BREAK_SUCCESS`, async (ctx) => { 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)}`) @@ -444,6 +754,7 @@ rpg.action(`SHOP_CASH_BREAK_SUCCESS`, async (ctx) => { timer += 500 } setTimeout(() => { + Exp(ctx, character, character.intelligence + 30) character.dirtymoney += cashIn character.save() return ctx.editMessageText(`Вы достали из кассы Ð${utils.spaces(cashIn)}, пора валить.`, Markup.inlineKeyboard([ @@ -481,6 +792,273 @@ rpg.action(/lock_*/, async (ctx) => { 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 = []; @@ -518,7 +1096,7 @@ function removeButton(ctx, buttonId) { } } - ctx.editMessageText('Взлом замка:', Markup.inlineKeyboard(keyboard)); + ctx.editMessageText('Взлом замка:', Markup.inlineKeyboard(keyboard).resize()); } // Восстановление здоровья (HP) @@ -555,6 +1133,82 @@ async function recoverStamina() { } } +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 минута) @@ -562,6 +1216,70 @@ function startRecoveryIntervals() { 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;