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,
|
allowNull: false,
|
||||||
defaultValue: "inactive"
|
defaultValue: "inactive"
|
||||||
},
|
},
|
||||||
|
logs: {
|
||||||
|
type: DataTypes.ARRAY(DataTypes.STRING),
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: []
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = Battle;
|
module.exports = Battle;
|
||||||
|
202
rpg.js
202
rpg.js
@ -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` +
|
||||||
|
Loading…
Reference in New Issue
Block a user