From 125b782a640fb5ddc516da52436d86dd963fd080 Mon Sep 17 00:00:00 2001 From: Degradin Date: Fri, 10 Jan 2025 00:54:54 +0300 Subject: [PATCH] v5.2-rc Crime update --- bot.js | 7 +- commands/menu.js | 8 +- config/index.js | 8 + models/character.model.js | 148 +++++++-------- models/inventory.model.js | 20 +- rpg.js | 390 +++++++++++++++++++++++--------------- 6 files changed, 346 insertions(+), 235 deletions(-) diff --git a/bot.js b/bot.js index c537876..b856242 100644 --- a/bot.js +++ b/bot.js @@ -206,10 +206,11 @@ bot.command('start', async (ctx) => { return await ctx.reply('Главное меню', Markup .keyboard([ ['😎 Профиль'], // Row1 with 2 buttons - ['🗄️ Работать', '🌐 Организация', '🎁 Бонус', '🏯 Казино'], // Row2 with 2 buttons - ['🏗️ Предприятия'], + ['🗄️ Работать', '🌐 Организация', '🏗️ Предприятия', '🏯 Казино'], // Row2 with 2 buttons + ['CampFireGG.Crime'], + ['🎁 Бонус'], ['📦 Контейнеры'], - ['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'] // Row3 with 3 buttons + ['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'], ]) .resize() ) diff --git a/commands/menu.js b/commands/menu.js index e87d0af..8332361 100644 --- a/commands/menu.js +++ b/commands/menu.js @@ -10,14 +10,14 @@ module.exports = async (ctx) => { let user = await UserModel.findByPk(ctx.from.id) const buttons = [] if (user.status == 'admin') { - buttons.push("CampFireGG.Crime"); + buttons.push("Топ"); } - return await ctx.reply('Main Menu', Markup .keyboard([ ['😎 Профиль'], // Row1 with 2 buttons - ['🗄️ Работать', '🌐 Организация', '🎁 Бонус', '🏯 Казино'], // Row2 with 2 buttons - ['🏗️ Предприятия'], + ['🗄️ Работать', '🌐 Организация', '🏗️ Предприятия', '🏯 Казино'], // Row2 with 2 buttons + ['CampFireGG.Crime'], + ['🎁 Бонус'], ['📦 Контейнеры'], ['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'], buttons // Row3 with 3 buttons diff --git a/config/index.js b/config/index.js index 63bb6e7..b44dbd8 100644 --- a/config/index.js +++ b/config/index.js @@ -1,3 +1,10 @@ +const sequelize = require('../db'); +const Character = require('../models/character.model'); +const Inventory = require('../models/inventory.model'); +// Устанавливаем ассоциации здесь +Character.hasMany(Inventory, { foreignKey: 'telegram_id' }); +Inventory.belongsTo(Character, { foreignKey: 'telegram_id' }); + module.exports = { weaponshop : require('../json/weaponshop.json'), slots : require('../json/slots.json'), @@ -10,6 +17,7 @@ module.exports = { equipment : require('../presets/equipment.json'), UserModel : require('../models/user.model'), CharacterModel : require('../models/character.model'), + InventoryModel : require('../models/inventory.model'), ItemsModel : require('../models/items.model'), StolenCardsModel : require('../models/stolencards.model'), WorldModel : require('../models/world.model'), diff --git a/models/character.model.js b/models/character.model.js index 6f1170a..2e68745 100644 --- a/models/character.model.js +++ b/models/character.model.js @@ -1,80 +1,80 @@ -const sequelize = require('../db'); const { DataTypes } = require('sequelize'); +const sequelize = require('../db'); const Character = sequelize.define('character', { - telegram_id: { - type: DataTypes.BIGINT, - primaryKey: true, - unique: true - }, - username: { - type: DataTypes.STRING - }, - name: { - type: DataTypes.STRING - }, - level: { - type: DataTypes.INTEGER, - defaultValue: 1 - }, - exp: { - type: DataTypes.INTEGER, - defaultValue: 0 - }, - 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 - }, - intelligence: { - type: DataTypes.INTEGER, - defaultValue: 1 - }, - resilience: { - type: DataTypes.INTEGER, - defaultValue: 1 - }, - endurance: { - type: DataTypes.INTEGER, - defaultValue: 1 - }, - dirtymoney: { - type: DataTypes.INTEGER, - defaultValue: 0 - }, - stealedcards: { - type: DataTypes.INTEGER, - defaultValue: 0 - }, - shoprobcd: { - type: DataTypes.INTEGER, - defaultValue: 0 - }, - pocketstealcd: { - type: DataTypes.INTEGER, - defaultValue: 0 - }, - activeEffects: { type: DataTypes.JSON, allowNull: true, defaultValue: [] }, - equippedItems: { type: DataTypes.ARRAY(DataTypes.INTEGER), allowNull: true, defaultValue: [] }, + telegram_id: { + type: DataTypes.BIGINT, + primaryKey: true, + unique: true, + }, + username: { + type: DataTypes.STRING + }, + name: { + type: DataTypes.STRING + }, + level: { + type: DataTypes.INTEGER, + defaultValue: 1 + }, + exp: { + type: DataTypes.INTEGER, + defaultValue: 0 + }, + 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 + }, + intelligence: { + type: DataTypes.INTEGER, + defaultValue: 1 + }, + resilience: { + type: DataTypes.INTEGER, + defaultValue: 1 + }, + endurance: { + type: DataTypes.INTEGER, + defaultValue: 1 + }, + dirtymoney: { + type: DataTypes.INTEGER, + defaultValue: 0 + }, + stealedcards: { + type: DataTypes.INTEGER, + defaultValue: 0 + }, + shoprobcd: { + type: DataTypes.INTEGER, + defaultValue: 0 + }, + pocketstealcd: { + type: DataTypes.INTEGER, + defaultValue: 0 + }, + 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 index d8435a6..4912016 100644 --- a/models/inventory.model.js +++ b/models/inventory.model.js @@ -2,9 +2,17 @@ const { DataTypes } = require('sequelize'); const sequelize = require('../db'); const Inventory = sequelize.define('inventory', { - telegram_id: { - type: DataTypes.BIGINT, - primaryKey: true + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + telegram_id: { + type: DataTypes.BIGINT, // Используем другой внешний ключ + references: { + model: 'characters', // Указываем правильное имя модели + key: 'telegram_id', // Внешний ключ указывает на telegram_id в модели Character + }, }, name: { type: DataTypes.STRING, @@ -34,8 +42,10 @@ const Inventory = sequelize.define('inventory', { type: DataTypes.INTEGER, allowNull: true }, // Длительность эффекта в секундах + equipped: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, }); - - module.exports = Inventory; diff --git a/rpg.js b/rpg.js index 453957a..51c5756 100644 --- a/rpg.js +++ b/rpg.js @@ -12,6 +12,7 @@ const { expToUp, UserModel, CharacterModel, + InventoryModel, ItemsModel, StolenCardsModel, WorldModel, @@ -28,6 +29,32 @@ const { } = 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`; @@ -61,7 +88,7 @@ rpg.action('rpg_profile', async (ctx) => { 🔋 Выносливость (E): ${character.endurance} 🔥 Стамина: ${character.stamina}/${character.max_stamina} 💰 Грязные деньги: ${utils.spaces(character.dirtymoney)} -🃏 Карточки: ${stolenCards.length} +🃏 Карты: ${stolenCards.length} `; // Отправляем сообщение @@ -144,8 +171,9 @@ rpg.hears('CampFireGG.Crime', async (ctx) => { Markup.inlineKeyboard([ [Markup.button.callback('💼 Задачи', 'crime_missions')], [Markup.button.callback('📊 Профиль', 'rpg_profile')], - //[Markup.button.callback('💳 Карточки', 'view_cards')], - [Markup.button.callback('💰 Инвентарь', 'inventory')], + [Markup.button.callback('💳 Карточки', 'view_cards')], + [Markup.button.callback('🎒 Инвентарь', 'inventory')], + [Markup.button.callback('💰 Магазин', 'shop')], ]) ); } @@ -294,7 +322,7 @@ rpg.action(/purchase_/, async (ctx) => { } // Если баланс карты достаточно для покупки, добавляем предмет в инвентарь - character.inventory.push(item.id); + character.InventoryModel.push(item.id); await character.save(); // Если товар электронный, начисляем процент от стоимости на счет @@ -337,16 +365,26 @@ rpg.action(/purchase_fail_/, async (ctx) => { // Обработка попытки взлома карточки rpg.action(/brutecard_/, async (ctx) => { - const cardId = ctx.match.input.split('_')[1]; // Получаем ID карточки из callback_data - const card = await StolenCardsModel.findByPk(cardId); // Ищем карточку в базе данных + 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 buttonsCount = 10; // Количество кнопок - const winButton = utils.rand(1, buttonsCount); // Выбираем случайную кнопку для успешного пина - const maxAttempts = 3; // Максимальное количество попыток + // Проверяем наличие "Эмулятора картридера" в инвентаре + const emulator = inventory.find((item) => item.name === 'Эмулятор картридера'); + 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]) { @@ -373,16 +411,30 @@ rpg.action(/brutecard_/, async (ctx) => { // Сортируем кнопки случайным образом const keyboard = Markup.inlineKeyboard( - rows.sort(() => Math.random() - 0.5).map((row) => row) // Сортируем строки кнопок случайным образом + rows.sort(() => Math.random() - 0.5).map((row) => row) // Сортируем строки кнопок случайным образом ); // Отправляем сообщение с клавиатурой await ctx.reply( - `💳 Брутфорс карты\n\nПопробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`, + `💳 Брутфорс карты\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]; @@ -430,7 +482,17 @@ rpg.action(/brute_fail_/, async (ctx) => { // Обновляем сообщение с клавиатурой await ctx.editMessageText( - `💳 Взлом карточки\n\nПопробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`, + `💳 Брутфорс карты\n + ━━━━━━━━━━━━━━━━━━━━ + ${card.bankName.toUpperCase()} + ━━━━━━━━━━━━━━━━━━━━ + Номер: ${card.cardNumber} + CVV: ${card.cvv} + Владелец: ${card.holderName.toUpperCase()} + Срок действия: ${card.expiresDate} + ━━━━━━━━━━━━━━━━━━━━ + + Попробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`, keyboard ); }); @@ -458,7 +520,17 @@ rpg.action(/brute_success_/, async (ctx) => { // Отправляем сообщение о выигрыше await ctx.editMessageText( - `✅ Взлом успешен! Вы получили Ð${amount} грязных денег.` + `💳 Брутфорс карты\n + ━━━━━━━━━━━━━━━━━━━━ + ${card.bankName.toUpperCase()} + ━━━━━━━━━━━━━━━━━━━━ + Номер: ${card.cardNumber} + CVV: ${card.cvv} + Владелец: ${card.holderName.toUpperCase()} + Срок действия: ${card.expiresDate} + ━━━━━━━━━━━━━━━━━━━━ + + ✅ Взлом успешен! Вы получили Ð${amount}.` ); }); @@ -799,56 +871,44 @@ rpg.action('inventory', async (ctx) => { return ctx.reply('Персонаж не найден!'); } - const inventory = character.inventory || []; - const equippedItems = character.equippedItems || []; + // Загружаем предметы из инвентаря + const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } }); - // Если инвентарь пустой - if (inventory.length === 0 && equippedItems.length === 0) { + 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'; - for (const item of equippedItems) { - if (item) { - message += `- ${item.name} (${item.type})\n`; - } - } + equippedItems.forEach((item) => { + message += `- ${item.name} (${item.type})\n`; + }); message += '\n'; } - // Предметы в инвентаре - if (inventory.length > 0) { + if (unequippedItems.length > 0) { message += '🎒 *Предметы в инвентаре:*\n'; - for (const item of inventory) { - if (item) { - message += `- ${item.name} (${item.type})\n`; - } - } + unequippedItems.forEach((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}`) - ); - } - } + const buttons = [ + ...unequippedItems.map((item) => + Markup.button.callback(`🎯 Использовать ${item.name}`, `use_item_${item.id}`) + ), + ...equippedItems.map((item) => + Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`) + ), + ]; await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 })); } catch (error) { @@ -857,66 +917,64 @@ rpg.action('inventory', async (ctx) => { } }); + 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 item = await InventoryModel.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 (!item || item.telegram_id != ctx.from.id) { + 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('Персонаж не найден!'); + return ctx.reply('Персонаж не найден.'); } + if (item.equipped) { + return ctx.reply(`${item.name} уже снаряжен.`); + } + + // Применяем эффекты предмета + if (item.effectData) { + const resultMessages = processEffects(character, item.effectData, true); + await ctx.reply(resultMessages); + } + + // Снаряжаем предмет + item.equipped = true; + await item.save(); + + 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.reply('Этот предмет не найден в вашем инвентаре.'); + } + + if (!item.equipped) { + return ctx.reply(`${item.name} не снаряжен.`); + } + + if (item.effectData) { + const resultMessages = processEffects(character, item.effectData, false); + await ctx.reply(resultMessages); + } + + item.equipped = false; + await item.save(); + + ctx.reply(`Вы успешно сняли ${item.name}.`); +}); + + +rpg.action('shop', async (ctx) => { const items = await ItemsModel.findAll(); if (items.length === 0) { @@ -925,130 +983,166 @@ rpg.command('shop', async (ctx) => { let message = 'Добро пожаловать в магазин! Здесь вы можете купить предметы:\n\n'; - const buttons = items.map((item) => { - return [Markup.button.callback(`${item.name} - ${item.price}₽`, `buy_item_${item.id}`)]; - }); + // Генерируем кнопки, каждая кнопка будет в отдельной строке + const buttons = items.map((item) => [ + 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 (!item) { + return ctx.reply('Предмет не найден.'); + } + + const character = await CharacterModel.findByPk(ctx.from.id); + + if (!character) { + return ctx.reply('Персонаж не найден.'); } if (character.balance < item.price) { return ctx.reply('У вас недостаточно средств для покупки этого предмета.'); } - // Снимаем деньги с баланса персонажа + // Снимаем деньги с баланса character.balance -= item.price; - // Добавляем предмет в инвентарь (в массив) - character.inventory = [...character.inventory, item]; + // Добавляем предмет в инвентарь + await InventoryModel.create({ + telegram_id: ctx.from.id, + name: item.name, + description: item.description, + effectData: item.effectData, + price: item.price, + rarity: item.rarity, + type: item.type, + duration: item.duration, + equipped: false, + }); await character.save(); - - // Отправляем сообщение об успешной покупке - await ctx.reply(`Вы успешно купили ${item.name} за ${item.price}₽!`); - - // Можно добавить сюда логику для применения эффекта, если он есть + 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; // Предмет должен быть в инвентаре +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 (!this.equippedItems.some((equippedItem) => equippedItem.id === item.id)) { - this.equippedItems.push(item.id); // Добавляем только ID предмета - this.changed('equippedItems', true); // Помечаем, что поле изменилось - await this.save(); // Сохраняем изменения в базе данных + // Проверяем, не снаряжен ли уже этот предмет + 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 }, + }); -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(); // Сохраняем изменения в базе данных + if (!inventoryItem || !inventoryItem.equipped) { + throw new Error('Этот предмет не снаряжен.'); } - return null; + + // Снимаем предмет + 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) => { - // Если предмет снимается (isEquipping = false), эффекты снимаются if (!isEquipping) { + // Снимаем эффекты switch (effect.type) { case 'damage_boost': - character.force -= effect.amount; + character.force = Math.max(0, character.force - effect.amount); + character.save() messages.push(`Ваш урон уменьшен на ${effect.amount}.`); break; case 'max_health_boost': - character.max_hp -= effect.amount; + 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; default: - messages.push('Эффект не распознан при снятии.'); + messages.push('Неизвестный эффект при снятии.'); } } else { - // Применяем эффект при снаряжении + // Применяем эффекты switch (effect.type) { case 'heal': - const maxHp = character.maxHp || 100; - character.hp = Math.min(maxHp, character.hp + effect.amount); + 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; default: - messages.push('Эффект не распознан при надевании.'); + messages.push('Неизвестный эффект при снаряжении.'); } } }); @@ -1056,8 +1150,6 @@ const processEffects = (character, effects, isEquipping) => { return messages.join('\n'); }; - - function generateKeyboard() { const buttonsCount = 10; const buttons = [];