// Подключаем необходимые библиотеки const { Telegraf, Scenes, session, Markup, Stage } = require('telegraf'); const { Op } = require('sequelize'); const schedule = require('node-schedule'); const sequelize = require('./db'); // Подключение базы данных // Подключаем обработчики const commands = require('./commands'); const utils = require('./utils'); const handlers = require('./handlers'); const { UserModel, WorldModel, JobModel, PropertyModel, AFKPropertyModel, BusinessModel, ReportModel, BlockModel, PromocodeModel, EnterpriseModel, WarehouseModel, TruckModel, SaleModel, ResourcePriceModel, SkillsModel, DailyModel, logMiddleware, logs } = global.config const bot = new Telegraf(process.env.BOT_TOKEN) const rpg = require('./rpg'); // Подключение RPG-механик const crime = require('./scenes/crime') const pocketsteal = require('./scenes/pocketsteal') const shop = require('./scenes/shop') const pve = require('./scenes/pve') const newpve = require('./scenes/newpve') const stage = new Scenes.Stage([crime, pocketsteal, shop, pve, newpve]); const start = async () => { try { // Подключаемся к базе данных await sequelize.authenticate(); console.log('Подключение к базе данных успешно!'); // Синхронизация моделей, если нужно await sequelize.sync({ alter: true }); console.log('Синхронизация моделей завершена.'); // Запуск бота console.log('Бот успешно запущен!'); } catch (error) { console.error('Ошибка при запуске приложения:', error); } } bot.telegram.setMyCommands([{ command: "pay", description: "Перевести указанному пользователю сумму." }, { command: "buy", description: "Приобрести указанное имущество." }, { command: "business", description: "Создать организацию." }, { command: "invite", description: "Пригласить пользователя в организацию." }, { command: "percent", description: "Установить пользователю процент заработка." }, { command: "report", 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(rpg) bot.use( session({ getSessionKey: (ctx) => { if ((ctx.from && ctx.chat && ctx.chat.id === ctx.from.id) || (!ctx.chat && ctx.from)) { return `user:${ctx.from.id}` } else if (ctx.from && ctx.chat) { return `${ctx.from.id}:${ctx.chat.id}` } return ctx.update.update_id } }) ) bot.use(stage) bot.use(utils.stats) bot.use(async (ctx, next) => { bot.context.config = require('./ctxconfig.json') let id = ctx.from.id let username = ctx.from.username if (username == null) username = ctx.from.id switch (ctx.updateType) { case `message`: console.log(utils.getCurrentTime() + `: ` + username + `: ` + ctx.update.message.text) break; case `callback_query`: console.log(utils.getCurrentTime() + `: ${username}: ${ctx.update.callback_query.data}`) break; default: console.log(ctx) } let user = await UserModel.findByPk(id); let block = await BlockModel.findOne({ where: { telegram_id: id }, // Здесь id — это значение telegram_id, переданное в функцию }); let property = await PropertyModel.findByPk(id); let skill = await SkillsModel.findByPk(ctx.from.id) if (!user) ctx.reply(`❕ Первичная регистрация профиля.`); if (user === null) { await UserModel.create({ telegram_id: id, username: username, name: ctx.from.first_name }) } else { user.name = ctx.from.first_name if (user.username === null) user.username = ctx.from.id user.save() } if (property === null) { await PropertyModel.create({ telegram_id: id }) } if (skill === null) { await SkillsModel.create({ telegram_id: id, stealing: { level: 1, exp: 0 } }) } //if (whitelist.includes(id) == false) return ctx.reply(`У вас пока нет доступа к боту. Следите за обновлениями в группе: t.me/CampFireGameBotNews`) if (block) { const currentTime = Math.trunc(Date.now() / 1000); // Получаем текущее время в секундах if (block.isBlocked && block.time > currentTime) { const remainingTime = Math.trunc((block.time - currentTime) / 60); // Рассчитываем оставшееся время return ctx.reply( `📛 У вас активная блокировка по причине: ${block.reason}.\n⏲️ Оставшееся время: ${remainingTime} мин.` ); } // Если блокировка истекла или отключена block.isBlocked = false; await block.save(); // Обязательно используем `await` для сохранения изменений } const start = Date.now() const timeoutPromise = new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('timeout')) }, 1000 * 5) }) const nextPromise = next() .then(() => { const ms = Date.now() - start }) .catch((error) => { handleError(error, ctx) }) return Promise.race([timeoutPromise, nextPromise]) .catch((error) => { if (error.message === 'timeout') { console.error('timeout', ctx.update) return false } return true }) }) bot.command('start', async (ctx) => { if (ctx.payload) { let id = ctx.from.id let user = await UserModel.findByPk(id); if (user.level == 1) { let ref = await UserModel.findByPk(ctx.payload) let world = await WorldModel.findByPk(1) world.balance -= 25000 ref.money += Number(25000) await ref.save() await world.save() bot.telegram.sendMessage(ref.telegram_id, `${ctx.from.username} зарегистрировался по вашей реферальной ссылке. Получено ¤25.000`) console.log("Transaction to Ref") } else { console.log("Exist") } } return await ctx.reply('Главное меню', Markup .keyboard([ ['😎 Профиль'], // Row1 with 2 buttons ['🗄️ Работать', '🌐 Организация', '🏗️ Предприятия', '🏯 Казино'], // Row2 with 2 buttons ['CampFireGG.Crime'], ['🎁 Бонус'], ['📦 Контейнеры'], ['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'], ['🛡️ Test'], ]) .resize() ) }) bot.hears('🛡️ Test', async (ctx) => { const buttons = [ [Markup.button.callback('PVE', 'locations')], ]; ctx.reply(`🚨 Добро пожаловать в тестовый режим 🚨\nВесь функционал в этом режиме еще не сбалансирован\n`, Markup.inlineKeyboard(buttons)); }) bot.command('profile', (ctx) => { return ctx.reply('👤 Ваш профиль:', { reply_markup: { inline_keyboard: [ [ { text: "Открыть профиль", web_app: { url: "https://web-bot.campfiregg.ru/" }, // Замените на ваш URL }, ], ], }, }); }); bot.hears('промка', async (ctx) => { generatePromo() }); bot.hears('▶️ Меню', commands.menu); bot.hears('Чат', async (ctx) => { ctx.reply(`${ctx.message.chat.id}`) }); bot.hears('😎 Профиль', commands.profile); bot.command('getprofile', commands.getprofile); bot.hears('Рандом', async (ctx) => { let users = await UserModel.findAll(); let chosenOne = users.random() return ctx.reply(` 👤 ${chosenOne.username} 🆔: ${chosenOne.telegram_id} `); }); bot.hears('💳 Баланс', async (ctx) => { let user = await UserModel.findByPk(ctx.from.id); return ctx.reply(` ⏩ Аккаунт игрока ${user.username} 🆔 Игрока: ${user.telegram_id} 📶 Уровень: ${user.level} ⏩ Повышается за различные действия. 💰 Баланс: ¤${user.money} `); }) bot.hears('🎁 Бонус', commands.bonus) bot.hears('Гараж', commands.garage) bot.hears('Гонка', commands.race) bot.command('pay', commands.pay) bot.hears('Мир', commands.worldMenu) bot.hears('📞 Пригласить', commands.referal) bot.hears('📢 Вакансии', commands.jobs) bot.action(/job_(1|2|3|4|5|6|7|leave)/, commands.chooseJob) bot.hears('🏯 Казино', commands.casinoMenu) bot.hears('🗄️ Работать', commands.work) bot.hears('Топ', commands.top) bot.hears('🔵 Имущество', commands.propertyMenu) bot.action('shopmenu', commands.propertyMenu) bot.action(/shop_(house|phone|car)/, commands.propertyList) bot.action(/{"action": "buy"*/, commands.propertyBuy) bot.hears('Поставщик', commands.hatkeisList) bot.command('sell', commands.propertySell) bot.hears('🌐 Организация', commands.organizationMenu) bot.action('workoff', commands.workoff) bot.action('покинуть', commands.leaveOrg) bot.action('cancel', async (ctx) => { await ctx.deleteMessage() await bot.telegram.answerCbQuery(ctx.callbackQuery.id, `Отмена.`) }) bot.action('user_leave_business', commands.leaveOrgAccept) bot.action('payday', commands.payday) bot.command('orgmessage', commands.orgMessage) bot.command('materials', commands.materialsBuy) bot.command('percent', commands.percentSet) bot.command('business', commands.organizationCreate) bot.command('invite', commands.invite) bot.action(/{"type": "business_invite_(accept|refuse)"*/, commands.inviteAction) bot.command('report', commands.report) bot.hears('🎰 Слоты', commands.slotsMenu) // bot.action(/slots(1000|5000|25000|50000|100000)/, commands.slotsRun) bot.hears('Помощь', async (ctx) => { return await ctx.replyWithMarkdownV2(`• [Функционал](https://telegra.ph/CampFire-Bot-Info-09-25)\n• [Правила](https://telegra.ph/PRAVILA-BOTA-09-25)`, { disable_web_page_preview: true }) }) bot.command('promocode', commands.promocodeActivate) bot.hears('📦 Контейнеры', commands.carContainers) bot.action(/container_(1|2|3|4|5|6|7|8|9|10)/, commands.chooseContainer) bot.action(/{"action": "sueta_*/, async (ctx) => { let data = ctx.update.callback_query.data; data = JSON.parse(data) console.log(data.car) let user = await UserModel.findByPk(ctx.from.id) let property = await PropertyModel.findByPk(ctx.from.id) switch (data.action) { case `sueta_accept`: user.money += data.carprice await ctx.editMessageText(`➕ ${data.carprice}`) break; case `sueta_refuse`: user.money += Math.round(property.car.price / 2) property.car = { name: data.carname, price: data.carprice } await ctx.editMessageText(`➕ ${data.carname}`) break; } user.save() property.save() }) bot.action(/dissolve_organization_(\d+)/, async (ctx) => { try { const businessId = parseInt(ctx.match[1], 10); const business = await BusinessModel.findByPk(businessId); if (!business) { return ctx.answerCbQuery('Организация не найдена.', { show_alert: true }); } const user = await UserModel.findByPk(ctx.from.id); if (business.owner != ctx.from.id) { return ctx.answerCbQuery('Только владелец может ликвидировать организацию.', { show_alert: true }); } // Расчет и передача 25% от баланса владельцу const payout = Math.floor(business.balance * 0.25); user.money += payout; user.business = { id: 0, checks: 0, percent: 0 }; await user.save(); // Сброс бизнес-данных у участников const members = await UserModel.findAll({ where: { 'business.id': businessId, }, }); for (const member of members) { member.business = { id: 0, checks: 0, percent: 0 }; await member.save(); } logs(ctx, `Ликвидация организации ${business.name}`, { businessId, payout }); // Удаление организации await business.destroy(); await ctx.reply(`❌ Организация "${business.name}" ликвидирована. Вы получили ₽${spaces(payout)}.`); } catch (error) { console.error('Ошибка при ликвидации организации:', error); return ctx.reply('Произошла ошибка. Попробуйте снова.'); } }); bot.command('daily_bonus', async (ctx) => { try { const user = await UserModel.findByPk(ctx.from.id); const currentDate = new Date(); const day = currentDate.getDate(); // Проверяем, заходил ли пользователь сегодня const lastLoginDate = new Date(user.lastLogin); if ( lastLoginDate.getFullYear() === currentDate.getFullYear() && lastLoginDate.getMonth() === currentDate.getMonth() && lastLoginDate.getDate() === day ) { return ctx.reply('Вы уже получили награду за сегодня! Возвращайтесь завтра.'); } // Получение награды из базы const reward = await DailyModel.findOne({ where: { day } }); if (!reward) { return ctx.reply('На сегодня награды не настроены. Обратитесь к администратору.'); } // Обработка награды let totalMoney = reward.money; let message = `🎉 Награда за ${day} число:\n`; if (reward.experience > 0) { user.exp += reward.experience; message += `✨ Опыт: ${reward.experience}\n`; } if (user.business.id > 0) { user.materials += reward.materials; message += `🏗 Материалы: ${reward.materials}\n`; } else { totalMoney += reward.materials; // Материалы заменяются на деньги } // Добавляем деньги user.money += totalMoney; message += `💰 Деньги: ${totalMoney}\n`; // Обновляем прогресс //user.lastLogin = currentDate; user.loginStreak = (lastLoginDate.getDate() === day - 1) ? user.loginStreak + 1 : 1; await user.save(); // Отправляем сообщение await ctx.reply(`${message}\n🔥 Ваша серия входов: ${user.loginStreak} дней.`); } catch (error) { console.error('Ошибка при выдаче ежедневного бонуса:', error); return ctx.reply('Произошла ошибка. Попробуйте снова.'); } }); bot.command('daily', async (ctx) => { try { // Получаем данные пользователя const user = await UserModel.findByPk(ctx.from.id); // Создаем клавиатуру с кнопкой перехода в мини-приложение const keyboard = { inline_keyboard: [ [ { text: '🎁 Ежедневный бонус', web_app: { url: 'https://web-bot.campfiregg.ru/daily' } // Замените на URL мини-приложения } ] ] }; // Отправляем сообщение с кнопкой await ctx.reply('👋 Добро пожаловать в раздел ежедневных наград! Нажмите на кнопку ниже, чтобы открыть календарь и получить сегодняшнюю награду.', { reply_markup: keyboard }); } catch (error) { console.error('Ошибка при открытии ежедневного бонуса:', error); return ctx.reply('Произошла ошибка. Попробуйте снова.'); } }); /////////////////////////////////////Enterprise Update 20.12.2024////////////////////////////////////////////////// // Обновление меню "Предприятия" bot.hears('🏗️ Предприятия', async (ctx) => { try { const user = await UserModel.findByPk(ctx.from.id); if (!user) { console.error('Ошибка: пользователь не найден'); return await ctx.reply('Ошибка: пользователь не найден.'); } const warehouse = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } }); const enterprises = await EnterpriseModel.findAll({ where: { playerId: user.telegram_id } }); let message = `🏗️ Меню предприятий:\n`; message += `У вас: ${enterprises.length} предприятий.\n`; message += warehouse ? `🗄️ Единый склад: Доступен (Ёмкость: ${warehouse.capacity} ед.)\n` : `🗄️ Единый склад: Не построен.\n`; const buttons = []; buttons.push([{ text: '🏭 Мои предприятия', callback_data: 'my_enterprises' }]); buttons.push([{ text: '🛠️ Построить предприятие', callback_data: 'build_enterprise' }]); if (warehouse) { buttons.push([{ text: '🚛 Управление складом', callback_data: 'manage_warehouse' }]); } else { buttons.push([{ text: '🗄️ Построить склад', callback_data: 'buy_warehouse' }]); } buttons.push([{ text: '💰 Продать ресурсы', callback_data: 'sell_resources' }]); return await ctx.reply(message, Markup.inlineKeyboard(buttons).resize()); } catch (error) { console.error('Ошибка при выполнении команды "🏗️ Предприятия":', error); return await ctx.reply('Произошла ошибка при выполнении команды. Попробуйте позже.'); } }); bot.action('enterprise_menu', async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); const warehouse = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } }); const enterprises = await EnterpriseModel.findAll({ where: { playerId: user.telegram_id } }); let message = `🏗️ Меню предприятий:\n`; message += `У вас: ${enterprises.length} предприятий.\n`; message += warehouse ? `🗄️ Единый склад: Доступен (Ёмкость: ${warehouse.capacity} ед.)\n` : `🗄️ Единый склад: Не построен.\n`; const buttons = []; // Добавляем кнопки для предприятий buttons.push([{ text: '🏭 Мои предприятия', callback_data: 'my_enterprises' }]); buttons.push([{ text: '🛠️ Построить предприятие', callback_data: 'build_enterprise' }]); // Кнопка для управления или постройки склада if (warehouse) { buttons.push([{ text: '🚛 Управление складом', callback_data: 'manage_warehouse' }]); } else { buttons.push([{ text: '🗄️ Построить склад', callback_data: 'buy_warehouse' }]); } buttons.push([{ text: '💰 Продать ресурсы', callback_data: 'sell_resources' }]) // Возвращаем меню с кнопками return await ctx.editMessageText(message, Markup.inlineKeyboard(buttons).resize()); }); // Функция для преобразования типа ресурса в эмодзи function getEnterpriseEmoji(resourceType) { const emojis = { wood: '🌳', coal: '⛏️', oil: '🛢️', metall: '⚒️', gold: '💰', diamond: '💎' } return emojis[resourceType] || '🏭' } bot.action('my_enterprises', async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); const enterprises = await EnterpriseModel.findAll({ where: { playerId: user.telegram_id } }); if (enterprises.length === 0) { return await ctx.reply('У вас нет предприятий.'); } let metallPrice = await ResourcePriceModel.findOne({ where: { resource: "metall" } }); let message = `🏭 Мои предприятия:\n\n`; const buttons = []; for (const enterprise of enterprises) { const { id, name, level, efficiency, currentResources, resourceType, warehouseCapacity } = enterprise; const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: resourceType } }); let price = resourcePrice.price * 1.5 * 10 * 24 * 7 // Стоимость улучшения зависит от уровня message += `🔹 [ID: ${id}] ${getEnterpriseEmoji(resourceType)} ${name} st. ${level}\n └── ${currentResources}/${warehouseCapacity} [${efficiency} ед/ч]\n └──📈 ${utils.spaces(price)} руб.\n\n`; const truck = await TruckModel.findOne({ where: { enterpriseId: id } }); const warehouse = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } }); const enterpriseButtons = [ { text: `ID: 📈 ${id}`, callback_data: `upgrade_${id}` }, ]; if (!truck) { enterpriseButtons.push({ text: `🛻 ID: ${id}`, callback_data: `hire_truck_${id}` }); } else { enterpriseButtons.push({ text: `🚛 ID: ${id}`, callback_data: `upgrade_truck_${id}` }); } enterpriseButtons.push({ text: `💰 ID: ${id}`, callback_data: `sell_all_${id}` }); if (warehouse) { enterpriseButtons.push({ text: `🔄 ID: ${id}`, callback_data: `transfer_from_${id}` }); } enterpriseButtons.push({ text: `🚫 ID: ${id}`, callback_data: `sell_enterprise_${id}` }); buttons.push(enterpriseButtons); } message += `\n\n📈 - Улучшить\n🛻 - Купить грузовик [~${utils.spaces(metallPrice.price * 700)} руб.]\n🚛 - Улучшить грузовик\n💰 - Продать ресурсы с предприятия\n🔄 - Перевезти все на склад` buttons.push([{ text: '⬅️ Назад', callback_data: 'enterprise_menu' }]); return await ctx.editMessageText(message, Markup.inlineKeyboard(buttons).resize()); }); // Построение предприятия bot.action('build_enterprise', async (ctx) => { try { const user = await UserModel.findByPk(ctx.from.id); if (!user) { return await ctx.reply('Пользователь не найден.'); } const enterprises = await EnterpriseModel.findAll({ where: { playerId: user.telegram_id } }); if (enterprises.length >= 5) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, 'Вы достигли максимального числа предприятий.', { show_alert: true }); } // Получаем текущие цены из базы данных const resourcePrices = await ResourcePriceModel.findAll(); if (!resourcePrices || resourcePrices.length === 0) { return await ctx.reply('Цены на ресурсы отсутствуют. Пожалуйста, попробуйте позже.'); } let message = `🛠️ Постройка предприятия:\n`; const buttons = []; for (const resource of resourcePrices) { const resourceName = getReadableType(resource.resource); const resourceEmoji = getEnterpriseEmoji(resource.resource); message += `${resourceEmoji} ${resourceName}: ${utils.spaces(Math.round(resource.price * 1.5 * 10 * 24 * 7))} руб.\n`; // Генерируем кнопки для каждого ресурса buttons.push([ { text: resourceEmoji, callback_data: `build_${resource.resource}` } ]); } message += '\nВыберите тип предприятия:'; buttons.push([{ text: '⬅️ Назад', callback_data: 'enterprise_menu' }]); return await ctx.editMessageText(message, Markup.inlineKeyboard(buttons).resize()); } catch (error) { console.error('Ошибка в build_enterprise:', error); return await ctx.reply('Произошла ошибка при обработке запроса. Попробуйте снова.'); } }); // Построение предприятия по выбранному типу bot.action(/build_(wood|coal|oil|metall|gold|diamond)/, async (ctx) => { let user = await UserModel.findByPk(ctx.from.id) let data = ctx.update.callback_query.data let type = data.split('_')[1] // Получаем текущие цены из базы данных const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: type } }); let price = resourcePrice.price * 1.5 * 10 * 24 * 7 // Проверка, есть ли достаточно денег у пользователя if (user.money < price) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, `У вас недостаточно средств для постройки предприятия. Необходимо ${utils.spaces(price)} руб.`, { show_alert: true }) } // Строим предприятие let enterpriseName = `${user.username}'s ${getReadableType(type)}` // Название предприятия let enterprise = await EnterpriseModel.create({ name: enterpriseName, resourceType: type, playerId: user.telegram_id, level: 1, efficiency: 10, warehouseCapacity: 100 }) // Снимаем деньги с баланса await user.update({ money: user.money - price }) return await ctx.editMessageText(`Предприятие ${enterprise.name} (ID: ${enterprise.id}) построено!`) }) // Запрашиваем подтверждение на продажу предприятия bot.action(/sell_enterprise_(\d+)/, async (ctx) => { try { const enterpriseId = parseInt(ctx.match[1], 10); const enterprise = await EnterpriseModel.findByPk(enterpriseId); if (!enterprise) { return await ctx.reply('Предприятие не найдено.'); } const user = await UserModel.findByPk(ctx.from.id); if (enterprise.playerId !== user.telegram_id) { return await ctx.reply('Это не ваше предприятие.'); } // Получаем информацию о наличии грузовика у предприятия и его уровень const truck = await TruckModel.findOne({ where: { enterpriseId: enterprise.id } }); const truckLevel = truck ? truck.level : 0; const metallPrice = await ResourcePriceModel.findOne({ where: { resource: 'metall' } }); const truckPrice = metallPrice.price * 700 * truckLevel; // Получаем текущую стоимость предприятия const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: enterprise.resourceType } }); const price = Math.round(resourcePrice.price * 1.5 * 5 * 24 * 7 * enterprise.level + truckPrice * 0.5); return await ctx.reply(`Вы уверены, что хотите продать предприятие ${enterprise.name} за ${utils.spaces(price)} руб?`, Markup.inlineKeyboard([ [{ text: '✅ Да', callback_data: `confirm_enterprise_${enterpriseId}` }], [{ text: '❌ Нет', callback_data: 'enterprise_menu' }] ]).resize()); } catch (error) { console.error('Ошибка при запросе на продажу предприятия:', error); return await ctx.reply('Произошла ошибка при запросе на продажу предприятия. Попробуйте позже.'); } }); // Продажа предприятия bot.action(/confirm_enterprise_(\d+)/, async (ctx) => { try { const enterpriseId = parseInt(ctx.match[1], 10); const enterprise = await EnterpriseModel.findByPk(enterpriseId); if (!enterprise) { return await ctx.reply('Предприятие не найдено.'); } const user = await UserModel.findByPk(ctx.from.id); if (enterprise.playerId !== user.telegram_id) { return await ctx.reply('Это не ваше предприятие.'); } // Получаем информацию о наличии грузовика у предприятия и его уровень const truck = await TruckModel.findOne({ where: { enterpriseId: enterprise.id } }); const truckLevel = truck ? truck.level : 1; const metallPrice = await ResourcePriceModel.findOne({ where: { resource: 'metall' } }); const truckPrice = metallPrice.price * 700 * truckLevel; // Получаем текущую стоимость предприятия const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: enterprise.resourceType } }); console.log() const price = Math.round(resourcePrice.price * 1.5 * 5 * 24 * 7 * enterprise.level + truckPrice * 0.5); // Продаем предприятие await enterprise.destroy(); // Удаляем грузовик await TruckModel.destroy({ where: { enterpriseId: enterprise.id } }); await user.update({ money: user.money + price }); return await ctx.reply(`Предприятие ${enterprise.name} продано за ${utils.spaces(price)} руб.`); } catch (error) { console.error('Ошибка при продаже предприятия:', error); return await ctx.reply('Произошла ошибка при продаже предприятия. Попробуйте позже.'); } }); // Функция для преобразования типа ресурса в читаемое название function getReadableType(type) { const names = { wood: 'Деревообрабатывающее предприятие', coal: 'Угольное предприятие', oil: 'Нефтяное предприятие', metall: 'Металлургическое предприятие', gold: 'Золотое предприятие', diamond: 'Алмазное предприятие' } return names[type] || type } function getReadableResourceType(type) { const names = { wood: 'Дерево', coal: 'Уголь', oil: 'Нефть', metall: 'Металл', gold: 'Золото', diamond: 'Алмазы' } return names[type] || type } bot.action('buy_warehouse', async (ctx) => { try { // Получаем пользователя let user = await UserModel.findByPk(ctx.from.id); if (!user) { return await ctx.reply('Произошла ошибка. Пользователь не найден.'); } // Получаем цены на металл и дерево const woodPrice = await ResourcePriceModel.findOne({ where: { resource: 'wood' } }); const metallPrice = await ResourcePriceModel.findOne({ where: { resource: 'metall' } }); if (!woodPrice || !metallPrice) { return await ctx.reply('Не удалось получить цены на ресурсы. Попробуйте позже.'); } // Формируем стоимость склада const warehouseBaseCost = 10; // Коэффициент для расчёта const warehouseCost = Math.round( (woodPrice.price + metallPrice.price) * warehouseBaseCost * 24 * 7 ); // Проверяем, хватает ли денег у пользователя if (user.money < warehouseCost) { return await ctx.telegram.answerCbQuery( ctx.callbackQuery.id, `У вас недостаточно средств для покупки склада. Необходимо: ${utils.spaces(warehouseCost)} руб.`, { show_alert: true } ); } // Создаём склад await WarehouseModel.create({ playerId: user.telegram_id, capacity: 1000, // Начальная ёмкость wood: 0, coal: 0, oil: 0, metall: 0, gold: 0, diamond: 0, }); // Списываем деньги await user.update({ money: user.money - warehouseCost }); // Уведомление об успешной покупке return await ctx.reply( `Вы успешно купили единый склад за ${warehouseCost} руб!` ); } catch (error) { console.error('Ошибка при покупке склада:', error); return await ctx.reply('Произошла ошибка при покупке склада. Попробуйте позже.'); } }); // Управление складом bot.action('manage_warehouse', async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); const warehouse = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } }); if (!warehouse) { return await ctx.reply('У вас нет склада для управления.'); } let message = `🚛 Управление складом:\n`; message += `Общая ёмкость: ${warehouse.capacity} ед.\n`; message += `Хранимые ресурсы:\n`; message += `🌲 Дерево: ${warehouse.wood || 0}\n`; message += `⛏️ Уголь: ${warehouse.coal || 0}\n`; message += `🛢️ Нефть: ${warehouse.oil || 0}\n`; message += `⚙️ Металл: ${warehouse.metall || 0}\n`; message += `🥇 Золото: ${warehouse.gold || 0}\n`; message += `💎 Алмазы: ${warehouse.diamond || 0}\n`; const buttons = [ [{ text: '➕ Перевести ресурсы', callback_data: 'transfer_resources' }] ]; buttons.push([{ text: '⬅️ Назад', callback_data: 'enterprise_menu' }]); return await ctx.editMessageText(message, Markup.inlineKeyboard(buttons).resize()); }); bot.action('transfer_resources', async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); const warehouse = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } }); if (!warehouse) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, 'У вас нет единого склада.'); } const enterprises = await EnterpriseModel.findAll({ where: { playerId: user.telegram_id } }); let message = `➕ Перевозка ресурсов:\n`; message += `Общая ёмкость склада: ${warehouse.capacity} ед.\n`; message += `Выберите предприятие для перевозки ресурсов:`; const buttons = enterprises.map(ent => { return [{ text: `🏭 ${ent.name}`, callback_data: `transfer_from_${ent.id}` }]; }); buttons.push([{ text: '⬅️ Назад', callback_data: 'enterprise_menu' }]); return await ctx.editMessageText(message, Markup.inlineKeyboard(buttons).resize()); }); // Перевозка с конкретного предприятия bot.action(/transfer_from_(\d+)/, async (ctx) => { const enterpriseId = ctx.match[1]; const enterprise = await EnterpriseModel.findByPk(enterpriseId); if (!enterprise) { return await ctx.editMessageText('Предприятие не найдено.'); } const { currentResources, resourceType, playerId } = enterprise; if (currentResources === 0) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, 'На предприятии нет ресурсов для перевода.'); } const warehouse = await WarehouseModel.findOne({ where: { playerId } }); if (!warehouse) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, 'У вас нет склада для перевода ресурсов.'); } const freeCapacity = warehouse.capacity - getWarehouseUsedCapacity(warehouse); const transferAmount = Math.min(currentResources, freeCapacity); if (transferAmount === 0) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, 'Склад заполнен. Перевод невозможен.'); } // Перевод ресурсов warehouse[resourceType] = (warehouse[resourceType] || 0) + transferAmount; enterprise.currentResources -= transferAmount; await warehouse.save(); await enterprise.save(); return await ctx.reply( `Успешно переведено ${transferAmount} ед. ${resourceType} с предприятия в склад.` ); }); bot.command('ent_rename', async (ctx) => { let args = ctx.message.text.split(' ').slice(1) if (args.length < 2) { return await ctx.reply('Использование: /ent_rename <Новое название>') } let enterpriseId = parseInt(args[0]) let newName = args.slice(1).join(' ') let enterprise = await EnterpriseModel.findByPk(enterpriseId) if (!enterprise) { return await ctx.reply(`Предприятие с ID ${enterpriseId} не найдено.`) } // Переименовываем предприятие await enterprise.update({ name: newName }) return await ctx.reply(`Предприятие (ID: ${enterprise.id}) переименовано в "${newName}".`) }) bot.action(/upgrade_(\d+)/, async (ctx) => { let user = await UserModel.findByPk(ctx.from.id) let enterpriseId = ctx.match[1] let enterprise = await EnterpriseModel.findByPk(enterpriseId) if (!enterprise) return await ctx.reply(`Предприятие не найдено.`) const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: enterprise.resourceType } }); let upgradeCost = resourcePrice.price * 1.5 * 10 * 24 * 7 // Стоимость улучшения зависит от уровня if (user.money < upgradeCost) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, `У вас недостаточно средств для прокачки предприятия. Необходимо ${upgradeCost} руб.`) } if(enterprise.level >= 5) { return await ctx.reply('Предприятие уже достигло максимального уровня.') } // Прокачка: повышение уровня и эффективности await enterprise.update({ level: enterprise.level + 1, efficiency: enterprise.efficiency + 10, warehouseCapacity: enterprise.warehouseCapacity + 110 }) // Снимаем деньги с баланса await user.update({ money: user.money - upgradeCost }) return await ctx.editMessageText(`Предприятие ${enterprise.name} успешно прокачано! Уровень: ${enterprise.level}, Производительность: ${enterprise.efficiency} ед/ч.`) }) // Показ списка предприятий bot.action('sell_resources', async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); const enterprises = await EnterpriseModel.findAll({ where: { playerId: user.telegram_id } }); if (enterprises.length === 0) { return await ctx.reply('❌ У вас нет предприятий для продажи ресурсов.'); } let message = `📜 Список ваших предприятий и их ресурсы:\n\n`; enterprises.forEach((enterprise, index) => { message += `${index + 1}. ${enterprise.name} (${enterprise.resourceType}): ${enterprise.currentResources} единиц\n`; }); message += `\n📦 Продажа ресурсов:\n`; message += `• Для продажи ресурсов с предприятия используйте команду:\n/sellres [номер_предприятия] [количество]\nПример: /sellres 1 50\n\n`; message += `• Для продажи ресурсов со склада используйте команду:\n/sellstorage [тип_ресурса (wood/coal/oil/metall/gold/diamond)] [количество]\nПример: /sellstorage wood 10`; return await ctx.reply(message, { parse_mode: 'HTML', reply_markup: { inline_keyboard: [ [{ text: '↩ Назад', callback_data: 'enterprise_menu' }] ] } }); }); // Обработка продажи ресурсов bot.command('sellres', async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); const [enterpriseId, amountToSell] = ctx.message.text.split(' ').slice(1); if (!enterpriseId || !amountToSell) { return await ctx.reply('Неверный формат команды. Пример: /sellres 1 50'); } const enterprise = await EnterpriseModel.findByPk(enterpriseId, { where: { playerId: user.telegram_id } }); if (!enterprise) { return await ctx.reply('Предприятие с таким id не найдено.'); } const amount = parseInt(amountToSell, 10); if (isNaN(amount) || amount <= 0) { return await ctx.reply('Укажите корректное количество для продажи.'); } if (enterprise.currentResources < amount) { return await ctx.reply( `На предприятии ${enterprise.name} недостаточно ресурсов. Доступно: ${enterprise.currentResources} единиц.` ); } const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: enterprise.resourceType } }); if (!resourcePrice) { return await ctx.reply('Не удалось получить цену ресурса.'); } const totalSale = Math.floor(amount * resourcePrice.price); // Обновляем данные enterprise.currentResources -= amount; await enterprise.save(); user.money += totalSale; await user.save(); // Ослабленная инфляция resourcePrice.price = Math.round( resourcePrice.price * Math.exp(-resourcePrice.fluctuationRate * (amount / 10)) // Дробное уменьшение инфляции ); // Гарантируем, что цена не упадет ниже 50% от базовой цены resourcePrice.price = Math.max(resourcePrice.price, Math.round(resourcePrice.basePrice * 0.5)); await resourcePrice.save(); updateResourcePricesMessage(); return await ctx.reply( `Вы продали ${amount} единиц ${enterprise.resourceType} с предприятия ${enterprise.name} за ${totalSale} руб.\nТекущая цена за единицу: ${resourcePrice.price.toFixed(0)} руб.` ); }); bot.action(/sell_all_(\d+)/, async (ctx) => { const enterpriseId = ctx.match[1]; const enterprise = await EnterpriseModel.findByPk(enterpriseId); if (!enterprise) { return await ctx.reply('Предприятие не найдено.'); } const { currentResources, resourceType, playerId } = enterprise; const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: resourceType } }); const totalPrice = currentResources * resourcePrice.price; if (currentResources === 0) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, 'На предприятии нет ресурсов для продажи.'); } await ctx.reply( `Вы уверены, что хотите продать все ${currentResources} ед. ${resourceType} за ${totalPrice} руб.? Это необратимо!\n\nРекомендуем воспользоваться командой /sell для более гибкого управления продажами.`, Markup.inlineKeyboard([ [ { text: '✅ Продать всё', callback_data: `confirm_ressell_${enterpriseId}` }, { text: '❌ Отмена', callback_data: 'cancel' } ] ]) ); }); bot.action(/confirm_ressell_(\d+)/, async (ctx) => { const enterpriseId = ctx.match[1]; const enterprise = await EnterpriseModel.findByPk(enterpriseId); if (!enterprise) { return await ctx.reply('Предприятие не найдено.'); } const { currentResources, resourceType, playerId } = enterprise; const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: resourceType } }); const totalPrice = currentResources * resourcePrice.price; if (currentResources === 0) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, 'На предприятии нет ресурсов для продажи.'); } // Обновление баланса игрока const user = await UserModel.findByPk(playerId); user.money += totalPrice; enterprise.currentResources = 0; await user.save(); await enterprise.save(); console.log(resourcePrice.price * Math.exp(-resourcePrice.fluctuationRate * (currentResources / 10))) // Ослабленная инфляция resourcePrice.price = Math.round( resourcePrice.price * Math.exp(-resourcePrice.fluctuationRate * (currentResources / 10)) // Дробное уменьшение инфляции ); // Гарантируем, что цена не упадет ниже 50% от базовой цены resourcePrice.price = Math.max(resourcePrice.price, Math.round(resourcePrice.basePrice * 0.5)); await resourcePrice.save(); updateResourcePricesMessage(); await ctx.editMessageText(`Вы успешно продали ${currentResources} ед. ${getEnterpriseEmoji(resourceType)} за ${totalPrice} руб.`); }); // Продажа ресурсов со склада bot.command('sellstorage', async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); const [resourceType, amountToSell] = ctx.message.text.split(' ').slice(1); if (!resourceType || !amountToSell) { return await ctx.reply('Неверный формат команды. Пример: /sellstorage <тип_ресурса> <количество>'); } const storage = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } }); if (!storage || !storage[resourceType]) { return await ctx.reply(`У вас нет ресурсов типа ${resourceType} на складе.`); } const amount = parseInt(amountToSell, 10); if (isNaN(amount) || amount <= 0) { return await ctx.reply('Укажите корректное количество для продажи.'); } if (storage[resourceType] < amount) { return await ctx.reply(`На складе недостаточно ресурсов типа ${resourceType}. Доступно: ${storage[resourceType]} единиц.`); } const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: resourceType } }); if (!resourcePrice) { return await ctx.reply('Не удалось получить цену ресурса.'); } const totalSale = Math.floor(amount * resourcePrice.price); // Обновляем данные storage[resourceType] -= amount; await storage.save(); user.money += totalSale; await user.save(); // Ослабленная инфляция resourcePrice.price = Math.round( resourcePrice.price * Math.exp(-resourcePrice.fluctuationRate * (amount / 10)) // Дробное уменьшение инфляции ); // Гарантируем, что цена не упадет ниже 50% от базовой цены resourcePrice.price = Math.max(resourcePrice.price, Math.round(resourcePrice.basePrice * 0.5)); await resourcePrice.save(); updateResourcePricesMessage(); return await ctx.reply( `Вы продали ${amount} ед. ${resourceType} со склада за ${totalSale} руб.\nТекущая цена за единицу: ${resourcePrice.price.toFixed(0)} руб.` ); }); // Обработка найма грузовика для выбранного предприятия bot.action(/hire_truck_(\d+)/, async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); const enterpriseId = ctx.match[1]; // Находим предприятие const enterprise = await EnterpriseModel.findByPk(enterpriseId); if (!enterprise || enterprise.playerId != user.telegram_id) { return await ctx.reply('Предприятие не найдено или вам не принадлежит.'); } // Проверяем, есть ли уже грузовик для этого предприятия const existingTruck = await TruckModel.findOne({ where: { enterpriseId: enterprise.id } }); if (existingTruck) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, `У вас уже есть грузовик для предприятия ${enterprise.name}.`); } const resourcePrice = await ResourcePriceModel.findOne({ where: { resource: 'metall' } }); if (!resourcePrice) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, 'Не удалось получить цену ресурса.'); } if (user.money < resourcePrice.price * 700) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, `Недостаточно средств. Стоимость грузовика: ${utils.spaces(resourcePrice.price * 700)} руб.`); } await user.update({ money: user.money - (resourcePrice.price * 700) }) // Создаем новый грузовик const newTruck = await TruckModel.create({ enterpriseId: enterprise.id, capacity: 10, // Начальная вместимость efficiency: 1 // Начальная эффективность }); return await ctx.reply( `Вы успешно наняли грузовик для предприятия ${enterprise.name}!` ); }); async function initializePrices() { const resources = [ { resource: 'wood', price: 1000, basePrice: 1000, fluctuationRate: 0.002, recoveryRate: 0.15 }, { resource: 'coal', price: 2000, basePrice: 2000, fluctuationRate: 0.002, recoveryRate: 0.12 }, { resource: 'oil', price: 5000, basePrice: 5000, fluctuationRate: 0.001, recoveryRate: 0.1 }, { resource: 'metall', price: 5000, basePrice: 5000, fluctuationRate: 0.001, recoveryRate: 0.1 }, { resource: 'gold', price: 10000, basePrice: 10000, fluctuationRate: 0.0005, recoveryRate: 0.08 }, { resource: 'diamond', price: 25000, basePrice: 25000, fluctuationRate: 0.0004, recoveryRate: 0.05 }, ]; for (const resource of resources) { await ResourcePriceModel.findOrCreate({ where: { resource: resource.resource }, defaults: resource, }); } } initializePrices(); const recoverResourcePrices = async () => { const resources = await ResourcePriceModel.findAll(); for (const resource of resources) { // Определяем случайное колебание в диапазоне [-maxFluctuation, maxFluctuation] const maxFluctuation = resource.basePrice * 0.3; // 30% от базовой цены const priceFluctuation = (Math.random() * 2 - 1) * maxFluctuation; // Применяем колебание resource.price = Math.round(resource.price + priceFluctuation); // Если цена выше базовой, шанс на её снижение if (resource.price > resource.basePrice) { const chanceToDrop = 0.5; // 50% шанс на снижение if (Math.random() < chanceToDrop) { resource.price -= Math.round(resource.basePrice * 0.1); // Снижение на 1% базовой цены } } // Если цена ниже базовой, восстанавливаем с учётом recoveryRate if (resource.price < resource.basePrice) { resource.price = Math.min( Math.round(resource.price + resource.basePrice * resource.recoveryRate), resource.basePrice // Не превышать базовую цену ); } if (resource.price > resource.basePrice * 2.1) { resource.price = Math.round(resource.basePrice * 0.79764918); // Устанавливаем цену на уровне 1.5 базовой } // Гарантируем, что цена остаётся в диапазоне [50% basePrice, 150% basePrice] resource.price = Math.max(resource.price, Math.round(resource.basePrice * 0.5)); // Минимум resource.price = Math.min(resource.price, Math.round(resource.basePrice * 3)); // Максимум await resource.save(); // Сохраняем после всех корректировок } }; // Функция добычи ресурсов const resourceProduction = async () => { try { // Получаем все предприятия const enterprises = await EnterpriseModel.findAll(); for (const enterprise of enterprises) { const { id, efficiency, warehouseCapacity, resourceType, currentResources, level, playerId } = enterprise; // Расчёт добытых ресурсов const producedResources = efficiency; // Проверяем ёмкость склада предприятия if (currentResources + producedResources <= warehouseCapacity) { enterprise.currentResources += producedResources; await enterprise.save(); console.log( `Предприятие ${id}: добыто ${producedResources} единиц ${resourceType}.` ); } else { console.log(`Предприятие ${id}: склад заполнен.`); } } } catch (error) { console.error('Ошибка добычи ресурсов:', error); } }; // Функция транспортировки ресурсов const resourceTransportation = async () => { try { // Получаем все предприятия const enterprises = await EnterpriseModel.findAll(); for (const enterprise of enterprises) { const { id, name, resourceType, currentResources, playerId } = enterprise; if (currentResources > 0) { // Получаем грузовики, привязанные к предприятию const trucks = await TruckModel.findAll({ where: { enterpriseId: id } }); if (trucks.length === 0) { console.log( `[${id}] ${name}: нет доступных грузовиков для транспортировки.` ); continue; } // Получаем универсальный склад игрока const warehouse = await WarehouseModel.findOne({ where: { playerId } }); if (!warehouse) { console.log( `[${id}] ${name}: у игрока ${playerId} нет универсального склада.` ); continue; } // Транспортировка ресурсов let totalTransported = 0; for (const truck of trucks) { const transportableAmount = Math.min( truck.capacity, // Максимальная вместимость грузовика currentResources, // Доступные ресурсы на предприятии warehouse.capacity - getWarehouseUsedCapacity(warehouse) // Свободное место на складе ); if (transportableAmount > 0) { // Обновляем данные склада warehouse[resourceType] = (warehouse[resourceType] || 0) + transportableAmount; // Уменьшаем ресурсы на предприятии enterprise.currentResources -= transportableAmount; await warehouse.save(); await enterprise.save(); totalTransported += transportableAmount; console.log( `Грузовик ${truck.id} перевёз ${transportableAmount} единиц ${resourceType}.` ); } // Прекращаем, если ресурсы закончились if (enterprise.currentResources === 0) break; } if (totalTransported === 0) { console.log( `[${id}] ${name}: склад заполнен, транспортировка невозможна.` ); } } else { console.log(`[${id}] ${name}: нет ресурсов для транспортировки.`); } } } catch (error) { console.error('Ошибка транспортировки ресурсов:', error); } }; // Расчёт используемой ёмкости склада const getWarehouseUsedCapacity = (warehouse) => { const resources = ['wood', 'coal', 'oil', 'metall', 'gold', 'diamond']; return resources.reduce((sum, resource) => sum + (warehouse[resource] || 0), 0); }; const CHANNEL_ID = '@CampFireGameBotNews'; // Замените на username вашего канала let resourceMessageId = 18; // Хранение ID сообщения const previousPrices = {}; // Объект для хранения предыдущих цен const getResourcePricesText = async () => { const resources = await ResourcePriceModel.findAll(); // Получаем данные из базы let message = '💰 **Актуальные цены на ресурсы:**\n\n'; resources.forEach((resource) => { const currentPrice = resource.price; const previousPrice = previousPrices[resource.resource] || currentPrice; // Берем предыдущую цену или текущую, если нет данных // Определяем эмодзи изменения цены let trendEmoji = '⚖️'; // По умолчанию стабильность if (currentPrice > previousPrice) { trendEmoji = '📈'; // Рост } else if (currentPrice < previousPrice) { trendEmoji = '📉'; // Падение } // Сохраняем текущую цену как предыдущую для следующего сравнения previousPrices[resource.resource] = currentPrice; // Добавляем строку с ценой и эмодзи message += `• ${getEnterpriseEmoji(resource.resource)} ${getReadableResourceType(resource.resource)}: ${trendEmoji} ${utils.spaces(currentPrice)} руб/ед.\n`; }); message += `\n🔁 Последнее обновление цены: ${utils.getCurrentTime()}`; return message; }; // Функция для отправки/обновления сообщения const updateResourcePricesMessage = async () => { const pricesText = await getResourcePricesText(); try { if (resourceMessageId) { // Если сообщение существует, обновляем его await bot.telegram.editMessageText(CHANNEL_ID, resourceMessageId, null, pricesText, { parse_mode: 'Markdown', }); } else { // Если сообщения нет, отправляем новое const sentMessage = await bot.telegram.sendMessage(CHANNEL_ID, pricesText, { parse_mode: 'Markdown', }); resourceMessageId = sentMessage.message_id; // Сохраняем ID нового сообщения console.log("ID сообщения с котировками: " + sentMessage.message_id) } } catch (error) { console.error('Ошибка при обновлении сообщения с ценами ресурсов:', error); } }; const resetCasinoFlag = async () => { try { await UserModel.update( { isPlayingCasino: false }, // Новое значение для поля { where: { isPlayingCasino: true } } // Только для тех, у кого флаг был установлен ); console.log('Флаг isPlayingCasino успешно сброшен для всех пользователей.'); } catch (error) { console.error('Ошибка при сбросе флага isPlayingCasino:', error); } }; // Вызов функции при запуске бота resetCasinoFlag(); // Запускаем функцию updateResourcePricesMessage(); // Запускаем обновление каждые 15 минут schedule.scheduleJob('*/15 * * * *', recoverResourcePrices); schedule.scheduleJob('*/15 * * * *', updateResourcePricesMessage); // Запускаем процессы каждый час schedule.scheduleJob('0 * * * *', resourceProduction); // Каждый час в начале часа schedule.scheduleJob('5 * * * *', resourceTransportation); // Каждый час bot.command('force_prod', async (ctx) => { resourceProduction() return await ctx.reply(`Принудительно добыто.`) }) bot.command('force_transport', async (ctx) => { resourceTransportation() return await ctx.reply(`Принудительно перевезено.`) }) bot.command('force_hour', async (ctx) => { resourceProduction() resourceTransportation() return await ctx.reply(`Принудительный час.`) }) bot.command('force_recover', async (ctx) => { recoverResourcePrices() updateResourcePricesMessage() return await ctx.reply(`Принудительно.`) }) bot.command('force_mat', async (ctx) => { utils.matPriceUpdate() return await ctx.reply(`Принудительный материал.`) }) /////////////////////////////////////Enterprise Update end////////////////////////////////////////////////// /////////////////////////////////////Casino Update////////////////////////////////////////////////// // Функция для игры в слоты const spinSlots = async (ctx, bet, user) => { const slotIcons = ['🔥', '⚡', '⭐', '💀']; // Иконки для слотов // Определяем результат игры const winMultiplier = determineWin(); const finalIcons = generateVisualResult(winMultiplier, slotIcons); // Вычисляем выигрыш/проигрыш let resultMessage = `🎰 Итог:\n${finalIcons.join(' | ')}\n\n`; if (winMultiplier > 0) { const winnings = bet * winMultiplier; utils.giveExp(user, winMultiplier * 10) user.money += winnings; await user.save(); console.log(`Win: ${winnings}`) resultMessage += `🎉 Вы выиграли ₽${spaces(winnings)}! Множитель: x${winMultiplier}`; } else { utils.giveExp(user, 2) user.money -= bet; await user.save(); resultMessage += `💔 Вы проиграли ₽${spaces(bet)}. Попробуйте ещё раз!`; } // Отправляем результат await ctx.answerCbQuery(resultMessage, { show_alert: true }); }; // Функция для определения выигрыша const determineWin = () => { const probabilities = { 25: 0.001, // 0.01% шанс на x25 10: 0.009, // 0.9% шанс на x10 5: 0.01, // 1% шанс на x5 2: 0.09, // 9% шанс на x2 0: 0.9, // 90% шанс на проигрыш }; const random = Math.random(); let cumulativeProbability = 0; for (const [multiplier, probability] of Object.entries(probabilities)) { cumulativeProbability += probability; if (random < cumulativeProbability) { return parseInt(multiplier, 10); } } return 0; // По умолчанию проигрыш }; // Генерация визуального результата на основе выигрыша const generateVisualResult = (multiplier, slotIcons) => { if (multiplier === 25) return ['🔥', '🔥', '🔥']; if (multiplier === 10) return ['⚡', '⚡', '⚡']; if (multiplier === 5) return ['⭐', '⭐', '⭐']; if (multiplier === 2) return ['💀', '💀', '💀']; // Генерация случайных иконок для проигрыша let icons = [ slotIcons[Math.floor(Math.random() * slotIcons.length)], slotIcons[Math.floor(Math.random() * slotIcons.length)], slotIcons[Math.floor(Math.random() * slotIcons.length)], ]; // Проверка на уникальность if (icons[0] === icons[1] && icons[1] === icons[2]) { let newIcon; do { newIcon = slotIcons[Math.floor(Math.random() * slotIcons.length)]; } while (newIcon === icons[0]); // Заменяем одну из иконок (например, третью) icons[2] = newIcon; } return icons; }; // Основная команда слотов bot.action(/slots\d+/, async (ctx) => { try { const data = ctx.update.callback_query.data; const bet = parseInt(data.replace('slots', ''), 10); const user = await UserModel.findByPk(ctx.from.id); if (!user || user.money < bet) { return ctx.answerCbQuery('💸 У вас недостаточно средств для ставки.', { show_alert: true }); } if (user.isPlayingCasino) { return ctx.answerCbQuery('📛 Спам атака предотвращена.', { show_alert: true }); } const timer = user.slottime; const cooldown = utils.setCooldown(user, 10, timer); if (user.slottime > cooldown.currentTime) { return ctx.answerCbQuery('📛 Слоты будут доступны через пару секунд.', { show_alert: true }); } // Установить флаг игры user.isPlayingCasino = true; user.slottime = cooldown.endTime; await user.save(); // Запуск игры await spinSlots(ctx, bet, user); // Сброс флага игры user.isPlayingCasino = false; await user.save(); } catch (error) { console.error('Ошибка при игре в слоты:', error); return ctx.reply('Произошла ошибка. Попробуйте снова.'); } }); // Функция для форматирования чисел const spaces = (number) => { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' '); }; bot.hears('🎰 Рулетка', async (ctx) => { return ctx.reply('Закрыто') const user = await UserModel.findByPk(ctx.from.id); if (user.money <= 0) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, `У вас недостаточно средств для игры.`, { show_alert: true }); } // Инициализация ставки через ctx.session if (!ctx.session.betAmount) { ctx.session.betAmount = 10000; // Начальная ставка } // Вспомогательная функция для генерации случайного числа рулетки const spinRoulette = () => { // Все нечетные числа (красные) const redNumbers = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35]; // Все четные числа (черные) const blackNumbers = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36]; // Рулетка: делаем случайный выбор const randomIndex = Math.floor(Math.random() * 37); // от 0 до 36 return randomIndex; }; // Кнопки для выбора ставки const buttons = [ [{ text: 'Красный', callback_data: 'red' }], [{ text: 'Черный', callback_data: 'black' }], [{ text: 'Выбрать номер', callback_data: 'choose_number' }], [{ text: `Ставка: ₽${ctx.session.betAmount}`, callback_data: 'no_action' }], [ { text: '⬆️ Повысить ставку', callback_data: 'increase_bet' }, { text: '⬇️ Понизить ставку', callback_data: 'decrease_bet' } ] ]; const message = `🎰 Добро пожаловать в рулетку!\nВыберите ставку: Красный, Черный или Номер (0-36).`; await ctx.reply(message, Markup.inlineKeyboard(buttons)); // Обработчик для изменения ставки bot.action('increase_bet', async (ctx) => { if (ctx.session.betAmount < 50000) { ctx.session.betAmount += 10000; // Увеличиваем ставку на 10000 const buttons = [ [{ text: 'Красный', callback_data: 'red' }], [{ text: 'Черный', callback_data: 'black' }], [{ text: 'Выбрать номер', callback_data: 'choose_number' }], [{ text: `Ставка: ₽${ctx.session.betAmount}`, callback_data: 'no_action' }], [ { text: '⬆️ Повысить ставку', callback_data: 'increase_bet' }, { text: '⬇️ Понизить ставку', callback_data: 'decrease_bet' } ] ]; await ctx.editMessageText(`🎰 Добро пожаловать в рулетку!\nВыберите ставку: Красный, Черный или Номер (0-36).`, Markup.inlineKeyboard(buttons)); } else { await ctx.reply('Максимальная ставка - ₽50000'); } }); bot.action('decrease_bet', async (ctx) => { if (ctx.session.betAmount > 10000) { ctx.session.betAmount -= 10000; // Уменьшаем ставку на 10000 const buttons = [ [{ text: 'Красный', callback_data: 'red' }], [{ text: 'Черный', callback_data: 'black' }], [{ text: 'Выбрать номер', callback_data: 'choose_number' }], [{ text: `Ставка: ₽${ctx.session.betAmount}`, callback_data: 'no_action' }], [ { text: '⬆️ Повысить ставку', callback_data: 'increase_bet' }, { text: '⬇️ Понизить ставку', callback_data: 'decrease_bet' } ] ]; await ctx.editMessageText(`🎰 Добро пожаловать в рулетку!\nВыберите ставку: Красный, Черный или Номер (0-36).`, Markup.inlineKeyboard(buttons)); } else { await ctx.reply('Минимальная ставка - ₽10000'); } }); bot.action(['red', 'black', 'choose_number'], async (ctx) => { const data = ctx.update.callback_query.data; if (user.money < ctx.session.betAmount) { return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, `У вас недостаточно средств для этой ставки.`, { show_alert: true }); } let winMultiplier = 0; let betResult = ''; const spinResult = spinRoulette(); if (data === 'red') { if ([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35].includes(spinResult)) { winMultiplier = 2; betResult = `Вы выиграли! 🎉 Красный! Множитель: 2x`; } else { betResult = `Вы проиграли. Черный номер. 😢`; } } else if (data === 'black') { if ([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36].includes(spinResult)) { winMultiplier = 2; betResult = `Вы выиграли! 🎉 Черный! Множитель: 2x`; } else { betResult = `Вы проиграли. Красный номер. 😢`; } } else if (data === 'choose_number') { const number = Math.floor(Math.random() * 37); // Игрок выбирает случайное число if (spinResult === number) { winMultiplier = 35; // Огромный выигрыш для точного угадывания betResult = `Вы угадали номер! 🎉 Номер ${number}! Множитель: 35x`; } else { betResult = `Вы не угадали номер. Выпал номер ${spinResult}. 😢`; } } // Считаем выигрыш let prize = ctx.session.betAmount * winMultiplier; user.money += prize; // Вычитаем ставку, если выиграли await user.save(); // Отправляем результат return await ctx.telegram.answerCbQuery(ctx.callbackQuery.id, betResult, { show_alert: true }); }); }); /////////////////////////////////////Casino Update end////////////////////////////////////////////////////// /////////////////////////////////////Admin Commands////////////////////////////////////////////////// bot.command('answer', commands.reportAnswer) bot.command('fastblock', commands.fastblock) bot.command('createpromocode', commands.createPromo) bot.command('genpromo', commands.genPromo) bot.command('ban', async (ctx) => { const user = await UserModel.findByPk(ctx.from.id); // Проверка прав администратора if (user.status !== 'admin') { return await ctx.reply(`❌ У вас нет прав для выполнения этой команды.`); } // Разбор аргументов команды const args = ctx.message.text.split(' ').slice(1); if (args.length < 3) { return await ctx.reply(`⚠️ Использование: /ban <время в минутах> <причина>.`); } const identifier = args[0]; // ID или username пользователя const blockTimeMinutes = parseInt(args[1], 10); // Время блокировки в минутах const reason = args.slice(2).join(' '); // Причина блокировки // Проверка времени блокировки if (isNaN(blockTimeMinutes) || blockTimeMinutes <= 0) { return await ctx.reply(`❌ Укажите корректное время блокировки в минутах.`); } // Ищем пользователя по Telegram ID или никнейму let targetUser; if (identifier.startsWith('@')) { // Если передан username targetUser = await UserModel.findOne({ where: { username: identifier.slice(1) } }); } else { // Если передан Telegram ID targetUser = await UserModel.findOne({ where: { telegram_id: identifier } }); } if (!targetUser) { return await ctx.reply(`❌ Пользователь с идентификатором "${identifier}" не найден.`); } // Создаём запись о блокировке const block = await BlockModel.create({ telegram_id: targetUser.telegram_id, isBlocked: true, reason: reason, time: Math.trunc(Date.now() / 1000 + blockTimeMinutes * 60) // Время блокировки в секундах }); // Уведомляем заблокированного пользователя try { await bot.telegram.sendMessage( targetUser.telegram_id, `❌ Вы были заблокированы администратором ${user.username}.\nПричина: ${reason}\nСрок: ${blockTimeMinutes} минут(ы).` ); } catch (error) { console.error(`Ошибка отправки уведомления пользователю ${targetUser.telegram_id}:`, error); } // Уведомляем администратора return await ctx.reply( `✅ Пользователь ${targetUser.username || targetUser.telegram_id} был успешно заблокирован.\nПричина: ${reason}\nСрок: ${blockTimeMinutes} минут(ы).` ); }); ///////////////////////////////////////Functions////////////////////////////////////////////////////// setInterval(() => { var today = new Date(); let hours = today.getHours(); if (hours == "0" || hours == "12") { //weaponShopUpdate() utils.matPriceUpdate() } /*if (hours == "9" || hours == "18" || hours == "12") { generatePromo() }*/ }, 3600000); start() bot.launch()