Battle Update Preparations
This commit is contained in:
Degradin 2025-01-13 01:38:51 +03:00
parent 4f1e3943b4
commit 7813a7cde0
2 changed files with 141 additions and 66 deletions

View File

@ -28,6 +28,11 @@ const Battle = sequelize.define('battle', {
allowNull: false, allowNull: false,
defaultValue: "inactive" defaultValue: "inactive"
}, },
logs: {
type: DataTypes.ARRAY(DataTypes.STRING),
allowNull: true,
defaultValue: []
},
}); });
module.exports = Battle; module.exports = Battle;

202
rpg.js
View File

@ -1551,6 +1551,14 @@ const generateBattles = async () => {
const locations = await Location.findAll(); const locations = await Location.findAll();
for (const location of locations) { for (const location of locations) {
// Проверяем количество битв для текущей локации
const existingBattlesCount = await Battle.count({ where: { location: location.id, status: 'inactive' } });
if (existingBattlesCount >= 10) {
console.log(`Пропущена локация ${location.id}, уже есть 10 битв.`);
continue; // Пропускаем локацию, если уже есть 10 битв
}
const enemies = location.enemies; const enemies = location.enemies;
const generatedEnemies = enemies.map((enemyId) => { const generatedEnemies = enemies.map((enemyId) => {
const rarity = Math.random(); const rarity = Math.random();
@ -1561,18 +1569,29 @@ const generateBattles = async () => {
const enemy = await Enemy.findByPk(enemyId); const enemy = await Enemy.findByPk(enemyId);
if (!enemy) continue; if (!enemy) continue;
// Проверяем, нужно ли создавать битвы (не превышать лимит в 10)
const currentBattlesCount = await Battle.count({ where: { location: location.id, status: 'inactive' } });
if (currentBattlesCount >= 5) {
console.log(`Достигнут лимит битв для локации ${location.id}.`);
break;
}
await Battle.create({ await Battle.create({
enemy: enemy.id, enemy: enemy.id,
location: location.id, location: location.id,
character: null, character: null,
enemy_hp: enemy.hp, enemy_hp: enemy.hp,
status: "inactive", status: "inactive",
logs: [],
}); });
} }
} }
console.log("Battles generated."); console.log("Battles generated.");
}; };
generateBattles()
schedule.scheduleJob('0 * * * *', generateBattles); // Каждый час в начале часа
rpg.command("locations", async (ctx) => { rpg.command("locations", async (ctx) => {
const locations = await Location.findAll(); const locations = await Location.findAll();
if (!locations.length) { if (!locations.length) {
@ -1620,13 +1639,23 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
return ctx.reply("Локация не найдена."); return ctx.reply("Локация не найдена.");
} }
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
if (!character) {
return ctx.reply("Ваш персонаж не найден.");
}
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } });
const hasGrenadeLow = inventory.some((item) => item.text_id === "grenade_low");
const hasGrenadeMedium = inventory.some((item) => item.text_id === "grenade_medium");
const hasGrenadeHard = inventory.some((item) => item.text_id === "grenade_hard");
const enemyIds = location.enemies || []; const enemyIds = location.enemies || [];
if (enemyIds.length === 0) { if (enemyIds.length === 0) {
return ctx.reply("В этой локации сейчас нет врагов. Попробуйте позже."); return ctx.reply("В этой локации сейчас нет врагов. Попробуйте позже.");
} }
const activeBattles = await Battle.findAll({ const activeBattles = await Battle.findAll({
where: { location: location.id, status: 'inactive' }, where: { location: location.id, status: "inactive" },
}); });
if (activeBattles.length === 0) { if (activeBattles.length === 0) {
@ -1648,9 +1677,14 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
}; };
}); });
const keyboard = Markup.inlineKeyboard( if (hasGrenadeLow || hasGrenadeMedium || hasGrenadeHard) {
buttons.map((btn) => [btn]) buttons.push({
); text: "💣 Использовать гранату",
callback_data: `use_grenade_${locationId}`,
});
}
const keyboard = Markup.inlineKeyboard(buttons.map((btn) => [btn]));
await ctx.reply( await ctx.reply(
`🔍 Локация: ${location.name}\n\nВыберите врага для охоты:`, `🔍 Локация: ${location.name}\n\nВыберите врага для охоты:`,
@ -1658,6 +1692,67 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
); );
}); });
// Использование гранаты
rpg.action(/use_grenade_\d+/, async (ctx) => {
const locationId = ctx.match[0].split('_')[2];
const location = await Location.findByPk(locationId);
if (!location) {
return ctx.reply("Локация не найдена.");
}
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
if (!character) {
return ctx.reply("Ваш персонаж не найден.");
}
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } });
const grenade =
inventory.find((item) => item.text_id === "grenade_hard") ||
inventory.find((item) => item.text_id === "grenade_medium") ||
inventory.find((item) => item.text_id === "grenade_low");
if (!grenade) {
return ctx.reply("У вас нет гранаты для использования.");
}
const activeBattles = await Battle.findAll({
where: { location: location.id, status: "inactive" },
});
if (activeBattles.length === 0) {
return ctx.reply("В этой локации нет активных врагов.");
}
// Урон гранаты
const damage =
grenade.text_id === "grenade_hard"
? 50
: grenade.text_id === "grenade_medium"
? 30
: 10;
let message = `💥 Вы использовали гранату (${grenade.text_id}) и нанесли ${damage} урона всем врагам!`;
for (const battle of activeBattles) {
battle.enemy_hp -= damage;
battle.logs.push(`💣 Враг получил ${damage} урона от гранаты.`);
if (battle.enemy_hp <= 0) {
battle.status = "completed";
battle.logs.push("💀 Враг был убит гранатой.");
}
await battle.save({ fields: ["enemy_hp", "logs", "status"] });
}
// Удаляем гранату из инвентаря
await InventoryModel.destroy({ where: { id: grenade.id } });
await ctx.reply(message);
});
rpg.action(/start_battle_\d+/, async (ctx) => { rpg.action(/start_battle_\d+/, async (ctx) => {
const battleId = ctx.match[0].split('_')[2]; // Получаем ID битвы const battleId = ctx.match[0].split('_')[2]; // Получаем ID битвы
const battle = await Battle.findByPk(battleId); const battle = await Battle.findByPk(battleId);
@ -1701,22 +1796,24 @@ const enemyTurn = async (ctx, character, battle) => {
const isDodged = Math.random() < dodgeChance; const isDodged = Math.random() < dodgeChance;
if (isDodged) { if (isDodged) {
return ctx.reply("💨 Вы уклонились от атаки противника!"); battle.logs.push(`💨 ${character.name} уклонились от атаки противника!`);
return await battle.save({ fields: ["logs"] });
} }
const damage = enemy.damage; const damage = enemy.damage;
character.hp -= damage; character.hp -= damage;
if (character.hp <= 0) { if (character.hp <= 0) {
battle.status = "failed"; battle.status = "inactive";
await battle.save(); battle.logs.push(
return ctx.reply( `💔 Противник нанес ${character.name} ${damage} урона!\n\n${character.name} потерпел поражение от ${enemy.name}.`
`💔 Противник нанес вам ${damage} урона!\n\nВы потерпели поражение от ${enemy.name}.`
); );
return await battle.save({ fields: ["logs", "status"] });
} }
await character.save(); await character.save();
await ctx.reply(`💔 Противник нанес вам ${damage} урона. У вас осталось ${character.hp} HP.`); await battle.logs.push(`💔 Противник нанес ${character.name} ${damage} урона. У ${character.name} осталось ${character.hp} HP.`);
await battle.save({ fields: ["logs"] });
}; };
rpg.action(/attack_\d+/, async (ctx) => { rpg.action(/attack_\d+/, async (ctx) => {
@ -1738,44 +1835,8 @@ rpg.action(/attack_\d+/, async (ctx) => {
} }
// Генерация кнопок // Генерация кнопок
const buttons = []; const buttons = generateBattleButtons(character, battle);
const totalButtons = 10; // Всего 10 кнопок const keyboard = Markup.inlineKeyboard(buttons);
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 logs = battle.logs || [];
const logMessage = logs.slice(-5).map((log) => `${log}`).join("\n"); const logMessage = logs.slice(-5).map((log) => `${log}`).join("\n");
@ -1816,13 +1877,14 @@ rpg.action(/hit_\d+/, async (ctx) => {
// Логи // Логи
battle.logs = battle.logs || []; battle.logs = battle.logs || [];
battle.logs.push(`Вы нанесли ${damage} урона врагу.`); battle.logs.push(`${character.name} нанес ${damage} урона врагу.`);
await battle.save({ fields: ["enemy_hp", "logs"] });
// Проверка на победу // Проверка на победу
if (battle.enemy_hp <= 0) { if (battle.enemy_hp <= 0) {
battle.status = "completed"; battle.status = "completed";
await battle.save(); await battle.save();
return ctx.editMessageText(`🎉 Вы победили ${enemy.name}!`); return ctx.editMessageText(`🎉 ${character.name} победил ${enemy.name}!`);
} }
await battle.save(); await battle.save();
@ -1843,32 +1905,35 @@ rpg.action(/hit_\d+/, async (ctx) => {
); );
}); });
// Функция для генерации кнопок
function generateBattleButtons(character, battle) { function generateBattleButtons(character, battle) {
const buttons = [];
const totalButtons = 10; const totalButtons = 10;
const intelligenceFactor = Math.min(character.intelligence || 1, totalButtons - 1); const intelligenceFactor = Math.min(character.intelligence || 1, totalButtons - 2); // Уменьшаем на 2 для кнопки критического удара и гарантированного промаха
const hitDamage = () => Math.floor(Math.random() * (character.force || 10)) + 1; const buttons = [];
const criticalDamage = Math.floor((character.force || 10) * 2);
// Генерация кнопок с уроном от атаки // Генерация кнопок с уроном от атаки
for (let i = 0; i < intelligenceFactor; i++) { for (let i = 0; i < intelligenceFactor; i++) {
buttons.push({ buttons.push({
text: `Урон: ${hitDamage()}`, text: `🎯`,
callback_data: `hit_${battle.id}`, callback_data: `hit_${battle.id}`,
}); });
} }
// Генерация кнопки с критическим уроном // Генерация кнопки с критическим уроном
buttons.push({ buttons.push({
text: `Крит: ${criticalDamage}`, text: `💥`,
callback_data: `critical_${battle.id}`, callback_data: `critical_${battle.id}`,
}); });
// Заполнение оставшихся кнопок промахами // Гарантированная кнопка промаха
buttons.push({
text: "❌",
callback_data: `miss_${battle.id}`,
});
// Заполнение оставшихся кнопок (если не хватает до totalButtons)
while (buttons.length < totalButtons) { while (buttons.length < totalButtons) {
buttons.push({ buttons.push({
text: "Промах", text: "",
callback_data: `miss_${battle.id}`, callback_data: `miss_${battle.id}`,
}); });
} }
@ -1876,7 +1941,7 @@ function generateBattleButtons(character, battle) {
// Перетасовывание кнопок // Перетасовывание кнопок
const shuffledButtons = buttons.sort(() => Math.random() - 0.5); const shuffledButtons = buttons.sort(() => Math.random() - 0.5);
// Разбиение кнопок на 2 ряда (5 кнопок в каждой строке) // Разбиение кнопок на 2 строки (по 5 кнопок в каждой строке)
const rows = []; const rows = [];
for (let i = 0; i < shuffledButtons.length; i += 5) { for (let i = 0; i < shuffledButtons.length; i += 5) {
rows.push(shuffledButtons.slice(i, i + 5)); rows.push(shuffledButtons.slice(i, i + 5));
@ -1886,6 +1951,7 @@ function generateBattleButtons(character, battle) {
} }
// Обработка критического удара // Обработка критического удара
rpg.action(/critical_\d+/, async (ctx) => { rpg.action(/critical_\d+/, async (ctx) => {
const battleId = ctx.match[0].split("_")[1]; const battleId = ctx.match[0].split("_")[1];
@ -1911,18 +1977,18 @@ rpg.action(/critical_\d+/, async (ctx) => {
// Логи // Логи
battle.logs = battle.logs || []; battle.logs = battle.logs || [];
battle.logs.push(`Критический удар! Вы нанесли ${damage} урона врагу.`); battle.logs.push(`Критический удар! ${character.name} нанес ${damage} урона врагу.`);
// Проверка на победу // Проверка на победу
if (battle.enemy_hp <= 0) { if (battle.enemy_hp <= 0) {
battle.status = "completed"; battle.status = "completed";
await battle.save(); await battle.save();
return ctx.editMessageText( return ctx.editMessageText(
`🎉 Вы победили ${enemy.name}!\n\n📜 Логи битвы:\n${battle.logs.slice(-5).map((log) => `${log}`).join("\n")}` `🎉 ${character.name} победил ${enemy.name}!\n\n📜 Логи битвы:\n${battle.logs.slice(-5).map((log) => `${log}`).join("\n")}`
); );
} }
await battle.save(); await battle.save({ fields: ["enemy_hp", "logs"] });
// Генерация новых кнопок // Генерация новых кнопок
const buttons = generateBattleButtons(character, battle); const buttons = generateBattleButtons(character, battle);
@ -1962,16 +2028,20 @@ rpg.action(/miss_\d+/, async (ctx) => {
// Логи // Логи
battle.logs = battle.logs || []; battle.logs = battle.logs || [];
battle.logs.push("Вы промахнулись."); battle.logs.push(`${character.name} промахнулся.`);
await enemyTurn(ctx, character, battle); await enemyTurn(ctx, character, battle);
await battle.save(); await battle.save({ fields: ["enemy_hp", "logs"] });
// Генерация новых кнопок // Генерация новых кнопок
const buttons = generateBattleButtons(character, battle); const buttons = generateBattleButtons(character, battle);
const keyboard = Markup.inlineKeyboard(buttons); const keyboard = Markup.inlineKeyboard(buttons);
const logs = battle.logs.slice(-5).map((log) => `${log}`).join("\n"); const logs = battle.logs.slice(-5).map((log) => `${log}`).join("\n");
if (character.hp <= 0) {
return ctx.editMessageText(
`💔 ${character.name} потерпел поражение от ${enemy.name}!\n\n📜 Логи битвы:\n${logs}`
);
}
await ctx.editMessageText( await ctx.editMessageText(
`⚔️ Сражение с ${enemy.name}\n\n` + `⚔️ Сражение с ${enemy.name}\n\n` +
`❤️ Здоровье врага: ${battle.enemy_hp}/${enemy.hp}\n` + `❤️ Здоровье врага: ${battle.enemy_hp}/${enemy.hp}\n` +