v5.5
Battle Update Prepare
This commit is contained in:
parent
fb757f9f0a
commit
b4087cf26c
@ -19,6 +19,9 @@ module.exports = {
|
||||
CharacterModel : require('../models/character.model'),
|
||||
InventoryModel : require('../models/inventory.model'),
|
||||
ItemsModel : require('../models/items.model'),
|
||||
Enemy : require('../models/enemy.model'),
|
||||
Location : require('../models/location.model'),
|
||||
Battle : require('../models/battle.model'),
|
||||
StolenCardsModel : require('../models/stolencards.model'),
|
||||
WorldModel : require('../models/world.model'),
|
||||
JobModel : require('../models/job.model'),
|
||||
|
33
models/battle.model.js
Normal file
33
models/battle.model.js
Normal file
@ -0,0 +1,33 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../db');
|
||||
|
||||
const Battle = sequelize.define('battle', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
enemy: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
location: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
character: {
|
||||
type: DataTypes.BIGINT,
|
||||
allowNull: true,
|
||||
},
|
||||
enemy_hp: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "inactive"
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = Battle;
|
40
models/enemy.model.js
Normal file
40
models/enemy.model.js
Normal file
@ -0,0 +1,40 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../db');
|
||||
|
||||
const Enemy = sequelize.define('enemy', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
},
|
||||
level: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
hp: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true
|
||||
},
|
||||
damage: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
loot: {
|
||||
type: DataTypes.ARRAY(DataTypes.INTEGER),
|
||||
allowNull: true, defaultValue: []
|
||||
},
|
||||
rarity: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = Enemy;
|
38
models/location.model.js
Normal file
38
models/location.model.js
Normal file
@ -0,0 +1,38 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize = require('../db');
|
||||
|
||||
const Location = sequelize.define('location', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
},
|
||||
enemies: {
|
||||
type: DataTypes.ARRAY(DataTypes.INTEGER),
|
||||
allowNull: true,
|
||||
defaultValue: []
|
||||
},
|
||||
level: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
loot: {
|
||||
type: DataTypes.ARRAY(DataTypes.INTEGER),
|
||||
allowNull: true,
|
||||
defaultValue: []
|
||||
},
|
||||
rarity: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = Location;
|
470
rpg.js
470
rpg.js
@ -14,6 +14,9 @@ const {
|
||||
CharacterModel,
|
||||
InventoryModel,
|
||||
ItemsModel,
|
||||
Enemy,
|
||||
Location,
|
||||
Battle,
|
||||
StolenCardsModel,
|
||||
WorldModel,
|
||||
PropertyModel,
|
||||
@ -1502,13 +1505,480 @@ startRecoveryIntervals()
|
||||
|
||||
|
||||
|
||||
const fillEnemies = async () => {
|
||||
const enemies = [
|
||||
{ name: "Бандит", description: "Обычный бандит с ножом", level: 1, hp: 50, damage: 10, loot: [1, 2], rarity: 1 },
|
||||
{ name: "Вор", description: "Мелкий воришка", level: 1, hp: 30, damage: 5, loot: [3], rarity: 1 },
|
||||
{ name: "Собака", description: "Голодная дворняга", level: 1, hp: 40, damage: 8, loot: [], rarity: 2 },
|
||||
{ name: "Амбал-бандит", description: "Сильный и опасный бандит", level: 3, hp: 120, damage: 25, loot: [4, 5], rarity: 3 },
|
||||
];
|
||||
|
||||
for (const enemy of enemies) {
|
||||
await Enemy.create(enemy);
|
||||
}
|
||||
console.log("Enemies filled.");
|
||||
};
|
||||
|
||||
const fillLocations = async () => {
|
||||
const locations = [
|
||||
{
|
||||
name: "Заброшенный склад",
|
||||
description: "Темный склад с кучей мусора.",
|
||||
enemies: [1, 2, 3],
|
||||
level: 1,
|
||||
loot: [6, 7],
|
||||
rarity: 1
|
||||
},
|
||||
{
|
||||
name: "Лесопосадка",
|
||||
description: "Густой лес с опасными тропами.",
|
||||
enemies: [2, 3, 4],
|
||||
level: 2,
|
||||
loot: [8, 9],
|
||||
rarity: 2
|
||||
},
|
||||
];
|
||||
|
||||
for (const location of locations) {
|
||||
await Location.create(location);
|
||||
}
|
||||
console.log("Locations filled.");
|
||||
};
|
||||
|
||||
const generateBattles = async () => {
|
||||
const locations = await Location.findAll();
|
||||
|
||||
for (const location of locations) {
|
||||
const enemies = location.enemies;
|
||||
const generatedEnemies = enemies.map((enemyId) => {
|
||||
const rarity = Math.random();
|
||||
return rarity < 0.7 ? enemyId : null; // Шанс 70% для обычных врагов
|
||||
}).filter(Boolean);
|
||||
|
||||
for (const enemyId of generatedEnemies) {
|
||||
const enemy = await Enemy.findByPk(enemyId);
|
||||
if (!enemy) continue;
|
||||
|
||||
await Battle.create({
|
||||
enemy: enemy.id,
|
||||
location: location.id,
|
||||
character: null,
|
||||
enemy_hp: enemy.hp,
|
||||
status: "inactive",
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log("Battles generated.");
|
||||
};
|
||||
|
||||
rpg.command("locations", async (ctx) => {
|
||||
const locations = await Location.findAll();
|
||||
if (!locations.length) {
|
||||
return ctx.reply("Нет доступных локаций для исследования.");
|
||||
}
|
||||
|
||||
const locationButtons = locations.map((location) => ({
|
||||
text: location.name,
|
||||
callback_data: `viewlocation_${location.id}`,
|
||||
}));
|
||||
|
||||
const keyboard = Markup.inlineKeyboard(
|
||||
locationButtons.map((button) => [button]) // Одна кнопка на строку
|
||||
);
|
||||
|
||||
await ctx.reply("Выберите локацию для исследования:", keyboard);
|
||||
});
|
||||
|
||||
rpg.action(/viewlocation_\d+/, async (ctx) => {
|
||||
const locationId = ctx.match[0].split("_")[1];
|
||||
const location = await Location.findByPk(locationId);
|
||||
|
||||
if (!location) {
|
||||
return ctx.reply("Локация не найдена.");
|
||||
}
|
||||
|
||||
const lootItems = location.loot.length
|
||||
? location.loot.map((id) => `#${id}`).join(", ")
|
||||
: "Нет";
|
||||
|
||||
const description = `🏞️ ${location.name}\n\n${location.description}\n\nУровень: ${location.level}\nДобыча: ${lootItems}\n`;
|
||||
const keyboard = Markup.inlineKeyboard([
|
||||
[{ text: "Исследовать", callback_data: `explore_${location.id}` }],
|
||||
[{ text: "Охота", callback_data: `hunt_location_${location.id}` }],
|
||||
]);
|
||||
|
||||
await ctx.reply(description, keyboard);
|
||||
});
|
||||
|
||||
rpg.action(/hunt_location_\d+/, async (ctx) => {
|
||||
const locationId = ctx.match[0].split('_')[2]; // Получаем ID локации
|
||||
const location = await Location.findByPk(locationId);
|
||||
|
||||
if (!location) {
|
||||
return ctx.reply("Локация не найдена.");
|
||||
}
|
||||
|
||||
const enemyIds = location.enemies || [];
|
||||
if (enemyIds.length === 0) {
|
||||
return ctx.reply("В этой локации сейчас нет врагов. Попробуйте позже.");
|
||||
}
|
||||
|
||||
const activeBattles = await Battle.findAll({
|
||||
where: { location: location.id, status: 'inactive' },
|
||||
});
|
||||
|
||||
if (activeBattles.length === 0) {
|
||||
return ctx.reply("В этой локации сейчас нет активных врагов. Попробуйте позже.");
|
||||
}
|
||||
|
||||
const activeEnemyIds = activeBattles.map((battle) => battle.enemy);
|
||||
const enemies = await Enemy.findAll({ where: { id: activeEnemyIds } });
|
||||
|
||||
if (enemies.length === 0) {
|
||||
return ctx.reply("В этой локации сейчас нет врагов.");
|
||||
}
|
||||
|
||||
const buttons = activeBattles.map((battle) => {
|
||||
const enemy = enemies.find((e) => e.id === battle.enemy);
|
||||
return {
|
||||
text: `${enemy.name} (HP: ${battle.enemy_hp})`,
|
||||
callback_data: `start_battle_${battle.id}`,
|
||||
};
|
||||
});
|
||||
|
||||
const keyboard = Markup.inlineKeyboard(
|
||||
buttons.map((btn) => [btn])
|
||||
);
|
||||
|
||||
await ctx.reply(
|
||||
`🔍 Локация: ${location.name}\n\nВыберите врага для охоты:`,
|
||||
keyboard
|
||||
);
|
||||
});
|
||||
|
||||
rpg.action(/start_battle_\d+/, async (ctx) => {
|
||||
const battleId = ctx.match[0].split('_')[2]; // Получаем ID битвы
|
||||
const battle = await Battle.findByPk(battleId);
|
||||
const enemy = await Enemy.findByPk(battle.enemy);
|
||||
|
||||
if (!battle || battle.status !== 'inactive') {
|
||||
return ctx.reply("Этот враг уже сражается с другим игроком или сражение завершено.");
|
||||
}
|
||||
|
||||
const existingBattle = await Battle.findOne({
|
||||
where: { character: ctx.from.id, status: 'active' },
|
||||
});
|
||||
|
||||
if (existingBattle) {
|
||||
return ctx.reply("Вы уже участвуете в другом сражении!");
|
||||
}
|
||||
|
||||
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
|
||||
if (!character) {
|
||||
return ctx.reply("Ваш персонаж не найден. Создайте его, чтобы начать играть!");
|
||||
}
|
||||
|
||||
battle.status = 'active';
|
||||
battle.character = ctx.from.id;
|
||||
await battle.save();
|
||||
|
||||
await startBattle(ctx, character, enemy, battle);
|
||||
});
|
||||
|
||||
const startBattle = async (ctx, character, enemy, battle) => {
|
||||
await ctx.reply(
|
||||
`⚔️ Начинается сражение!\n\nВаш противник: ${enemy.name}\n🛡️ Уровень: ${enemy.level}\n❤️ Здоровье: ${enemy.hp}\n\nВы готовы?`,
|
||||
Markup.inlineKeyboard([[{ text: "Атаковать", callback_data: `attack_${battle.id}` }]])
|
||||
);
|
||||
};
|
||||
|
||||
const enemyTurn = async (ctx, character, battle) => {
|
||||
const enemy = await Enemy.findByPk(battle.enemy);
|
||||
|
||||
const dodgeChance = Math.min(character.resistance * 0.05, 0.5);
|
||||
const isDodged = Math.random() < dodgeChance;
|
||||
|
||||
if (isDodged) {
|
||||
return ctx.reply("💨 Вы уклонились от атаки противника!");
|
||||
}
|
||||
|
||||
const damage = enemy.damage;
|
||||
character.hp -= damage;
|
||||
|
||||
if (character.hp <= 0) {
|
||||
battle.status = "failed";
|
||||
await battle.save();
|
||||
return ctx.reply(
|
||||
`💔 Противник нанес вам ${damage} урона!\n\nВы потерпели поражение от ${enemy.name}.`
|
||||
);
|
||||
}
|
||||
|
||||
await character.save();
|
||||
await ctx.reply(`💔 Противник нанес вам ${damage} урона. У вас осталось ${character.hp} HP.`);
|
||||
};
|
||||
|
||||
rpg.action(/attack_\d+/, async (ctx) => {
|
||||
const battleId = ctx.match[0].split("_")[1];
|
||||
const battle = await Battle.findByPk(battleId);
|
||||
|
||||
if (!battle || battle.status !== "active") {
|
||||
return ctx.reply("Сражение завершено или не существует.");
|
||||
}
|
||||
|
||||
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
|
||||
if (!character || battle.character != ctx.from.id) {
|
||||
return ctx.reply("Это не ваша битва.");
|
||||
}
|
||||
|
||||
const enemy = await Enemy.findByPk(battle.enemy);
|
||||
if (!enemy) {
|
||||
return ctx.reply("Противник не найден.");
|
||||
}
|
||||
|
||||
// Генерация кнопок
|
||||
const buttons = [];
|
||||
const totalButtons = 10; // Всего 10 кнопок
|
||||
const intelligenceFactor = Math.min(character.intelligence || 1, totalButtons - 1); // Интеллект увеличивает кнопки попадания
|
||||
const hitDamage = () => Math.floor(Math.random() * (character.force || 10)) + 1; // Урон от силы
|
||||
const criticalDamage = Math.floor((character.force || 10) * 2); // Критический урон
|
||||
|
||||
// Добавляем кнопки с попаданием
|
||||
for (let i = 0; i < intelligenceFactor; i++) {
|
||||
buttons.push({
|
||||
text: `Урон: ${hitDamage()}`,
|
||||
callback_data: `hit_${battleId}`,
|
||||
});
|
||||
}
|
||||
|
||||
// Добавляем кнопку с критическим уроном
|
||||
buttons.push({
|
||||
text: `Крит: ${criticalDamage}`,
|
||||
callback_data: `critical_${battleId}`,
|
||||
});
|
||||
|
||||
// Добавляем кнопки промаха
|
||||
while (buttons.length < totalButtons) {
|
||||
buttons.push({
|
||||
text: "Промах",
|
||||
callback_data: `miss_${battleId}`,
|
||||
});
|
||||
}
|
||||
|
||||
// Перетасовываем кнопки и создаём клавиатуру
|
||||
const shuffledButtons = buttons.sort(() => Math.random() - 0.5);
|
||||
const keyboard = Markup.inlineKeyboard(
|
||||
shuffledButtons.map((btn, index) => [btn]).reduce((rows, btn, i) => {
|
||||
if (i % 2 === 0) rows.push([]);
|
||||
rows[rows.length - 1].push(btn[0]);
|
||||
return rows;
|
||||
}, [])
|
||||
);
|
||||
|
||||
// Логи битвы
|
||||
const logs = battle.logs || [];
|
||||
const logMessage = logs.slice(-5).map((log) => `• ${log}`).join("\n");
|
||||
|
||||
// Сообщение с информацией
|
||||
await ctx.editMessageText(
|
||||
`⚔️ Сражение с ${enemy.name}\n\n` +
|
||||
`❤️ Здоровье врага: ${battle.enemy_hp}/${enemy.hp}\n` +
|
||||
`⚔️ Урон врага: ${enemy.damage}\n\n` +
|
||||
`📜 Логи битвы:\n${logMessage || "Пока ничего не произошло."}\n\n` +
|
||||
`🎯 Выберите цель для атаки:`,
|
||||
keyboard
|
||||
);
|
||||
});
|
||||
|
||||
// Обработка попадания
|
||||
rpg.action(/hit_\d+/, async (ctx) => {
|
||||
const battleId = ctx.match[0].split("_")[1];
|
||||
const battle = await Battle.findByPk(battleId);
|
||||
|
||||
if (!battle || battle.status !== "active") {
|
||||
return ctx.reply("Сражение завершено или не существует.");
|
||||
}
|
||||
|
||||
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
|
||||
if (!character || battle.character != ctx.from.id) {
|
||||
return ctx.reply("Это не ваша битва.");
|
||||
}
|
||||
|
||||
const enemy = await Enemy.findByPk(battle.enemy);
|
||||
if (!enemy) {
|
||||
return ctx.reply("Противник не найден.");
|
||||
}
|
||||
|
||||
// Урон
|
||||
const damage = Math.floor(Math.random() * (character.force || 10)) + 1;
|
||||
battle.enemy_hp -= damage;
|
||||
|
||||
// Логи
|
||||
battle.logs = battle.logs || [];
|
||||
battle.logs.push(`Вы нанесли ${damage} урона врагу.`);
|
||||
|
||||
// Проверка на победу
|
||||
if (battle.enemy_hp <= 0) {
|
||||
battle.status = "completed";
|
||||
await battle.save();
|
||||
return ctx.editMessageText(`🎉 Вы победили ${enemy.name}!`);
|
||||
}
|
||||
|
||||
await battle.save();
|
||||
|
||||
// Обновление сообщения с новыми кнопками
|
||||
const buttons = generateBattleButtons(character, battle); // Генерация новых кнопок
|
||||
const keyboard = Markup.inlineKeyboard(buttons);
|
||||
|
||||
const logs = battle.logs.slice(-5).map((log) => `• ${log}`).join("\n");
|
||||
|
||||
await ctx.editMessageText(
|
||||
`⚔️ Сражение с ${enemy.name}\n\n` +
|
||||
`❤️ Здоровье врага: ${battle.enemy_hp}/${enemy.hp}\n` +
|
||||
`⚔️ Урон врага: ${enemy.damage}\n\n` +
|
||||
`📜 Логи битвы:\n${logs || "Пока ничего не произошло."}\n\n` +
|
||||
`🎯 Выберите цель для атаки:`,
|
||||
keyboard
|
||||
);
|
||||
});
|
||||
|
||||
// Функция для генерации кнопок
|
||||
function generateBattleButtons(character, battle) {
|
||||
const buttons = [];
|
||||
const totalButtons = 10;
|
||||
const intelligenceFactor = Math.min(character.intelligence || 1, totalButtons - 1);
|
||||
const hitDamage = () => Math.floor(Math.random() * (character.force || 10)) + 1;
|
||||
const criticalDamage = Math.floor((character.force || 10) * 2);
|
||||
|
||||
// Генерация кнопок с уроном от атаки
|
||||
for (let i = 0; i < intelligenceFactor; i++) {
|
||||
buttons.push({
|
||||
text: `Урон: ${hitDamage()}`,
|
||||
callback_data: `hit_${battle.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
// Генерация кнопки с критическим уроном
|
||||
buttons.push({
|
||||
text: `Крит: ${criticalDamage}`,
|
||||
callback_data: `critical_${battle.id}`,
|
||||
});
|
||||
|
||||
// Заполнение оставшихся кнопок промахами
|
||||
while (buttons.length < totalButtons) {
|
||||
buttons.push({
|
||||
text: "Промах",
|
||||
callback_data: `miss_${battle.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
// Перетасовывание кнопок
|
||||
const shuffledButtons = buttons.sort(() => Math.random() - 0.5);
|
||||
|
||||
// Разбиение кнопок на 2 ряда (5 кнопок в каждой строке)
|
||||
const rows = [];
|
||||
for (let i = 0; i < shuffledButtons.length; i += 5) {
|
||||
rows.push(shuffledButtons.slice(i, i + 5));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
// Обработка критического удара
|
||||
rpg.action(/critical_\d+/, async (ctx) => {
|
||||
const battleId = ctx.match[0].split("_")[1];
|
||||
const battle = await Battle.findByPk(battleId);
|
||||
|
||||
if (!battle || battle.status !== "active") {
|
||||
return ctx.reply("Сражение завершено или не существует.");
|
||||
}
|
||||
|
||||
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
|
||||
if (!character || battle.character != ctx.from.id) {
|
||||
return ctx.reply("Это не ваша битва.");
|
||||
}
|
||||
|
||||
const enemy = await Enemy.findByPk(battle.enemy);
|
||||
if (!enemy) {
|
||||
return ctx.reply("Противник не найден.");
|
||||
}
|
||||
|
||||
// Критический урон
|
||||
const damage = Math.floor((character.force || 10) * 2);
|
||||
battle.enemy_hp -= damage;
|
||||
|
||||
// Логи
|
||||
battle.logs = battle.logs || [];
|
||||
battle.logs.push(`Критический удар! Вы нанесли ${damage} урона врагу.`);
|
||||
|
||||
// Проверка на победу
|
||||
if (battle.enemy_hp <= 0) {
|
||||
battle.status = "completed";
|
||||
await battle.save();
|
||||
return ctx.editMessageText(
|
||||
`🎉 Вы победили ${enemy.name}!\n\n📜 Логи битвы:\n${battle.logs.slice(-5).map((log) => `• ${log}`).join("\n")}`
|
||||
);
|
||||
}
|
||||
|
||||
await battle.save();
|
||||
|
||||
// Генерация новых кнопок
|
||||
const buttons = generateBattleButtons(character, battle);
|
||||
const keyboard = Markup.inlineKeyboard(buttons);
|
||||
|
||||
const logs = battle.logs.slice(-5).map((log) => `• ${log}`).join("\n");
|
||||
|
||||
await ctx.editMessageText(
|
||||
`⚔️ Сражение с ${enemy.name}\n\n` +
|
||||
`❤️ Здоровье врага: ${battle.enemy_hp}/${enemy.hp}\n` +
|
||||
`⚔️ Урон врага: ${enemy.damage}\n\n` +
|
||||
`📜 Логи битвы:\n${logs || "Пока ничего не произошло."}\n\n` +
|
||||
`🎯 Выберите цель для атаки:`,
|
||||
keyboard
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
// Обработка промаха
|
||||
rpg.action(/miss_\d+/, async (ctx) => {
|
||||
const battleId = ctx.match[0].split("_")[1];
|
||||
const battle = await Battle.findByPk(battleId);
|
||||
|
||||
if (!battle || battle.status !== "active") {
|
||||
return ctx.reply("Сражение завершено или не существует.");
|
||||
}
|
||||
|
||||
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
|
||||
if (!character || battle.character != ctx.from.id) {
|
||||
return ctx.reply("Это не ваша битва.");
|
||||
}
|
||||
|
||||
const enemy = await Enemy.findByPk(battle.enemy);
|
||||
if (!enemy) {
|
||||
return ctx.reply("Противник не найден.");
|
||||
}
|
||||
|
||||
// Логи
|
||||
battle.logs = battle.logs || [];
|
||||
battle.logs.push("Вы промахнулись.");
|
||||
await enemyTurn(ctx, character, battle);
|
||||
await battle.save();
|
||||
|
||||
// Генерация новых кнопок
|
||||
const buttons = generateBattleButtons(character, battle);
|
||||
const keyboard = Markup.inlineKeyboard(buttons);
|
||||
|
||||
const logs = battle.logs.slice(-5).map((log) => `• ${log}`).join("\n");
|
||||
|
||||
await ctx.editMessageText(
|
||||
`⚔️ Сражение с ${enemy.name}\n\n` +
|
||||
`❤️ Здоровье врага: ${battle.enemy_hp}/${enemy.hp}\n` +
|
||||
`⚔️ Урон врага: ${enemy.damage}\n\n` +
|
||||
`📜 Логи битвы:\n${logs || "Пока ничего не произошло."}\n\n` +
|
||||
`🎯 Выберите цель для атаки:`,
|
||||
keyboard
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user