Battle Update
This commit is contained in:
Degradin 2025-01-21 18:38:21 +03:00
parent 122ba64b5b
commit a246ee0ca6

252
rpg.js
View File

@ -9,9 +9,6 @@ const sequelize = require('./db'); // Подключение базы данны
// Подключаем обработчики // Подключаем обработчики
const utils = require('./utils'); const utils = require('./utils');
const handlers = require('./handlers'); const handlers = require('./handlers');
const { keyboard } = require('telegraf/markup');
const { parse } = require('error-stack-parser');
const { get } = require('http');
const { const {
phones, phones,
expToUp, expToUp,
@ -1075,12 +1072,14 @@ rpg.action(/view_item_(\d+)/, async (ctx) => {
// Подготовка кнопок // Подготовка кнопок
const buttons = []; const buttons = [];
if (!item.equipped) { if (!item.equipped) {
buttons.push({ text: `🎯 Использовать ${item.name}`, callback_data: `use_item_${item.id}` }); buttons.push({ text: `🎯 Использовать`, callback_data: `use_item_${item.id}` });
} }
if (item.equipped && item.canBeEquipped) { if (item.equipped && item.canBeEquipped) {
buttons.push({ text: `🚫 Снять ${item.name}`, callback_data: `unequip_item_${item.id}` }); buttons.push({ text: `🚫 Снять`, callback_data: `unequip_item_${item.id}` });
} }
buttons.push({ text: `💰 Продать`, callback_data: `sell_item_${item.id}` });
// Формируем сообщение с эффектами // Формируем сообщение с эффектами
let effectsMessage = '*Эффекты:\n*'; let effectsMessage = '*Эффекты:\n*';
if (item.effectData) { if (item.effectData) {
@ -1100,7 +1099,7 @@ rpg.action(/view_item_(\d+)/, async (ctx) => {
// Отправляем фото и сообщение с кнопками // Отправляем фото и сообщение с кнопками
await ctx.replyWithPhoto({ source: imagePath }, { // Отправка фото из папки await ctx.replyWithPhoto({ source: imagePath }, { // Отправка фото из папки
caption: `🎒 _*${utils.escape(item.name)}*_\n\n*Тип:* ${utils.escape(getItemType(item.type))}\n*Описание:* \n**>${utils.escape(item.description)}\n*Цена:* ${utils.escape(utils.spaces(item.price))}\n*Снаряжаемый:* ${utils.escape(item.canBeEquipped ? 'Да' : 'Нет')}\n${item.effectData ? effectsMessage : ""}`, caption: `🎒 _*${utils.escape(item.name)}*_\n\n*Тип:* ${utils.escape(getItemType(item.type))}\n*Описание:* \n**>${utils.escape(item.description)}\n*Цена:* ${utils.escape(utils.spaces(item.price))}Ð \\(В магазине\\)\n*Снаряжаемый:* ${utils.escape(item.canBeEquipped ? 'Да' : 'Нет')}\n${item.effectData ? effectsMessage : ""}`,
parse_mode: 'MarkdownV2', // Используем MarkdownV2 для форматирования parse_mode: 'MarkdownV2', // Используем MarkdownV2 для форматирования
reply_markup: { reply_markup: {
inline_keyboard: [buttons] // Кнопки передаем как часть структуры inline_keyboard inline_keyboard: [buttons] // Кнопки передаем как часть структуры inline_keyboard
@ -1112,6 +1111,36 @@ rpg.action(/view_item_(\d+)/, async (ctx) => {
} }
}); });
rpg.action(/sell_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10);
const item = await InventoryModel.findByPk(itemId);
if (!item || item.telegram_id != ctx.from.id) {
return ctx.reply('Этот предмет не найден в вашем инвентаре.');
}
const character = await CharacterModel.findByPk(ctx.from.id);
if (!character) {
return ctx.reply('Персонаж не найден.');
}
if (item.equipped) {
return ctx.answerCbQuery(`${item.name} нельзя продать, пока он снаряжен.`);
}
// Продаем предмет (обычно за треть от цены, но в зависимости от интеллекта персонажа, цена может быть выше, вплоть до 100%)
let sellPrice = Math.round(item.price * (0.3 + character.intelligence / 100));
character.dirtymoney += sellPrice;
await InventoryModel.destroy({ where: { id: item.id } });
await character.save();
ctx.editMessageCaption(`Вы продали ${item.name} за ${utils.spaces(sellPrice)}Ð`);
logs(ctx, "Продажа предмета", { item, sellPrice });
});
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 item = await InventoryModel.findByPk(itemId); const item = await InventoryModel.findByPk(itemId);
@ -1185,38 +1214,153 @@ rpg.action(/unequip_item_(\d+)/, async (ctx) => {
}); });
rpg.action('shop', async (ctx) => { rpg.action('shop', async (ctx) => {
// Получаем текущую запись мира // Выводим красиво кнопки разделов магазина "Оружие", "Броня", "Аксессуары" и т.д.
await ctx.editMessageText('🛒 Магазин', Markup.inlineKeyboard([
[{ text: 'Оружие', callback_data: 'shop_weapon' }],
[{ text: 'Броня', callback_data: 'shop_armor' }],
[{ text: 'Аксессуары', callback_data: 'shop_accessory' }],
[{ text: 'Расходники', callback_data: 'shop_consumable' }],
[{ text: 'Импланты', callback_data: 'shop_implant' }],
[{ text: '🔙 В меню', callback_data: 'crime_menu' }],
]));
});
rpg.action('shop_weapon', async (ctx) => {
const items = await ItemsModel.findAll({ where: { type: 'weapon' } });
const world = await WorldModel.findOne({ where: { id: 1 } }); const world = await WorldModel.findOne({ where: { id: 1 } });
if (!world) {
return ctx.reply('Магазин недоступен.');
}
// Получаем ID предметов, доступных в магазине
const { itemsInCrimeShop } = world;
if (!itemsInCrimeShop || itemsInCrimeShop.length === 0) {
return ctx.reply('Магазин пуст!');
}
// Загружаем только те предметы, ID которых есть в массиве
const items = await ItemsModel.findAll({ where: { id: itemsInCrimeShop } });
if (items.length === 0) { if (items.length === 0) {
return ctx.reply('Магазин пуст!'); return ctx.editMessageText('В магазине нет оружия.');
} }
let message = 'Добро пожаловать в магазин! Здесь вы можете купить предметы:\n\n'; // Проверяем есть ли найденные предметы (id) в world.itemsInCrimeShop
let itemsInCrimeShop = items.filter((item) => world.itemsInCrimeShop.includes(item.id));
// Генерируем кнопки, каждая кнопка будет в отдельной строке if (itemsInCrimeShop.length === 0) {
const buttons = items.map((item) => [ return ctx.editMessageText('В магазине нет оружия.');
Markup.button.callback(`${item.name} - ${item.price}`, `buy_item_${item.id}`) }
]);
buttons.push([Markup.button.callback('🔙 В меню', 'crime_menu')]);
// Отправляем сообщение с клавиатурой let message = '*🛒 Оружие в магазине:*\n\n'
await ctx.editMessageText(message, Markup.inlineKeyboard(buttons)); itemsInCrimeShop.forEach((item) => {
message += `🔹 ${item.name} - ${item.price}\n`;
}
);
await ctx.editMessageText(message, Markup.inlineKeyboard([
itemsInCrimeShop.map((item) => Markup.button.callback(`Купить ${item.name}`, `buy_item_${item.id}`)),
[{ text: '🔙 В меню', callback_data: 'shop' }]
]));
}); });
rpg.action('shop_armor', async (ctx) => {
const items = await ItemsModel.findAll({ where: { type: 'armor' } });
const world = await WorldModel.findOne({ where: { id: 1 } });
if (items.length === 0) {
return ctx.editMessageText('В магазине нет брони.');
}
// Проверяем есть ли найденные предметы (id) в world.itemsInCrimeShop
let itemsInCrimeShop = items.filter((item) => world.itemsInCrimeShop.includes(item.id));
if (itemsInCrimeShop.length === 0) {
return ctx.editMessageText('В магазине нет брони.');
}
let message = '*🛒 Броня в магазине:*\n\n'
itemsInCrimeShop.forEach((item) => {
message += `🔹 ${item.name} - ${item.price}\n`;
}
);
await ctx.editMessageText(message, Markup.inlineKeyboard([
itemsInCrimeShop.map((item) => Markup.button.callback(`Купить ${item.name}`, `buy_item_${item.id}`)),
[{ text: '🔙 В меню', callback_data: 'shop' }]
]));
});
rpg.action('shop_accessory', async (ctx) => {
const items = await ItemsModel.findAll({ where: { type: 'accessory' } });
const world = await WorldModel.findOne({ where: { id: 1 } });
if (items.length === 0) {
return ctx.editMessageText('В магазине нет аксессуаров.');
}
// Проверяем есть ли найденные предметы (id) в world.itemsInCrimeShop
let itemsInCrimeShop = items.filter((item) => world.itemsInCrimeShop.includes(item.id));
if (itemsInCrimeShop.length === 0) {
return ctx.editMessageText('В магазине нет аксессуаров.');
}
let message = '*🛒 Аксессуары в магазине:*\n\n'
itemsInCrimeShop.forEach((item) => {
message += `🔹 ${item.name} - ${item.price}\n`;
}
);
await ctx.editMessageText(message, Markup.inlineKeyboard([
itemsInCrimeShop.map((item) => Markup.button.callback(`Купить ${item.name}`, `buy_item_${item.id}`)),
[{ text: '🔙 В меню', callback_data: 'shop' }]
]));
});
rpg.action('shop_consumable', async (ctx) => {
const items = await ItemsModel.findAll({ where: { type: 'consumable' } });
const world = await WorldModel.findOne({ where: { id: 1 } });
if (items.length === 0) {
return ctx.editMessageText('В магазине нет расходников.');
}
// Проверяем есть ли найденные предметы (id) в world.itemsInCrimeShop
let itemsInCrimeShop = items.filter((item) => world.itemsInCrimeShop.includes(item.id));
if (itemsInCrimeShop.length === 0) {
return ctx.editMessageText('В магазине нет расходников.');
}
let message = '*🛒 Расходники в магазине:*\n\n'
itemsInCrimeShop.forEach((item) => {
message += `🔹 ${item.name} - ${item.price}\n`;
}
);
await ctx.editMessageText(message, Markup.inlineKeyboard([
itemsInCrimeShop.map((item) => Markup.button.callback(`Купить ${item.name}`, `buy_item_${item.id}`)),
[{ text: '🔙 В меню', callback_data: 'shop' }]
]))
});
rpg.action('shop_implant', async (ctx) => {
const items = await ItemsModel.findAll({ where: { type: 'implant' } });
const world = await WorldModel.findOne({ where: { id: 1 } });
if (items.length === 0) {
return ctx.editMessageText('В магазине нет имплантов.');
}
// Проверяем есть ли найденные предметы (id) в world.itemsInCrimeShop
let itemsInCrimeShop = items.filter((item) => world.itemsInCrimeShop.includes(item.id));
if (itemsInCrimeShop.length === 0) {
return ctx.editMessageText('В магазине нет имплантов.');
}
let message = '*🛒 Импланты в магазине:*\n\n'
itemsInCrimeShop.forEach((item) => {
message += `🔹 ${item.name} - ${item.price}\n`;
}
);
await ctx.editMessageText(message, Markup.inlineKeyboard([
itemsInCrimeShop.map((item) => Markup.button.callback(`Купить ${item.name}`, `buy_item_${item.id}`)),
[{ text: '🔙 В меню', callback_data: 'shop' }]
]));
});
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 item = await ItemsModel.findByPk(itemId); const item = await ItemsModel.findByPk(itemId);
@ -1369,6 +1513,9 @@ const processEffects = (character, effects, isEquipping) => {
case 'max_health_boost': case 'max_health_boost':
character.max_hp = Math.max(1, character.max_hp - effect.amount); character.max_hp = Math.max(1, character.max_hp - effect.amount);
if (character.hp > character.max_hp) {
character.hp = character.max_hp;
}
character.save() character.save()
messages.push(`Ваше максимальное здоровье уменьшено на ${effect.amount}.`); messages.push(`Ваше максимальное здоровье уменьшено на ${effect.amount}.`);
break; break;
@ -1441,6 +1588,7 @@ const processEffects = (character, effects, isEquipping) => {
case 'max_health_boost': case 'max_health_boost':
character.max_hp += effect.amount; character.max_hp += effect.amount;
character.hp += effect.amount;
character.save() character.save()
messages.push(`Ваше максимальное здоровье увеличено на ${effect.amount}.`); messages.push(`Ваше максимальное здоровье увеличено на ${effect.amount}.`);
break; break;
@ -1614,34 +1762,34 @@ function removeButton(ctx, buttonId) {
// Восстановление здоровья (HP) // Восстановление здоровья (HP)
async function recoverHealth() { async function recoverHealth() {
const characters = await CharacterModel.findAll({ const characters = await CharacterModel.findAll()
where: { // Восстанавливаем только тем, у кого HP меньше максимума
hp: {
[Op.lt]: 100, // Восстанавливаем только тем, у кого HP меньше 100
},
},
});
for (const character of characters) { for (const character of characters) {
const recoveryRate = character.resilience; // Восстановление 10 HP за интервал if (character.hp >= character.max_hp) {
character.hp = Math.min(character.hp + recoveryRate, 100); // Не превышаем максимум continue; // Пропускаем, если здоровье полное
}
let recoveryRate = character.resilience; // Восстановление за интервал
if (recoveryRate <= 0) {
recoveryRate = 1; // Минимум 1 HP
}
character.hp = Math.min(character.hp + recoveryRate, character.max_hp); // Не превышаем максимум
await character.save(); await character.save();
} }
} }
// Восстановление выносливости (стамины) // Восстановление выносливости (стамины)
async function recoverStamina() { async function recoverStamina() {
const characters = await CharacterModel.findAll({ const characters = await CharacterModel.findAll()
where: { // Восстанавливаем только тем, у кого стамина меньше максимума
stamina: {
[Op.lt]: 100, // Восстанавливаем только тем, у кого стамина меньше 100
},
},
});
for (const character of characters) { for (const character of characters) {
const recoveryRate = character.endurance; // Восстановление 5 стамины за интервал if (character.stamina >= character.max_stamina) {
character.stamina = Math.min(character.stamina + recoveryRate, 100); // Не превышаем максимум continue; // Пропускаем, если стамина полная
}
let recoveryRate = character.endurance; // Восстановление 5 стамины за интервал
if (recoveryRate <= 0) {
recoveryRate = 1; // Минимум 1 стамина
}
character.stamina = Math.min(character.stamina + recoveryRate, character.max_stamina); // Не превышаем максимум
await character.save(); await character.save();
} }
} }
@ -1725,7 +1873,7 @@ async function Exp(ctx, character, experience) {
// Периодическое выполнение задач // Периодическое выполнение задач
function startRecoveryIntervals() { function startRecoveryIntervals() {
const interval = 60000; // 1 мин Интервал в миллисекундах (например, 1 минута) const interval = 1000; // 1 мин Интервал в миллисекундах (например, 1 минута)
setInterval(recoverHealth, interval); setInterval(recoverHealth, interval);
setInterval(recoverStamina, interval); setInterval(recoverStamina, interval);
} }
@ -2175,7 +2323,7 @@ rpg.action(/hit_\d+/, async (ctx) => {
battle.status = "completed"; battle.status = "completed";
await battle.save(); await battle.save();
logs(ctx, "Победа персонажа", { enemy, battle }); logs(ctx, "Победа персонажа", { enemy, battle });
Exp(ctx, character, enemy.level * 10) Exp(ctx, character, enemy.level * 5)
character.enemiesKilled += 1; character.enemiesKilled += 1;
await character.save(); await character.save();
let droppedItems = await dropItem(character, enemy.id); let droppedItems = await dropItem(character, enemy.id);
@ -2435,7 +2583,7 @@ rpg.action(/critical_\d+/, async (ctx) => {
if (battle.enemy_hp <= 0) { if (battle.enemy_hp <= 0) {
battle.status = "completed"; battle.status = "completed";
await battle.save(); await battle.save();
Exp(ctx, character, enemy.level * 11) Exp(ctx, character, enemy.level * 6)
character.enemiesKilled += 1; character.enemiesKilled += 1;
await character.save(); await character.save();
let droppedItems = await dropItem(character, enemy.id); let droppedItems = await dropItem(character, enemy.id);