// Подключаем необходимые библиотеки const { Telegraf, Scenes, session, Markup, Stage } = require('telegraf'); const { Op } = require('sequelize'); 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, } = global.config const bot = new Telegraf(process.env.BOT_TOKEN) 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.use(stage.middleware()) 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.findByPk(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 !== null) { if (block.isBlocked == true && block.time > Date.now() / 1000) return ctx.reply(`📛 У вас активная блокировка по причине: ${block.reason}.\n⏲️ Оставшееся время: ${Math.trunc((block.time - Date.now()/1000)/60)} мин.`) block.isBlocked = false block.save() } 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 ['🏗️ Предприятия'], ['📦 Контейнеры'], ['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'] // Row3 with 3 buttons ]) .resize() ) }) bot.hears('Криминал', async (ctx) => { await ctx.reply(`Closed`) /*await ctx.scene.enter('Crime')*/ }) 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() }) /////////////////////////////////////Enterprise Update 20.12.2024////////////////////////////////////////////////// // Обновление меню "Предприятия" bot.hears('🏗️ Предприятия', 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.reply(message, Markup.inlineKeyboard(buttons).resize()); }); 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 message = `🏭 Мои предприятия:\n\n`; const buttons = []; for (const enterprise of enterprises) { const { id, name, level, efficiency, currentResources, resourceType, warehouseCapacity } = enterprise; message += `🔹 [ID: ${id}] ${getEnterpriseEmoji(resourceType)} ${name} st. ${level}\n └── ${currentResources}/${warehouseCapacity} [${efficiency} ед/ч]\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}` }); } buttons.push(enterpriseButtons); } message += '\n\n[📈 - Улучшить]\n[🛻 - Нанять грузовик]\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.reply('Вы достигли максимального числа предприятий.'); } // Получаем текущие цены из базы данных 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 = getEnterpriseEmoji(resource.resource); message += `${resourceName}: ${Math.round(resource.price)} руб.\n`; // Генерируем кнопки для каждого ресурса buttons.push([ { text: resourceName, callback_data: `build_${resource.resource}` } ]); } message += '\nВыберите тип предприятия:'; 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] let price = getEnterprisePrice(type) // Проверка, есть ли достаточно денег у пользователя if (user.balance < price) { return await ctx.reply(`У вас недостаточно средств для постройки предприятия. Необходимо ${price} руб.`) } // Строим предприятие 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}) построено!`) }) // Функция для расчета стоимости предприятия function getEnterprisePrice(resourceType) { const prices = { wood: 5000, coal: 10000, oil: 20000, metall: 50000, gold: 150000, diamond: 250000 } return prices[resourceType] || 0 } // Функция для преобразования типа ресурса в читаемое название function getReadableType(type) { const names = { wood: 'Деревообрабатывающее предприятие', coal: 'Угольное предприятие', oil: 'Нефтяное предприятие', metall: 'Металлургическое предприятие', gold: 'Золотое предприятие', diamond: 'Алмазное предприятие' } return names[type] || type } bot.action('buy_warehouse', async (ctx) => { let user = await UserModel.findByPk(ctx.from.id) if (user.money < 500000) { return await ctx.reply(`У вас недостаточно средств для покупки склада.`) } 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 - 500000 }) 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.reply('У вас нет единого склада.'); } 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.reply('На предприятии нет ресурсов для перевода.'); } const warehouse = await WarehouseModel.findOne({ where: { playerId } }); if (!warehouse) { return await ctx.reply('У вас нет склада для перевода ресурсов.'); } const freeCapacity = warehouse.capacity - getWarehouseUsedCapacity(warehouse); const transferAmount = Math.min(currentResources, freeCapacity); if (transferAmount === 0) { return await ctx.reply('Склад заполнен. Перевод невозможен.'); } // Перевод ресурсов 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_enterprise', async (ctx) => { let user = await UserModel.findByPk(ctx.from.id) let enterprises = await EnterpriseModel.findAll({ where: { playerId: user.telegram_id } }) if (enterprises.length === 0) return await ctx.reply(`У вас нет предприятий для прокачки.`) let buttons = [] enterprises.forEach(enterprise => { buttons.push({ text: `Прокачать ${enterprise.name}`, callback_data: `upgrade_${enterprise.id}` }) }) return await ctx.editMessageText(`Выберите предприятие для прокачки:`, Markup.inlineKeyboard(buttons).resize()) }) 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(`Предприятие не найдено.`) let upgradeCost = enterprise.level * 100 // Стоимость улучшения зависит от уровня if (user.balance < upgradeCost) { return await ctx.reply(`У вас недостаточно средств для прокачки предприятия. Необходимо ${upgradeCost} руб.`) } // Прокачка: повышение уровня и эффективности await enterprise.update({ level: enterprise.level + 1, efficiency: enterprise.efficiency + 10 }) // Снимаем деньги с баланса await user.update({ balance: user.balance - 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(); return await ctx.reply( `Вы продали ${amount} единиц ${enterprise.resourceType} с предприятия ${enterprise.name} за ${totalSale} руб.\nТекущая цена за единицу: ${resourcePrice.price.toFixed(0)} руб.` ); }); const recoverResourcePrices = async () => { const resources = await ResourcePriceModel.findAll(); for (const resource of resources) { // Определяем случайное колебание в диапазоне [-maxFluctuation, maxFluctuation] const maxFluctuation = resource.basePrice * 0.03; // 3% от базовой цены const priceFluctuation = (Math.random() * 2 - 1) * maxFluctuation; // Применяем колебание resource.price = Math.round(resource.price + priceFluctuation); // Если цена выше базовой, шанс на её снижение if (resource.price > resource.basePrice) { const chanceToDrop = 0.6; // 60% шанс на снижение if (Math.random() < chanceToDrop) { resource.price -= Math.round(resource.basePrice * 0.01); // Снижение на 1% базовой цены } } // Если цена ниже базовой, восстанавливаем с учётом recoveryRate if (resource.price < resource.basePrice) { resource.price = Math.min( Math.round(resource.price + resource.basePrice * resource.recoveryRate), resource.basePrice // Не превышать базовую цену ); } // Гарантируем, что цена остаётся в диапазоне [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 * 1.5)); // Максимум await resource.save(); // Сохраняем после всех корректировок } }; // Запускаем процесс восстановления цен каждые 15 минут setInterval(recoverResourcePrices, 5 * 1000); 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.reply('На предприятии нет ресурсов для продажи.'); } 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.reply('На предприятии нет ресурсов для продажи.'); } // Обновление баланса игрока const user = await UserModel.findByPk(playerId); user.money += totalPrice; enterprise.currentResources = 0; await user.save(); await enterprise.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(); await ctx.editMessageText(`Вы успешно продали ${currentResources} ед. ${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(); return await ctx.reply( `Вы продали ${amount} ед. ${resourceType} со склада за ${totalSale} руб.\nТекущая цена за единицу: ${resourcePrice.price.toFixed(0)} руб.` ); }); // Найм грузовика bot.action('hire_truck', 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('У вас нет предприятий для найма грузовиков.'); } // Создаем кнопки для выбора предприятия const buttons = enterprises.map((enterprise) => [ { text: `Нанять для ${enterprise.name}`, callback_data: `hire_truck_${enterprise.id}` } ]); return await ctx.reply( 'Выберите предприятие для найма грузовика:', Markup.inlineKeyboard(buttons).resize() ); }); // Обработка найма грузовика для выбранного предприятия 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.reply(`У вас уже есть грузовик для предприятия ${enterprise.name}.`); } // Создаем новый грузовик 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 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 * level; // Проверяем ёмкость склада предприятия 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, resourceType, currentResources, playerId } = enterprise; if (currentResources > 0) { // Получаем грузовики, привязанные к предприятию const trucks = await TruckModel.findAll({ where: { enterpriseId: id } }); if (trucks.length === 0) { console.log( `Предприятие ${id}: нет доступных грузовиков для транспортировки.` ); continue; } // Получаем универсальный склад игрока const warehouse = await WarehouseModel.findOne({ where: { playerId } }); if (!warehouse) { console.log( `Предприятие ${id}: у игрока ${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}: склад заполнен, транспортировка невозможна.` ); } } else { console.log(`Предприятие ${id}: нет ресурсов для транспортировки.`); } } } 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); }; // Запускаем процессы каждый час setInterval(resourceProduction, 60 * 60 * 1000); setInterval(resourceTransportation, 60 * 60 * 1000); bot.command('force_prod', async (ctx) => { resourceProduction() return await ctx.reply(`Принудительно добыто.`) }) bot.command('force_transport', async (ctx) => { resourceTransportation() return await ctx.reply(`Принудительно перевезено.`) }) /////////////////////////////////////Enterprise Update end////////////////////////////////////////////////// /////////////////////////////////////Admin Commands////////////////////////////////////////////////// bot.command('answer', commands.reportAnswer) bot.command('fastblock', commands.fastblock) bot.command('createpromocode', commands.createPromo) bot.command('genpromo', commands.genPromo) ///////////////////////////////////////Functions////////////////////////////////////////////////////// setInterval(() => { var today = new Date(); let hours = today.getHours(); if (hours == "0" || hours == "12") { weaponShopUpdate() matPriceUpdate() } /*if (hours == "9" || hours == "18" || hours == "12") { generatePromo() }*/ }, 3600000); start() bot.launch()