Logs and Stabily Update
This commit is contained in:
Degradin 2025-01-15 19:24:55 +03:00
parent 0c11fd7339
commit 6e60a8be8b
3 changed files with 19119 additions and 29 deletions

22
bot.js
View File

@ -24,7 +24,8 @@ const {
ResourcePriceModel, ResourcePriceModel,
SkillsModel, SkillsModel,
DailyModel, DailyModel,
logMiddleware logMiddleware,
logs
} = global.config } = global.config
const bot = new Telegraf(process.env.BOT_TOKEN) const bot = new Telegraf(process.env.BOT_TOKEN)
const rpg = require('./rpg'); // Подключение RPG-механик const rpg = require('./rpg'); // Подключение RPG-механик
@ -77,6 +78,22 @@ bot.telegram.setMyCommands([{
description: "Создать жалобу/обращение/идею." description: "Создать жалобу/обращение/идею."
} }
]) ])
bot.catch((err, ctx) => {
console.error(`Произошла ошибка:`, err);
// Отправляем сообщение админу из adminList
for (let admin of global.config.adminList) {
bot.telegram.sendMessage(admin, `Произошла ошибка:\n\n${err.on.method}`);
}
switch (err.on.method) {
case 'sendMessage':
return ctx.answerCbQuery(`Произошла ошибка при отправке сообщения.`);
case 'editMessageText':
return ctx.answerCbQuery(`Произошла ошибка при редактировании сообщения.`);
default:
return ctx.answerCbQuery(`Произошла ошибка.`);
}
});
bot.use(stage.middleware()) bot.use(stage.middleware())
bot.use(rpg) bot.use(rpg)
@ -373,7 +390,6 @@ bot.action(/dissolve_organization_(\d+)/, async (ctx) => {
try { try {
const businessId = parseInt(ctx.match[1], 10); const businessId = parseInt(ctx.match[1], 10);
const business = await BusinessModel.findByPk(businessId); const business = await BusinessModel.findByPk(businessId);
console.log(businessId + " " + business.owner)
if (!business) { if (!business) {
return ctx.answerCbQuery('Организация не найдена.', { show_alert: true }); return ctx.answerCbQuery('Организация не найдена.', { show_alert: true });
} }
@ -401,7 +417,7 @@ bot.action(/dissolve_organization_(\d+)/, async (ctx) => {
member.business = { id: 0, checks: 0, percent: 0 }; member.business = { id: 0, checks: 0, percent: 0 };
await member.save(); await member.save();
} }
logs(ctx, `Ликвидация организации ${business.name}`, { businessId, payout });
// Удаление организации // Удаление организации
await business.destroy(); await business.destroy();

File diff suppressed because it is too large Load Diff

83
rpg.js
View File

@ -7,6 +7,7 @@ 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 { const {
phones, phones,
expToUp, expToUp,
@ -145,7 +146,7 @@ rpg.action('fire_distribute', async (ctx) => {
Markup.button.callback('🎯', 'increase_resilience'), Markup.button.callback('🎯', 'increase_resilience'),
Markup.button.callback('💖', 'increase_endurance'), Markup.button.callback('💖', 'increase_endurance'),
], { columns: 2 }); ], { columns: 2 });
logs(ctx, "Распределение очков F.I.R.E", {firePoints: character.firePoints, force: character.force, intelligence: character.intelligence, resilience: character.resilience, endurance: character.endurance});
// Отправляем сообщение с кнопками // Отправляем сообщение с кнопками
await ctx.reply(message, keyboard); await ctx.reply(message, keyboard);
}); });
@ -181,6 +182,7 @@ rpg.action(/^increase_(force|intelligence|resilience|endurance)$/, async (ctx) =
// Уменьшаем количество очков и сохраняем изменения // Уменьшаем количество очков и сохраняем изменения
character.firePoints--; character.firePoints--;
logs(ctx, "Увеличение характеристики", { attribute: attribute, firePoints: character.firePoints, force: character.force, intelligence: character.intelligence, resilience: character.resilience, endurance: character.endurance });
await character.save(); await character.save();
// Отправляем обновлённое сообщение // Отправляем обновлённое сообщение
@ -1582,19 +1584,17 @@ schedule.scheduleJob('0 * * * *', generateBattles); // Каждый час в н
rpg.action("locations", async (ctx) => { rpg.action("locations", async (ctx) => {
const locations = await Location.findAll(); const locations = await Location.findAll();
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
if (!locations.length) { if (!locations.length) {
return ctx.reply("Нет доступных локаций для исследования."); return ctx.reply("Нет доступных локаций для исследования.");
} }
// Создаем кнопки для каждой локации и сортируем их по уровню
const locationButtons = locations.map((location) => ({ const buttons = locations
text: location.name + ` (${location.level} lvl.)`, .sort((a, b) => a.level - b.level)
callback_data: `viewlocation_${location.id}`, .map((location) => {
})); return Markup.button.callback(location.name + ` [${character.level < location.level + 3 ? `⚠️ ` + `${location.level} - ${location.level + 3}` : `${location.level} - ${location.level + 3}`} Ур.]`, `viewlocation_${location.id}`);
});
const keyboard = Markup.inlineKeyboard( const keyboard = Markup.inlineKeyboard(buttons, { columns: 1 });
locationButtons.map((button) => [button]) // Одна кнопка на строку
);
await ctx.reply("Выберите локацию для исследования:", keyboard); await ctx.reply("Выберите локацию для исследования:", keyboard);
}); });
@ -1624,14 +1624,16 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
const location = await Location.findByPk(locationId); const location = await Location.findByPk(locationId);
if (!location) { if (!location) {
logs(ctx, "Локация не найдена", { locationId });
return ctx.reply("Локация не найдена."); return ctx.reply("Локация не найдена.");
} }
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } }); const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
if (!character) { if (!character) {
logs(ctx, "Персонаж не найден", { telegramId: ctx.from.id });
return ctx.reply("Ваш персонаж не найден."); return ctx.reply("Ваш персонаж не найден.");
} }
logs(ctx, "Охота", {location: location});
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } }); const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } });
const hasGrenadeLow = inventory.some((item) => item.text_id === "grenade_low"); const hasGrenadeLow = inventory.some((item) => item.text_id === "grenade_low");
const hasGrenadeMedium = inventory.some((item) => item.text_id === "grenade_medium"); const hasGrenadeMedium = inventory.some((item) => item.text_id === "grenade_medium");
@ -1639,6 +1641,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
const enemyIds = location.enemies || []; const enemyIds = location.enemies || [];
if (enemyIds.length === 0) { if (enemyIds.length === 0) {
logs(ctx, "Нет врагов в локации", { location });
return ctx.answerCbQuery("В этой локации сейчас нет врагов. Попробуйте позже."); return ctx.answerCbQuery("В этой локации сейчас нет врагов. Попробуйте позже.");
} }
@ -1647,6 +1650,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
}); });
if (activeBattles.length === 0) { if (activeBattles.length === 0) {
logs(ctx, "Нет активных врагов в локации", { location });
return ctx.answerCbQuery("В этой локации сейчас нет активных врагов. Попробуйте позже."); return ctx.answerCbQuery("В этой локации сейчас нет активных врагов. Попробуйте позже.");
} }
@ -1654,6 +1658,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
const enemies = await Enemy.findAll({ where: { id: activeEnemyIds } }); const enemies = await Enemy.findAll({ where: { id: activeEnemyIds } });
if (enemies.length === 0) { if (enemies.length === 0) {
logs(ctx, "Нет врагов в локации", { location });
return ctx.answerCbQuery("В этой локации сейчас нет врагов."); return ctx.answerCbQuery("В этой локации сейчас нет врагов.");
} }
@ -1674,6 +1679,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
const keyboard = Markup.inlineKeyboard(buttons.map((btn) => [btn])); const keyboard = Markup.inlineKeyboard(buttons.map((btn) => [btn]));
logs(ctx, "Выбор врага для охоты", { location, enemies });
await ctx.editMessageText( await ctx.editMessageText(
`🔍 Локация: ${location.name}\n\nВыберите врага для охоты:`, `🔍 Локация: ${location.name}\n\nВыберите врага для охоты:`,
keyboard keyboard
@ -1686,11 +1692,13 @@ rpg.action(/use_grenade_\d+/, async (ctx) => {
const location = await Location.findByPk(locationId); const location = await Location.findByPk(locationId);
if (!location) { if (!location) {
logs(ctx, "Локация не найдена", { locationId });
return ctx.reply("Локация не найдена."); return ctx.reply("Локация не найдена.");
} }
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } }); const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
if (!character) { if (!character) {
logs(ctx, "Персонаж не найден", { telegramId: ctx.from.id });
return ctx.reply("Ваш персонаж не найден."); return ctx.reply("Ваш персонаж не найден.");
} }
@ -1701,6 +1709,7 @@ rpg.action(/use_grenade_\d+/, async (ctx) => {
inventory.find((item) => item.text_id === "grenade_low"); inventory.find((item) => item.text_id === "grenade_low");
if (!grenade) { if (!grenade) {
logs(ctx, "Граната не найдена", { telegramId: ctx.from.id });
return ctx.reply("У вас нет гранаты для использования."); return ctx.reply("У вас нет гранаты для использования.");
} }
@ -1709,6 +1718,7 @@ rpg.action(/use_grenade_\d+/, async (ctx) => {
}); });
if (activeBattles.length === 0) { if (activeBattles.length === 0) {
logs(ctx, "Нет активных врагов в локации", { location });
return ctx.reply("В этой локации нет активных врагов."); return ctx.reply("В этой локации нет активных врагов.");
} }
@ -1737,16 +1747,17 @@ rpg.action(/use_grenade_\d+/, async (ctx) => {
// Удаляем гранату из инвентаря // Удаляем гранату из инвентаря
await InventoryModel.destroy({ where: { id: grenade.id } }); await InventoryModel.destroy({ where: { id: grenade.id } });
logs(ctx, "Использование гранаты", { grenade, damage });
await ctx.answerCbQuery(message, { show_alert: true }); await ctx.answerCbQuery(message, { show_alert: true });
}); });
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);
const enemy = await Enemy.findByPk(battle.enemy); const enemy = await Enemy.findByPk(battle.enemy);
if (!battle || battle.status !== 'inactive') { if (!battle || battle.status !== 'inactive') {
logs(ctx, "Битва не найдена или уже активна", { battleId });
return ctx.reply("Этот враг уже сражается с другим игроком или сражение завершено."); return ctx.reply("Этот враг уже сражается с другим игроком или сражение завершено.");
} }
@ -1755,11 +1766,13 @@ rpg.action(/start_battle_\d+/, async (ctx) => {
}); });
if (existingBattle) { if (existingBattle) {
logs(ctx, "Игрок уже участвует в другой битве", { telegramId: ctx.from.id });
return ctx.reply("Вы уже участвуете в другом сражении!"); return ctx.reply("Вы уже участвуете в другом сражении!");
} }
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } }); const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
if (!character) { if (!character) {
logs(ctx, "Персонаж не найден", { telegramId: ctx.from.id });
return ctx.reply("Ваш персонаж не найден. Создайте его, чтобы начать играть!"); return ctx.reply("Ваш персонаж не найден. Создайте его, чтобы начать играть!");
} }
@ -1775,6 +1788,7 @@ const startBattle = async (ctx, character, enemy, battle) => {
`⚔️ Начинается сражение!\n\nВаш противник: ${enemy.name}\n🛡️ Уровень: ${enemy.level}\n❤️ Здоровье: ${enemy.hp}\n\nВы готовы?`, `⚔️ Начинается сражение!\n\nВаш противник: ${enemy.name}\n🛡️ Уровень: ${enemy.level}\n❤️ Здоровье: ${enemy.hp}\n\nВы готовы?`,
Markup.inlineKeyboard([[{ text: "Атаковать", callback_data: `attack_${battle.id}` }]]) Markup.inlineKeyboard([[{ text: "Атаковать", callback_data: `attack_${battle.id}` }]])
); );
logs(ctx, "Начало сражения", { enemy, battle });
}; };
const enemyTurn = async (ctx, character, battle) => { const enemyTurn = async (ctx, character, battle) => {
@ -1785,7 +1799,9 @@ const enemyTurn = async (ctx, character, battle) => {
if (isDodged) { if (isDodged) {
battle.logs.push(`💨 ${character.name} уклонились от атаки противника!`); battle.logs.push(`💨 ${character.name} уклонились от атаки противника!`);
return await battle.save({ fields: ["logs"] }); await battle.save({ fields: ["logs"] });
logs(ctx, "Уклонение от атаки", { enemy, battle });
return;
} }
const damage = enemy.damage; const damage = enemy.damage;
@ -1796,12 +1812,15 @@ const enemyTurn = async (ctx, character, battle) => {
battle.logs.push( battle.logs.push(
`💔 Противник нанес ${character.name} ${damage} урона!\n\n${character.name} потерпел поражение от ${enemy.name}.` `💔 Противник нанес ${character.name} ${damage} урона!\n\n${character.name} потерпел поражение от ${enemy.name}.`
); );
return await battle.save({ fields: ["logs", "status"] }); await battle.save({ fields: ["logs", "status"] });
logs(ctx, "Поражение персонажа", { enemy, battle });
return;
} }
await character.save(); await character.save();
await battle.logs.push(`💔 Противник нанес ${character.name} ${damage} урона. У ${character.name} осталось ${character.hp} HP.`); battle.logs.push(`💔 Противник нанес ${character.name} ${damage} урона. У ${character.name} осталось ${character.hp} HP.`);
await battle.save({ fields: ["logs"] }); await battle.save({ fields: ["logs"] });
logs(ctx, "Атака врага", { enemy, battle, damage });
}; };
rpg.action(/attack_\d+/, async (ctx) => { rpg.action(/attack_\d+/, async (ctx) => {
@ -1809,16 +1828,19 @@ rpg.action(/attack_\d+/, async (ctx) => {
const battle = await Battle.findByPk(battleId); const battle = await Battle.findByPk(battleId);
if (!battle || battle.status !== "active") { if (!battle || battle.status !== "active") {
logs(ctx, "Сражение завершено или не существует", { battleId });
return ctx.reply("Сражение завершено или не существует."); return ctx.reply("Сражение завершено или не существует.");
} }
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } }); const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
if (!character || battle.character != ctx.from.id) { if (!character || battle.character != ctx.from.id) {
logs(ctx, "Персонаж не найден или не участвует в битве", { telegramId: ctx.from.id, battleId });
return ctx.reply("Это не ваша битва."); return ctx.reply("Это не ваша битва.");
} }
const enemy = await Enemy.findByPk(battle.enemy); const enemy = await Enemy.findByPk(battle.enemy);
if (!enemy) { if (!enemy) {
logs(ctx, "Противник не найден", { enemyId: battle.enemy });
return ctx.reply("Противник не найден."); return ctx.reply("Противник не найден.");
} }
@ -1826,10 +1848,11 @@ rpg.action(/attack_\d+/, async (ctx) => {
const buttons = generateBattleButtons(character, battle); const buttons = generateBattleButtons(character, battle);
const keyboard = Markup.inlineKeyboard(buttons); const keyboard = Markup.inlineKeyboard(buttons);
// Логи битвы // Логи битвы
const logs = battle.logs || []; const battlelogs = battle.logs || [];
const logMessage = logs.slice(-5).map((log) => `${log}`).join("\n"); const logMessage = battlelogs.slice(-5).map((log) => `${log}`).join("\n");
// Сообщение с информацией // Сообщение с информацией
logs(ctx, "Атака", { enemyId: battle.enemy });
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` +
@ -1846,16 +1869,19 @@ rpg.action(/hit_\d+/, async (ctx) => {
const battle = await Battle.findByPk(battleId); const battle = await Battle.findByPk(battleId);
if (!battle || battle.status !== "active") { if (!battle || battle.status !== "active") {
logs(ctx, "Сражение завершено или не существует", { battleId });
return ctx.reply("Сражение завершено или не существует."); return ctx.reply("Сражение завершено или не существует.");
} }
const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } }); const character = await CharacterModel.findOne({ where: { telegram_id: ctx.from.id } });
if (!character || battle.character != ctx.from.id) { if (!character || battle.character != ctx.from.id) {
logs(ctx, "Персонаж не найден или не участвует в битве", { telegramId: ctx.from.id, battleId });
return ctx.reply("Это не ваша битва."); return ctx.reply("Это не ваша битва.");
} }
const enemy = await Enemy.findByPk(battle.enemy); const enemy = await Enemy.findByPk(battle.enemy);
if (!enemy) { if (!enemy) {
logs(ctx, "Противник не найден", { enemyId: battle.enemy });
return ctx.reply("Противник не найден."); return ctx.reply("Противник не найден.");
} }
@ -1872,6 +1898,7 @@ rpg.action(/hit_\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();
logs(ctx, "Победа персонажа", { enemy, battle });
return ctx.editMessageText(`🎉 ${character.name} победил ${enemy.name}!`); return ctx.editMessageText(`🎉 ${character.name} победил ${enemy.name}!`);
} }
@ -1881,19 +1908,21 @@ rpg.action(/hit_\d+/, async (ctx) => {
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 logMessage = battle.logs.slice(-5).map((log) => `${log}`).join("\n");
logs(ctx, "Попадание", { enemy, battle, damage });
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` +
`⚔️ Урон врага: ${enemy.damage}\n\n` + `⚔️ Урон врага: ${enemy.damage}\n\n` +
`📜 Логи битвы:\n${logs || "Пока ничего не произошло."}\n\n` + `📜 Логи битвы:\n${logMessage|| "Пока ничего не произошло."}\n\n` +
`🎯 Выберите цель для атаки:`, `🎯 Выберите цель для атаки:`,
keyboard keyboard
); );
}); });
function generateBattleButtons(character, battle) { function generateBattleButtons(character, battle) {
let ctx = { from: { id: character.telegram_id } };
const totalButtons = 10; const totalButtons = 10;
const intelligenceFactor = Math.min(character.intelligence || 1, totalButtons - 2); // Уменьшаем на 2 для кнопки критического удара и гарантированного промаха const intelligenceFactor = Math.min(character.intelligence || 1, totalButtons - 2); // Уменьшаем на 2 для кнопки критического удара и гарантированного промаха
const buttons = []; const buttons = [];
@ -1934,7 +1963,7 @@ function generateBattleButtons(character, battle) {
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));
} }
logs(ctx, "Генерация кнопок для битвы", { battle, keyboard: rows });
return rows; return rows;
} }
@ -1982,13 +2011,13 @@ rpg.action(/critical_\d+/, async (ctx) => {
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 logMessage = battle.logs.slice(-5).map((log) => `${log}`).join("\n");
logs(ctx, "Критический удар", { enemy, battle, damage });
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` +
`⚔️ Урон врага: ${enemy.damage}\n\n` + `⚔️ Урон врага: ${enemy.damage}\n\n` +
`📜 Логи битвы:\n${logs || "Пока ничего не произошло."}\n\n` + `📜 Логи битвы:\n${logMessage|| "Пока ничего не произошло."}\n\n` +
`🎯 Выберите цель для атаки:`, `🎯 Выберите цель для атаки:`,
keyboard keyboard
); );
@ -2024,17 +2053,19 @@ rpg.action(/miss_\d+/, async (ctx) => {
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 logMessage = battle.logs.slice(-5).map((log) => `${log}`).join("\n");
if (character.hp <= 0) { if (character.hp <= 0) {
logs(ctx, "Поражение персонажа", { enemy, battle });
return ctx.editMessageText( return ctx.editMessageText(
`💔 ${character.name} потерпел поражение от ${enemy.name}!\n\n📜 Логи битвы:\n${logs}` `💔 ${character.name} потерпел поражение от ${enemy.name}!\n\n📜 Логи битвы:\n${logs}`
); );
} }
logs(ctx, "Промах", { enemy, battle });
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` +
`⚔️ Урон врага: ${enemy.damage}\n\n` + `⚔️ Урон врага: ${enemy.damage}\n\n` +
`📜 Логи битвы:\n${logs || "Пока ничего не произошло."}\n\n` + `📜 Логи битвы:\n${logMessage|| "Пока ничего не произошло."}\n\n` +
`🎯 Выберите цель для атаки:`, `🎯 Выберите цель для атаки:`,
keyboard keyboard
); );