v6
Battle Update
This commit is contained in:
parent
122ba64b5b
commit
a246ee0ca6
252
rpg.js
252
rpg.js
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user