This commit is contained in:
Degradin 2024-12-23 20:04:00 +03:00
parent bf04318a1f
commit 3eb1d2ffa9
4 changed files with 333 additions and 163 deletions

477
bot.js
View File

@ -18,6 +18,7 @@ const {
PromocodeModel,
EnterpriseModel,
WarehouseModel,
TruckModel,
SaleModel,
ResourcePriceModel,
SkillsModel,
@ -406,20 +407,38 @@ bot.action('my_enterprises', async (ctx) => {
let message = `🏭 Мои предприятия:\n\n`;
const buttons = [];
enterprises.forEach((enterprise) => {
message += `🔹 ${enterprise.name} (Уровень: ${enterprise.level}, Эффективность: ${enterprise.efficiency} ед/ч)\n`;
buttons.push([
{ text: `📈 Улучшить ${enterprise.name}`, callback_data: `upgrade_${enterprise.id}` },
{ text: `🚛 Управлять ${enterprise.name}`, callback_data: `manage_${enterprise.id}` }
]);
});
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: 'back_to_menu' }]);
return await ctx.reply(message, Markup.inlineKeyboard(buttons).resize());
});
// Построение предприятия
bot.action('build_enterprise', async (ctx) => {
try {
@ -567,42 +586,18 @@ bot.action('manage_warehouse', async (ctx) => {
return await ctx.reply(message, Markup.inlineKeyboard(buttons).resize());
});
bot.action('warehouse_management', async (ctx) => {
let user = await UserModel.findByPk(ctx.from.id)
let warehouse = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } })
if (!warehouse) {
return await ctx.reply(`У вас нет склада. Вы можете купить его за 500,000 руб.`, Markup.inlineKeyboard([
[{ text: 'Купить склад', callback_data: 'buy_warehouse' }]
]).resize())
}
let message = `
🏗 Единый склад
Емкость: ${warehouse.capacity} ед.
Ресурсы:
🌲 Дерево: ${warehouse.wood || 0}
Уголь: ${warehouse.coal || 0}
🛢 Нефть: ${warehouse.oil || 0}
🛠 Металл: ${warehouse.metall || 0}
💰 Золото: ${warehouse.gold || 0}
💎 Алмазы: ${warehouse.diamond || 0}
`
return await ctx.reply(message, Markup.inlineKeyboard([
[{ text: 'Управление транспортом', callback_data: 'manage_trucks' }],
[{ text: 'Продать ресурсы', callback_data: 'sell_from_warehouse' }]
]).resize())
})
// Управление предприятием
bot.action(/manage_(\d+)/, async (ctx) => {
let enterpriseId = ctx.match[1]
let enterprise = await EnterpriseModel.findByPk(enterpriseId)
if (!enterprise) return await ctx.reply(`Предприятие не найдено.`)
const buttons = [
[{ text: 'Продать ресурсы', callback_data: 'sell_resources' }],
[{ text: 'Нанять грузовик', callback_data: 'hire_truck' }]
];
// Логика управления предприятием (например, прокачка или продажа ресурсов)
return await ctx.reply(`Вы управляете предприятием ${enterprise.name} (ID: ${enterprise.id}).`)
return await ctx.reply(`Вы управляете предприятием ${enterprise.name} (ID: ${enterprise.id}).`, Markup.inlineKeyboard(buttons).resize())
})
bot.action('transfer_resources', async (ctx) => {
const user = await UserModel.findByPk(ctx.from.id);
@ -630,24 +625,41 @@ bot.action('transfer_resources', async (ctx) => {
// Перевозка с конкретного предприятия
bot.action(/transfer_from_(\d+)/, async (ctx) => {
const enterpriseId = ctx.match[1];
const user = await UserModel.findByPk(ctx.from.id);
const warehouse = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } });
const enterprise = await EnterpriseModel.findByPk(enterpriseId);
if (!enterprise) {
return await ctx.reply('Предприятие не найдено.');
}
let message = `🚛 Перевозка с предприятия ${enterprise.name}:\n`;
message += `🌲 Дерево: ${enterprise.wood || 0}\n`;
message += `⛏️ Уголь: ${enterprise.coal || 0}\n`;
message += `🛢️ Нефть: ${enterprise.oil || 0}\n`;
message += `⚙️ Металл: ${enterprise.metall || 0}\n`;
message += `🥇 Золото: ${enterprise.gold || 0}\n`;
message += `💎 Алмазы: ${enterprise.diamond || 0}\n`;
message += `\nВведите количество ресурса для перевозки.`;
const { currentResources, resourceType, playerId } = enterprise;
return await ctx.reply(message);
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) => {
@ -712,70 +724,226 @@ bot.action(/upgrade_(\d+)/, async (ctx) => {
return await ctx.reply(`Предприятие ${enterprise.name} успешно прокачано! Уровень: ${enterprise.level}, Производительность: ${enterprise.efficiency} ед/ч.`)
})
// Показ списка предприятий
bot.action('sell_resources', async (ctx) => {
let user = await UserModel.findByPk(ctx.from.id)
let enterprises = await EnterpriseModel.findAll({
where: {
playerId: user.telegram_id
}
})
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 buttons = []
enterprises.forEach(enterprise => {
buttons.push({ text: `Продать ресурсы с ${enterprise.name}`, callback_data: `sell_${enterprise.id}` })
})
return await ctx.reply(`Выберите предприятие для продажи ресурсов:`, Markup.inlineKeyboard(buttons).resize())
})
bot.action(/sell_(\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 resourceQuantity = await ResourceModel.findOne({
where: { playerId: user.telegram_id, type: enterprise.resourceType }
})
if (!resourceQuantity || resourceQuantity.quantity <= 0) {
return await ctx.reply(`У вас нет ресурсов для продажи на предприятии ${enterprise.name}.`)
if (enterprises.length === 0) {
return await ctx.reply('У вас нет предприятий для продажи ресурсов.');
}
const salePrice = getResourcePrice(enterprise.resourceType) // Цена за единицу ресурса
const totalSale = salePrice * resourceQuantity.quantity
let message = 'Список ваших предприятий и их ресурсы:\n\n';
enterprises.forEach((enterprise, index) => {
message += `${index + 1}. ${enterprise.name} (${enterprise.resourceType}): ${enterprise.currentResources} единиц\n`;
});
// Обновляем количество ресурсов
await ResourceModel.update(
{ quantity: 0 }, // Все ресурсы продаются
{ where: { playerId: user.telegram_id, type: enterprise.resourceType } }
)
message += `\nЧтобы продать ресурсы, используйте команду:\n/sellres <номер_предприятия> <количество>\nПример: /sellres 1 50`;
return await ctx.reply(message);
});
// Добавляем деньги пользователю
await user.update({ balance: user.balance + totalSale })
// Обработка продажи ресурсов
bot.command('sellres', async (ctx) => {
const user = await UserModel.findByPk(ctx.from.id);
const [enterpriseId, amountToSell] = ctx.message.text.split(' ').slice(1);
return await ctx.reply(`Вы продали все ресурсы с ${enterprise.name} за ${totalSale} монет.`)
})
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)
);
// Гарантируем, что цена не упадет ниже 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) {
if (resource.price < resource.basePrice) {
resource.price = Math.min(
resource.price + resource.basePrice * resource.recoveryRate,
resource.basePrice // Не превышать базовую цену
);
await resource.save();
}
}
};
// Запускаем процесс восстановления цен каждые 15 минут
setInterval(recoverResourcePrices, 15 * 60 * 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)
);
// Гарантируем, что цена не упадет ниже 50% от базовой цены
resourcePrice.price = Math.max(resourcePrice.price, Math.round(resourcePrice.basePrice * 0.5));
await resourcePrice.save();
await ctx.reply(`Вы успешно продали ${currentResources} ед. ${resourceType} за ${totalPrice} руб.`);
});
// Найм грузовика
bot.action('hire_truck', async (ctx) => {
let user = await UserModel.findByPk(ctx.from.id)
let warehouse = await WarehouseModel.findOne({ where: { playerId: user.telegram_id } })
const user = await UserModel.findByPk(ctx.from.id);
if (!warehouse) return await ctx.reply(`У вас нет склада для найма грузовиков.`)
// Получаем список предприятий пользователя
const enterprises = await EnterpriseModel.findAll({
where: { playerId: user.telegram_id }
});
// Логика найма грузовика
let truck = await TruckModel.create({
warehouseId: warehouse.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}!`
);
});
return await ctx.reply(`Вы наняли грузовик для транспортировки ресурсов!`)
})
async function initializePrices() {
const resources = [
@ -810,91 +978,82 @@ setInterval(async () => {
}
}, 60000) // Обновляем цены каждые 60 секунд
// Функция добычи ресурсов
const resourceProduction = async () => {
try {
// Получаем все предприятия без фильтрации по пользователю
// Получаем все предприятия
const enterprises = await EnterpriseModel.findAll();
for (const enterprise of enterprises) {
const { id, efficiency, warehouseCapacity, resourceType, playerId, level, currentResources } = enterprise;
const {
id,
efficiency,
warehouseCapacity,
resourceType,
currentResources,
level,
playerId
} = enterprise;
// Рассчитываем добычу ресурсов
// Расчёт добытых ресурсов
const producedResources = efficiency * level;
// Проверяем, не превышает ли общая сумма ресурсов ёмкость склада
// Проверяем ёмкость склада предприятия
if (currentResources + producedResources <= warehouseCapacity) {
enterprise.currentResources = currentResources + producedResources;
enterprise.currentResources += producedResources;
await enterprise.save();
console.log(`Предприятие ${id}: добыто ${producedResources} единиц ${resourceType}.`);
console.log(
`Предприятие ${id}: добыто ${producedResources} единиц ${resourceType}.`
);
} else {
console.log(`Предприятие ${id}: склад заполнен.`);
}
// Получаем универсальный склад, если он есть
const Warehouse = await WarehouseModel.findOne({
where: { playerId: playerId } // Привязка к игроку через playerId
});
if (Warehouse) {
const transportableAmount = Math.min(
enterprise.currentResources,
universalWarehouse.remainingCapacity
);
if (transportableAmount > 0) {
// Перемещаем ресурсы
enterprise.currentResources -= transportableAmount;
Warehouse.resources[resourceType] =
(Warehouse.resources[resourceType] || 0) + transportableAmount;
await enterprise.save();
await Warehouse.save();
console.log(`Предприятие ${id}: перевезено ${transportableAmount} единиц ${resourceType} на универсальный склад.`);
} else {
console.log(`Универсальный склад игрока ${playerId} заполнен.`);
}
}
}
} catch (error) {
console.error('Ошибка добычи ресурсов:', error);
}
};
// Запуск функции каждый час
setInterval(resourceProduction, 60 * 60 * 1000);
// Функция добычи ресурсов
// Функция транспортировки ресурсов
const resourceTransportation = async () => {
try {
// Получаем все предприятия
const enterprises = await EnterpriseModel.findAll();
for (const enterprise of enterprises) {
const { id, resourceType, currentResources, playerId } = enterprise;
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(`У игрока ${playerId} нет склада.`);
console.log(
`Предприятие ${id}: у игрока ${playerId} нет универсального склада.`
);
continue;
}
// Получаем грузовики, привязанные к этому складу
const trucks = await Truck.findAll({
where: { warehouseId: warehouse.id }
});
if (trucks.length === 0) {
console.log(`На складе ${warehouse.id} нет доступных грузовиков.`);
continue;
}
// Транспортируем ресурсы
// Транспортировка ресурсов
let totalTransported = 0;
for (const truck of trucks) {
const transportableAmount = Math.min(
@ -905,7 +1064,8 @@ const resourceTransportation = async () => {
if (transportableAmount > 0) {
// Обновляем данные склада
warehouse[resourceType] = (warehouse[resourceType] || 0) + transportableAmount;
warehouse[resourceType] =
(warehouse[resourceType] || 0) + transportableAmount;
// Уменьшаем ресурсы на предприятии
enterprise.currentResources -= transportableAmount;
@ -915,18 +1075,22 @@ const resourceTransportation = async () => {
totalTransported += transportableAmount;
console.log(`Грузовик ${truck.id} перевёз ${transportableAmount} единиц ${resourceType}.`);
console.log(
`Грузовик ${truck.id} перевёз ${transportableAmount} единиц ${resourceType}.`
);
}
// Прекращаем, если на предприятии закончились ресурсы
// Прекращаем, если ресурсы закончились
if (enterprise.currentResources === 0) break;
}
if (totalTransported === 0) {
console.log(`Склад ${warehouse.id} заполнен. Ресурсы не перевезены.`);
console.log(
`Предприятие ${id}: склад заполнен, транспортировка невозможна.`
);
}
} else {
console.log(`Предприятие ${id} не имеет доступных ресурсов для транспортировки.`);
console.log(`Предприятие ${id}: нет ресурсов для транспортировки.`);
}
}
} catch (error) {
@ -940,7 +1104,8 @@ const getWarehouseUsedCapacity = (warehouse) => {
return resources.reduce((sum, resource) => sum + (warehouse[resource] || 0), 0);
};
// Запускаем процесс транспортировки каждый час
// Запускаем процессы каждый час
setInterval(resourceProduction, 60 * 60 * 1000);
setInterval(resourceTransportation, 60 * 60 * 1000);

View File

@ -21,6 +21,7 @@ module.exports = {
LobbyModel: require('../models/lobby.model'),
EnterpriseModel: require('../models/enterprise.model'),
WarehouseModel: require('../models/warehouse.model'),
TruckModel: require('../models/truck.model'),
ResourcePriceModel: require('../models/resourceprice.model'),
SaleModel: require('../models/sales.model'),
mainChat : -1001895132127,

10
models/truck.model.js Normal file
View File

@ -0,0 +1,10 @@
const sequelize = require('../db');
const {DataTypes} = require('sequelize');
const Truck = sequelize.define('truck', {
enterpriseId: DataTypes.INTEGER,
capacity: DataTypes.INTEGER, // Сколько может перевезти за час
efficiency: DataTypes.INTEGER // Частота транспортировки (количество операций в час)
})
module.exports = Truck;

View File

@ -12,10 +12,4 @@ const Warehouse = sequelize.define('warehouse', {
diamond: DataTypes.INTEGER,
})
const Truck = sequelize.define('truck', {
warehouseId: DataTypes.INTEGER,
capacity: DataTypes.INTEGER, // Сколько может перевезти за час
efficiency: DataTypes.INTEGER // Частота транспортировки (количество операций в час)
})
module.exports = Warehouse, Truck;
module.exports = Warehouse;