v5.6
Battle Update Preparations
This commit is contained in:
parent
4f1e3943b4
commit
7813a7cde0
@ -28,6 +28,11 @@ const Battle = sequelize.define('battle', {
|
||||
allowNull: false,
|
||||
defaultValue: "inactive"
|
||||
},
|
||||
logs: {
|
||||
type: DataTypes.ARRAY(DataTypes.STRING),
|
||||
allowNull: true,
|
||||
defaultValue: []
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = Battle;
|
||||
|
202
rpg.js
202
rpg.js
@ -1551,6 +1551,14 @@ const generateBattles = async () => {
|
||||
const locations = await Location.findAll();
|
||||
|
||||
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 generatedEnemies = enemies.map((enemyId) => {
|
||||
const rarity = Math.random();
|
||||
@ -1561,18 +1569,29 @@ const generateBattles = async () => {
|
||||
const enemy = await Enemy.findByPk(enemyId);
|
||||
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({
|
||||
enemy: enemy.id,
|
||||
location: location.id,
|
||||
character: null,
|
||||
enemy_hp: enemy.hp,
|
||||
status: "inactive",
|
||||
logs: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log("Battles generated.");
|
||||
};
|
||||
|
||||
|
||||
generateBattles()
|
||||
schedule.scheduleJob('0 * * * *', generateBattles); // Каждый час в начале часа
|
||||
rpg.command("locations", async (ctx) => {
|
||||
const locations = await Location.findAll();
|
||||
if (!locations.length) {
|
||||
@ -1620,13 +1639,23 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
|
||||
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 || [];
|
||||
if (enemyIds.length === 0) {
|
||||
return ctx.reply("В этой локации сейчас нет врагов. Попробуйте позже.");
|
||||
}
|
||||
|
||||
const activeBattles = await Battle.findAll({
|
||||
where: { location: location.id, status: 'inactive' },
|
||||
where: { location: location.id, status: "inactive" },
|
||||
});
|
||||
|
||||
if (activeBattles.length === 0) {
|
||||
@ -1648,9 +1677,14 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
|
||||
};
|
||||
});
|
||||
|
||||
const keyboard = Markup.inlineKeyboard(
|
||||
buttons.map((btn) => [btn])
|
||||
);
|
||||
if (hasGrenadeLow || hasGrenadeMedium || hasGrenadeHard) {
|
||||
buttons.push({
|
||||
text: "💣 Использовать гранату",
|
||||
callback_data: `use_grenade_${locationId}`,
|
||||
});
|
||||
}
|
||||
|
||||
const keyboard = Markup.inlineKeyboard(buttons.map((btn) => [btn]));
|
||||
|
||||
await ctx.reply(
|
||||
`🔍 Локация: ${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) => {
|
||||
const battleId = ctx.match[0].split('_')[2]; // Получаем ID битвы
|
||||
const battle = await Battle.findByPk(battleId);
|
||||
@ -1701,22 +1796,24 @@ const enemyTurn = async (ctx, character, battle) => {
|
||||
const isDodged = Math.random() < dodgeChance;
|
||||
|
||||
if (isDodged) {
|
||||
return ctx.reply("💨 Вы уклонились от атаки противника!");
|
||||
battle.logs.push(`💨 ${character.name} уклонились от атаки противника!`);
|
||||
return await battle.save({ fields: ["logs"] });
|
||||
}
|
||||
|
||||
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}.`
|
||||
battle.status = "inactive";
|
||||
battle.logs.push(
|
||||
`💔 Противник нанес ${character.name} ${damage} урона!\n\n${character.name} потерпел поражение от ${enemy.name}.`
|
||||
);
|
||||
return await battle.save({ fields: ["logs", "status"] });
|
||||
}
|
||||
|
||||
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) => {
|
||||
@ -1738,44 +1835,8 @@ rpg.action(/attack_\d+/, async (ctx) => {
|
||||
}
|
||||
|
||||
// Генерация кнопок
|
||||
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 buttons = generateBattleButtons(character, battle);
|
||||
const keyboard = Markup.inlineKeyboard(buttons);
|
||||
// Логи битвы
|
||||
const logs = battle.logs || [];
|
||||
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.push(`Вы нанесли ${damage} урона врагу.`);
|
||||
battle.logs.push(`${character.name} нанес ${damage} урона врагу.`);
|
||||
await battle.save({ fields: ["enemy_hp", "logs"] });
|
||||
|
||||
// Проверка на победу
|
||||
if (battle.enemy_hp <= 0) {
|
||||
battle.status = "completed";
|
||||
await battle.save();
|
||||
return ctx.editMessageText(`🎉 Вы победили ${enemy.name}!`);
|
||||
return ctx.editMessageText(`🎉 ${character.name} победил ${enemy.name}!`);
|
||||
}
|
||||
|
||||
await battle.save();
|
||||
@ -1843,32 +1905,35 @@ rpg.action(/hit_\d+/, async (ctx) => {
|
||||
);
|
||||
});
|
||||
|
||||
// Функция для генерации кнопок
|
||||
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);
|
||||
const intelligenceFactor = Math.min(character.intelligence || 1, totalButtons - 2); // Уменьшаем на 2 для кнопки критического удара и гарантированного промаха
|
||||
const buttons = [];
|
||||
|
||||
// Генерация кнопок с уроном от атаки
|
||||
for (let i = 0; i < intelligenceFactor; i++) {
|
||||
buttons.push({
|
||||
text: `Урон: ${hitDamage()}`,
|
||||
text: `🎯`,
|
||||
callback_data: `hit_${battle.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
// Генерация кнопки с критическим уроном
|
||||
buttons.push({
|
||||
text: `Крит: ${criticalDamage}`,
|
||||
text: `💥`,
|
||||
callback_data: `critical_${battle.id}`,
|
||||
});
|
||||
|
||||
// Заполнение оставшихся кнопок промахами
|
||||
// Гарантированная кнопка промаха
|
||||
buttons.push({
|
||||
text: "❌",
|
||||
callback_data: `miss_${battle.id}`,
|
||||
});
|
||||
|
||||
// Заполнение оставшихся кнопок (если не хватает до totalButtons)
|
||||
while (buttons.length < totalButtons) {
|
||||
buttons.push({
|
||||
text: "Промах",
|
||||
text: "❌",
|
||||
callback_data: `miss_${battle.id}`,
|
||||
});
|
||||
}
|
||||
@ -1876,7 +1941,7 @@ function generateBattleButtons(character, battle) {
|
||||
// Перетасовывание кнопок
|
||||
const shuffledButtons = buttons.sort(() => Math.random() - 0.5);
|
||||
|
||||
// Разбиение кнопок на 2 ряда (5 кнопок в каждой строке)
|
||||
// Разбиение кнопок на 2 строки (по 5 кнопок в каждой строке)
|
||||
const rows = [];
|
||||
for (let i = 0; i < shuffledButtons.length; i += 5) {
|
||||
rows.push(shuffledButtons.slice(i, i + 5));
|
||||
@ -1886,6 +1951,7 @@ function generateBattleButtons(character, battle) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Обработка критического удара
|
||||
rpg.action(/critical_\d+/, async (ctx) => {
|
||||
const battleId = ctx.match[0].split("_")[1];
|
||||
@ -1911,18 +1977,18 @@ rpg.action(/critical_\d+/, async (ctx) => {
|
||||
|
||||
// Логи
|
||||
battle.logs = battle.logs || [];
|
||||
battle.logs.push(`Критический удар! Вы нанесли ${damage} урона врагу.`);
|
||||
battle.logs.push(`Критический удар! ${character.name} нанес ${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")}`
|
||||
`🎉 ${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);
|
||||
@ -1962,16 +2028,20 @@ rpg.action(/miss_\d+/, async (ctx) => {
|
||||
|
||||
// Логи
|
||||
battle.logs = battle.logs || [];
|
||||
battle.logs.push("Вы промахнулись.");
|
||||
battle.logs.push(`${character.name} промахнулся.`);
|
||||
await enemyTurn(ctx, character, battle);
|
||||
await battle.save();
|
||||
await battle.save({ fields: ["enemy_hp", "logs"] });
|
||||
|
||||
// Генерация новых кнопок
|
||||
const buttons = generateBattleButtons(character, battle);
|
||||
const keyboard = Markup.inlineKeyboard(buttons);
|
||||
|
||||
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(
|
||||
`⚔️ Сражение с ${enemy.name}\n\n` +
|
||||
`❤️ Здоровье врага: ${battle.enemy_hp}/${enemy.hp}\n` +
|
||||
|
Loading…
Reference in New Issue
Block a user