Crime update
This commit is contained in:
Degradin 2025-01-10 00:54:54 +03:00
parent 4f97a3dba1
commit 125b782a64
6 changed files with 346 additions and 235 deletions

7
bot.js
View File

@ -206,10 +206,11 @@ bot.command('start', async (ctx) => {
return await ctx.reply('Главное меню', Markup return await ctx.reply('Главное меню', Markup
.keyboard([ .keyboard([
['😎 Профиль'], // Row1 with 2 buttons ['😎 Профиль'], // Row1 with 2 buttons
['🗄️ Работать', '🌐 Организация', '🎁 Бонус', '🏯 Казино'], // Row2 with 2 buttons ['🗄️ Работать', '🌐 Организация', '🏗️ Предприятия', '🏯 Казино'], // Row2 with 2 buttons
['🏗️ Предприятия'], ['CampFireGG.Crime'],
['🎁 Бонус'],
['📦 Контейнеры'], ['📦 Контейнеры'],
['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'] // Row3 with 3 buttons ['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'],
]) ])
.resize() .resize()
) )

View File

@ -10,14 +10,14 @@ module.exports = async (ctx) => {
let user = await UserModel.findByPk(ctx.from.id) let user = await UserModel.findByPk(ctx.from.id)
const buttons = [] const buttons = []
if (user.status == 'admin') { if (user.status == 'admin') {
buttons.push("CampFireGG.Crime"); buttons.push("Топ");
} }
return await ctx.reply('Main Menu', Markup return await ctx.reply('Main Menu', Markup
.keyboard([ .keyboard([
['😎 Профиль'], // Row1 with 2 buttons ['😎 Профиль'], // Row1 with 2 buttons
['🗄️ Работать', '🌐 Организация', '🎁 Бонус', '🏯 Казино'], // Row2 with 2 buttons ['🗄️ Работать', '🌐 Организация', '🏗️ Предприятия', '🏯 Казино'], // Row2 with 2 buttons
['🏗️ Предприятия'], ['CampFireGG.Crime'],
['🎁 Бонус'],
['📦 Контейнеры'], ['📦 Контейнеры'],
['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'], ['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'],
buttons // Row3 with 3 buttons buttons // Row3 with 3 buttons

View File

@ -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 = { module.exports = {
weaponshop : require('../json/weaponshop.json'), weaponshop : require('../json/weaponshop.json'),
slots : require('../json/slots.json'), slots : require('../json/slots.json'),
@ -10,6 +17,7 @@ module.exports = {
equipment : require('../presets/equipment.json'), equipment : require('../presets/equipment.json'),
UserModel : require('../models/user.model'), UserModel : require('../models/user.model'),
CharacterModel : require('../models/character.model'), CharacterModel : require('../models/character.model'),
InventoryModel : require('../models/inventory.model'),
ItemsModel : require('../models/items.model'), ItemsModel : require('../models/items.model'),
StolenCardsModel : require('../models/stolencards.model'), StolenCardsModel : require('../models/stolencards.model'),
WorldModel : require('../models/world.model'), WorldModel : require('../models/world.model'),

View File

@ -1,80 +1,80 @@
const sequelize = require('../db');
const { DataTypes } = require('sequelize'); const { DataTypes } = require('sequelize');
const sequelize = require('../db');
const Character = sequelize.define('character', { const Character = sequelize.define('character', {
telegram_id: { telegram_id: {
type: DataTypes.BIGINT, type: DataTypes.BIGINT,
primaryKey: true, primaryKey: true,
unique: true unique: true,
}, },
username: { username: {
type: DataTypes.STRING type: DataTypes.STRING
}, },
name: { name: {
type: DataTypes.STRING type: DataTypes.STRING
}, },
level: { level: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 1 defaultValue: 1
}, },
exp: { exp: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 0 defaultValue: 0
}, },
hp: { hp: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 100 defaultValue: 100
}, },
max_hp: { max_hp: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 100 defaultValue: 100
}, },
armor: { armor: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 0 defaultValue: 0
}, },
stamina: { stamina: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 100 defaultValue: 100
}, },
max_stamina: { max_stamina: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 100 defaultValue: 100
}, },
force: { force: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 1 defaultValue: 1
}, },
intelligence: { intelligence: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 1 defaultValue: 1
}, },
resilience: { resilience: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 1 defaultValue: 1
}, },
endurance: { endurance: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 1 defaultValue: 1
}, },
dirtymoney: { dirtymoney: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 0 defaultValue: 0
}, },
stealedcards: { stealedcards: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 0 defaultValue: 0
}, },
shoprobcd: { shoprobcd: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 0 defaultValue: 0
}, },
pocketstealcd: { pocketstealcd: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: 0 defaultValue: 0
}, },
activeEffects: { type: DataTypes.JSON, allowNull: true, defaultValue: [] }, activeEffects: { type: DataTypes.JSON, allowNull: true, defaultValue: [] },
equippedItems: { type: DataTypes.ARRAY(DataTypes.INTEGER), allowNull: true, defaultValue: [] }, equippedItems: { type: DataTypes.ARRAY(DataTypes.INTEGER), allowNull: true, defaultValue: [] },
}); });
module.exports = Character; module.exports = Character;

View File

@ -2,9 +2,17 @@ const { DataTypes } = require('sequelize');
const sequelize = require('../db'); const sequelize = require('../db');
const Inventory = sequelize.define('inventory', { const Inventory = sequelize.define('inventory', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
telegram_id: { telegram_id: {
type: DataTypes.BIGINT, type: DataTypes.BIGINT, // Используем другой внешний ключ
primaryKey: true references: {
model: 'characters', // Указываем правильное имя модели
key: 'telegram_id', // Внешний ключ указывает на telegram_id в модели Character
},
}, },
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
@ -34,8 +42,10 @@ const Inventory = sequelize.define('inventory', {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: true allowNull: true
}, // Длительность эффекта в секундах }, // Длительность эффекта в секундах
equipped: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
}); });
module.exports = Inventory; module.exports = Inventory;

390
rpg.js
View File

@ -12,6 +12,7 @@ const {
expToUp, expToUp,
UserModel, UserModel,
CharacterModel, CharacterModel,
InventoryModel,
ItemsModel, ItemsModel,
StolenCardsModel, StolenCardsModel,
WorldModel, WorldModel,
@ -28,6 +29,32 @@ const {
} = global.config } = global.config
const rpg = new Composer(); 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) => { rpg.hears('RPG', async (ctx) => {
let message = `Меню:\n`; let message = `Меню:\n`;
@ -61,7 +88,7 @@ rpg.action('rpg_profile', async (ctx) => {
🔋 Выносливость (E): ${character.endurance} 🔋 Выносливость (E): ${character.endurance}
🔥 Стамина: ${character.stamina}/${character.max_stamina} 🔥 Стамина: ${character.stamina}/${character.max_stamina}
💰 Грязные деньги: ${utils.spaces(character.dirtymoney)} 💰 Грязные деньги: ${utils.spaces(character.dirtymoney)}
🃏 Карточки: ${stolenCards.length} 🃏 Карты: ${stolenCards.length}
`; `;
// Отправляем сообщение // Отправляем сообщение
@ -144,8 +171,9 @@ rpg.hears('CampFireGG.Crime', async (ctx) => {
Markup.inlineKeyboard([ Markup.inlineKeyboard([
[Markup.button.callback('💼 Задачи', 'crime_missions')], [Markup.button.callback('💼 Задачи', 'crime_missions')],
[Markup.button.callback('📊 Профиль', 'rpg_profile')], [Markup.button.callback('📊 Профиль', 'rpg_profile')],
//[Markup.button.callback('💳 Карточки', 'view_cards')], [Markup.button.callback('💳 Карточки', 'view_cards')],
[Markup.button.callback('💰 Инвентарь', 'inventory')], [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(); await character.save();
// Если товар электронный, начисляем процент от стоимости на счет // Если товар электронный, начисляем процент от стоимости на счет
@ -337,16 +365,26 @@ rpg.action(/purchase_fail_/, async (ctx) => {
// Обработка попытки взлома карточки // Обработка попытки взлома карточки
rpg.action(/brutecard_/, async (ctx) => { rpg.action(/brutecard_/, async (ctx) => {
const cardId = ctx.match.input.split('_')[1]; // Получаем ID карточки из callback_data const cardId = ctx.match.input.split('_')[1]; // Получаем ID карточки из callback_data
const card = await StolenCardsModel.findByPk(cardId); // Ищем карточку в базе данных const card = await StolenCardsModel.findByPk(cardId); // Ищем карточку в базе данных
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } }); // Загружаем предметы из инвентаря
if (!card) { if (!card) {
return ctx.answerCbQuery('Карточка не найдена.'); return ctx.answerCbQuery('Карточка не найдена.');
} }
const buttonsCount = 10; // Количество кнопок // Проверяем наличие "Эмулятора картридера" в инвентаре
const winButton = utils.rand(1, buttonsCount); // Выбираем случайную кнопку для успешного пина const emulator = inventory.find((item) => item.name === 'Эмулятор картридера');
const maxAttempts = 3; // Максимальное количество попыток 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]) { if (!attempts[ctx.from.id]) {
@ -373,16 +411,30 @@ rpg.action(/brutecard_/, async (ctx) => {
// Сортируем кнопки случайным образом // Сортируем кнопки случайным образом
const keyboard = Markup.inlineKeyboard( 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( 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 keyboard
); );
}); });
// Обработка неудачной попытки взлома // Обработка неудачной попытки взлома
rpg.action(/brute_fail_/, async (ctx) => { rpg.action(/brute_fail_/, async (ctx) => {
const cardId = ctx.match.input.split('_')[2]; const cardId = ctx.match.input.split('_')[2];
@ -430,7 +482,17 @@ rpg.action(/brute_fail_/, async (ctx) => {
// Обновляем сообщение с клавиатурой // Обновляем сообщение с клавиатурой
await ctx.editMessageText( 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 keyboard
); );
}); });
@ -458,7 +520,17 @@ rpg.action(/brute_success_/, async (ctx) => {
// Отправляем сообщение о выигрыше // Отправляем сообщение о выигрыше
await ctx.editMessageText( 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('Персонаж не найден!'); 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) {
if (inventory.length === 0 && equippedItems.length === 0) {
return ctx.reply('Ваш инвентарь пуст.'); return ctx.reply('Ваш инвентарь пуст.');
} }
let message = '*Ваш инвентарь:*\n\n'; let message = '*Ваш инвентарь:*\n\n';
// Снаряженные предметы // Группируем предметы по их состоянию (снаряженные/обычные)
const equippedItems = inventory.filter((item) => item.equipped);
const unequippedItems = inventory.filter((item) => !item.equipped);
if (equippedItems.length > 0) { if (equippedItems.length > 0) {
message += '🛡️ *Снаряженные предметы:*\n'; message += '🛡️ *Снаряженные предметы:*\n';
for (const item of equippedItems) { equippedItems.forEach((item) => {
if (item) { message += `- ${item.name} (${item.type})\n`;
message += `- ${item.name} (${item.type})\n`; });
}
}
message += '\n'; message += '\n';
} }
// Предметы в инвентаре if (unequippedItems.length > 0) {
if (inventory.length > 0) {
message += '🎒 *Предметы в инвентаре:*\n'; message += '🎒 *Предметы в инвентаре:*\n';
for (const item of inventory) { unequippedItems.forEach((item) => {
if (item) { message += `- ${item.name} (${item.type})\n`;
message += `- ${item.name} (${item.type})\n`; });
}
}
message += '\n'; message += '\n';
} }
// Кнопки для взаимодействия // Кнопки для взаимодействия
const buttons = []; const buttons = [
...unequippedItems.map((item) =>
for (const item of inventory) { Markup.button.callback(`🎯 Использовать ${item.name}`, `use_item_${item.id}`)
if (item) { ),
buttons.push( ...equippedItems.map((item) =>
Markup.button.callback(`🎯 Использовать ${item.name}`, `use_item_${item.id}`) Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_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 })); await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
} catch (error) { } catch (error) {
@ -857,66 +917,64 @@ rpg.action('inventory', async (ctx) => {
} }
}); });
rpg.action(/use_item_(\d+)/, async (ctx) => { rpg.action(/use_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10); const itemId = parseInt(ctx.match[1], 10);
const character = await CharacterModel.findByPk(ctx.from.id); const item = await InventoryModel.findByPk(itemId);
const item = await ItemsModel.findByPk(itemId);
const inventory = character.inventory || []; if (!item || item.telegram_id != ctx.from.id) {
const isEquipped = character.equippedItems.some((equippedItem) => equippedItem.id === itemId); // Проверяем, снаряжен ли предмет return ctx.reply('Этот предмет не найден в вашем инвентаре.');
// Проверка наличия предмета в инвентаре
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); const character = await CharacterModel.findByPk(ctx.from.id);
if (!character) { 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(); const items = await ItemsModel.findAll();
if (items.length === 0) { if (items.length === 0) {
@ -925,130 +983,166 @@ rpg.command('shop', async (ctx) => {
let message = 'Добро пожаловать в магазин! Здесь вы можете купить предметы:\n\n'; 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)); await ctx.reply(message, Markup.inlineKeyboard(buttons));
}); });
rpg.action(/buy_item_(\d+)/, async (ctx) => { rpg.action(/buy_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10); const itemId = parseInt(ctx.match[1], 10);
const character = await CharacterModel.findByPk(ctx.from.id);
const item = await ItemsModel.findByPk(itemId); const item = await ItemsModel.findByPk(itemId);
if (!character || !item) { if (!item) {
return ctx.reply('Ошибка: Персонаж или предмет не найдены.'); return ctx.reply('Предмет не найден.');
}
const character = await CharacterModel.findByPk(ctx.from.id);
if (!character) {
return ctx.reply('Персонаж не найден.');
} }
if (character.balance < item.price) { if (character.balance < item.price) {
return ctx.reply('У вас недостаточно средств для покупки этого предмета.'); return ctx.reply('У вас недостаточно средств для покупки этого предмета.');
} }
// Снимаем деньги с баланса персонажа // Снимаем деньги с баланса
character.balance -= item.price; 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 character.save();
ctx.reply(`Вы успешно купили ${item.name} за ${item.price}₽!`);
// Отправляем сообщение об успешной покупке
await ctx.reply(`Вы успешно купили ${item.name} за ${item.price}₽!`);
// Можно добавить сюда логику для применения эффекта, если он есть
}); });
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
CharacterModel.prototype.addEquippedItem = async function(item) { CharacterModel.prototype.addEquippedItem = async function (item) {
// Проверяем, есть ли уже предмет в инвентаре // Проверяем, находится ли предмет в инвентаре персонажа
const isInInventory = this.inventory.some((invItem) => invItem.id === item.id); const inventoryItem = await InventoryModel.findOne({
if (!isInInventory) { where: { telegram_id: this.telegram_id, id: item.id },
return; // Предмет должен быть в инвентаре });
if (!inventoryItem) {
throw new Error('Предмет не найден в вашем инвентаре.');
} }
// Проверяем, есть ли уже этот предмет в снаряженных // Проверяем, не снаряжен ли уже этот предмет
if (!this.equippedItems.some((equippedItem) => equippedItem.id === item.id)) { if (inventoryItem.equipped) {
this.equippedItems.push(item.id); // Добавляем только ID предмета throw new Error('Этот предмет уже снаряжен.');
this.changed('equippedItems', true); // Помечаем, что поле изменилось
await this.save(); // Сохраняем изменения в базе данных
} }
// Снаряжаем предмет
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 (!inventoryItem || !inventoryItem.equipped) {
// Проверяем, снаряжен ли предмет throw new Error('Этот предмет не снаряжен.');
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;
// Снимаем предмет
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) => { const processEffects = (character, effects, isEquipping) => {
let messages = []; let messages = [];
effects.forEach((effect) => { effects.forEach((effect) => {
// Если предмет снимается (isEquipping = false), эффекты снимаются
if (!isEquipping) { if (!isEquipping) {
// Снимаем эффекты
switch (effect.type) { switch (effect.type) {
case 'damage_boost': case 'damage_boost':
character.force -= effect.amount; character.force = Math.max(0, character.force - effect.amount);
character.save()
messages.push(`Ваш урон уменьшен на ${effect.amount}.`); messages.push(`Ваш урон уменьшен на ${effect.amount}.`);
break; break;
case 'max_health_boost': 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}.`); messages.push(`Ваше максимальное здоровье уменьшено на ${effect.amount}.`);
break; break;
case 'stamina_penalty': case 'stamina_penalty':
character.max_stamina += effect.amount; character.max_stamina += effect.amount;
character.save()
messages.push(`Ваша выносливость увеличена на ${effect.amount}.`); messages.push(`Ваша выносливость увеличена на ${effect.amount}.`);
break; break;
default: default:
messages.push('Эффект не распознан при снятии.'); messages.push('Неизвестный эффект при снятии.');
} }
} else { } else {
// Применяем эффект при снаряжении // Применяем эффекты
switch (effect.type) { switch (effect.type) {
case 'heal': case 'heal':
const maxHp = character.maxHp || 100; character.hp = Math.min(character.max_hp, character.hp + effect.amount);
character.hp = Math.min(maxHp, character.hp + effect.amount); character.save()
messages.push(`Вы восстановили ${effect.amount} HP.`); messages.push(`Вы восстановили ${effect.amount} HP.`);
break; break;
case 'damage_boost': case 'damage_boost':
character.force += effect.amount; character.force += effect.amount;
character.save()
messages.push(`Ваш урон увеличен на ${effect.amount}.`); messages.push(`Ваш урон увеличен на ${effect.amount}.`);
break; break;
case 'max_health_boost': case 'max_health_boost':
character.max_hp += effect.amount; character.max_hp += effect.amount;
character.save()
messages.push(`Ваше максимальное здоровье увеличено на ${effect.amount}.`); messages.push(`Ваше максимальное здоровье увеличено на ${effect.amount}.`);
break; break;
case 'stamina_penalty': case 'stamina_penalty':
character.max_stamina -= effect.amount; character.max_stamina -= effect.amount;
character.save()
messages.push(`Ваша выносливость уменьшена на ${effect.amount}.`); messages.push(`Ваша выносливость уменьшена на ${effect.amount}.`);
break; break;
default: default:
messages.push('Эффект не распознан при надевании.'); messages.push('Неизвестный эффект при снаряжении.');
} }
} }
}); });
@ -1056,8 +1150,6 @@ const processEffects = (character, effects, isEquipping) => {
return messages.join('\n'); return messages.join('\n');
}; };
function generateKeyboard() { function generateKeyboard() {
const buttonsCount = 10; const buttonsCount = 10;
const buttons = []; const buttons = [];