Crime update
This commit is contained in:
Degradin 2025-01-10 00:54:54 +03:00
parent 4f97a3dba1
commit 125b782a64
6 changed files with 346 additions and 235 deletions

7
bot.js
View File

@ -206,10 +206,11 @@ bot.command('start', async (ctx) => {
return await ctx.reply('Главное меню', Markup
.keyboard([
['😎 Профиль'], // Row1 with 2 buttons
['🗄️ Работать', '🌐 Организация', '🎁 Бонус', '🏯 Казино'], // Row2 with 2 buttons
['🏗️ Предприятия'],
['🗄️ Работать', '🌐 Организация', '🏗️ Предприятия', '🏯 Казино'], // Row2 with 2 buttons
['CampFireGG.Crime'],
['🎁 Бонус'],
['📦 Контейнеры'],
['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'] // Row3 with 3 buttons
['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'],
])
.resize()
)

View File

@ -10,14 +10,14 @@ module.exports = async (ctx) => {
let user = await UserModel.findByPk(ctx.from.id)
const buttons = []
if (user.status == 'admin') {
buttons.push("CampFireGG.Crime");
buttons.push("Топ");
}
return await ctx.reply('Main Menu', Markup
.keyboard([
['😎 Профиль'], // Row1 with 2 buttons
['🗄️ Работать', '🌐 Организация', '🎁 Бонус', '🏯 Казино'], // Row2 with 2 buttons
['🏗️ Предприятия'],
['🗄️ Работать', '🌐 Организация', '🏗️ Предприятия', '🏯 Казино'], // Row2 with 2 buttons
['CampFireGG.Crime'],
['🎁 Бонус'],
['📦 Контейнеры'],
['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'],
buttons // Row3 with 3 buttons

View File

@ -1,3 +1,10 @@
const sequelize = require('../db');
const Character = require('../models/character.model');
const Inventory = require('../models/inventory.model');
// Устанавливаем ассоциации здесь
Character.hasMany(Inventory, { foreignKey: 'telegram_id' });
Inventory.belongsTo(Character, { foreignKey: 'telegram_id' });
module.exports = {
weaponshop : require('../json/weaponshop.json'),
slots : require('../json/slots.json'),
@ -10,6 +17,7 @@ module.exports = {
equipment : require('../presets/equipment.json'),
UserModel : require('../models/user.model'),
CharacterModel : require('../models/character.model'),
InventoryModel : require('../models/inventory.model'),
ItemsModel : require('../models/items.model'),
StolenCardsModel : require('../models/stolencards.model'),
WorldModel : require('../models/world.model'),

View File

@ -1,11 +1,11 @@
const sequelize = require('../db');
const { DataTypes } = require('sequelize');
const sequelize = require('../db');
const Character = sequelize.define('character', {
telegram_id: {
type: DataTypes.BIGINT,
primaryKey: true,
unique: true
unique: true,
},
username: {
type: DataTypes.STRING

View File

@ -2,9 +2,17 @@ const { DataTypes } = require('sequelize');
const sequelize = require('../db');
const Inventory = sequelize.define('inventory', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
telegram_id: {
type: DataTypes.BIGINT,
primaryKey: true
type: DataTypes.BIGINT, // Используем другой внешний ключ
references: {
model: 'characters', // Указываем правильное имя модели
key: 'telegram_id', // Внешний ключ указывает на telegram_id в модели Character
},
},
name: {
type: DataTypes.STRING,
@ -34,8 +42,10 @@ const Inventory = sequelize.define('inventory', {
type: DataTypes.INTEGER,
allowNull: true
}, // Длительность эффекта в секундах
equipped: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
});
module.exports = Inventory;

370
rpg.js
View File

@ -12,6 +12,7 @@ const {
expToUp,
UserModel,
CharacterModel,
InventoryModel,
ItemsModel,
StolenCardsModel,
WorldModel,
@ -28,6 +29,32 @@ const {
} = global.config
const rpg = new Composer();
rpg.use(async (ctx, next) => {
let id = ctx.from.id;
let username = ctx.from.username;
if (username == null) username = ctx.from.id;
const currentTime = utils.getCurrentTime();
switch (ctx.updateType) {
case 'message':
console.log(`${currentTime}: [RPG] ${username}: ${ctx.update.message.text}`);
break;
case 'callback_query':
console.log(`${currentTime}: [RPG] ${username}: ${ctx.update.callback_query.data}`);
break;
case 'edited_message':
console.log(`${currentTime}: [RPG] ${username} edited: ${ctx.update.edited_message.text}`);
break;
default:
console.log(`${currentTime}: [RPG] Unknown update type:`, ctx.update);
}
await next(); // Передаем управление следующему middleware
});
rpg.hears('RPG', async (ctx) => {
let message = `Меню:\n`;
@ -61,7 +88,7 @@ rpg.action('rpg_profile', async (ctx) => {
🔋 Выносливость (E): ${character.endurance}
🔥 Стамина: ${character.stamina}/${character.max_stamina}
💰 Грязные деньги: ${utils.spaces(character.dirtymoney)}
🃏 Карточки: ${stolenCards.length}
🃏 Карты: ${stolenCards.length}
`;
// Отправляем сообщение
@ -144,8 +171,9 @@ rpg.hears('CampFireGG.Crime', async (ctx) => {
Markup.inlineKeyboard([
[Markup.button.callback('💼 Задачи', 'crime_missions')],
[Markup.button.callback('📊 Профиль', 'rpg_profile')],
//[Markup.button.callback('💳 Карточки', 'view_cards')],
[Markup.button.callback('💰 Инвентарь', 'inventory')],
[Markup.button.callback('💳 Карточки', 'view_cards')],
[Markup.button.callback('🎒 Инвентарь', 'inventory')],
[Markup.button.callback('💰 Магазин', 'shop')],
])
);
}
@ -294,7 +322,7 @@ rpg.action(/purchase_/, async (ctx) => {
}
// Если баланс карты достаточно для покупки, добавляем предмет в инвентарь
character.inventory.push(item.id);
character.InventoryModel.push(item.id);
await character.save();
// Если товар электронный, начисляем процент от стоимости на счет
@ -339,11 +367,21 @@ rpg.action(/purchase_fail_/, async (ctx) => {
rpg.action(/brutecard_/, async (ctx) => {
const cardId = ctx.match.input.split('_')[1]; // Получаем ID карточки из callback_data
const card = await StolenCardsModel.findByPk(cardId); // Ищем карточку в базе данных
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } }); // Загружаем предметы из инвентаря
if (!card) {
return ctx.answerCbQuery('Карточка не найдена.');
}
// Проверяем наличие "Эмулятора картридера" в инвентаре
const emulator = inventory.find((item) => item.name === 'Эмулятор картридера');
if (!emulator) {
return ctx.reply('Для запуска брутфорса вам нужен "Эмулятор картридера".');
}
// Удаляем "Эмулятор картридера" из инвентаря
await InventoryModel.destroy({ where: { id: emulator.id } });
const buttonsCount = 10; // Количество кнопок
const winButton = utils.rand(1, buttonsCount); // Выбираем случайную кнопку для успешного пина
const maxAttempts = 3; // Максимальное количество попыток
@ -378,11 +416,25 @@ rpg.action(/brutecard_/, async (ctx) => {
// Отправляем сообщение с клавиатурой
await ctx.reply(
`💳 Брутфорс карты\n\nПопробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`,
`💳 Брутфорс карты\n
${card.bankName.toUpperCase()}
Номер: ${card.cardNumber}
CVV: ${card.cvv}
Владелец: ${card.holderName.toUpperCase()}
Срок действия: ${card.expiresDate}
Попробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.
"Эмулятор картридера" был использован.`,
keyboard
);
});
// Обработка неудачной попытки взлома
rpg.action(/brute_fail_/, async (ctx) => {
const cardId = ctx.match.input.split('_')[2];
@ -430,7 +482,17 @@ rpg.action(/brute_fail_/, async (ctx) => {
// Обновляем сообщение с клавиатурой
await ctx.editMessageText(
`💳 Взлом карточки\n\nПопробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`,
`💳 Брутфорс карты\n
${card.bankName.toUpperCase()}
Номер: ${card.cardNumber}
CVV: ${card.cvv}
Владелец: ${card.holderName.toUpperCase()}
Срок действия: ${card.expiresDate}
Попробуйте подобрать правильный ПИН-код. У вас есть ${maxAttempts - attempts[ctx.from.id]} попыток.`,
keyboard
);
});
@ -458,7 +520,17 @@ rpg.action(/brute_success_/, async (ctx) => {
// Отправляем сообщение о выигрыше
await ctx.editMessageText(
`✅ Взлом успешен! Вы получили Ð${amount} грязных денег.`
`💳 Брутфорс карты\n
${card.bankName.toUpperCase()}
Номер: ${card.cardNumber}
CVV: ${card.cvv}
Владелец: ${card.holderName.toUpperCase()}
Срок действия: ${card.expiresDate}
Взлом успешен! Вы получили Ð${amount}.`
);
});
@ -799,56 +871,44 @@ rpg.action('inventory', async (ctx) => {
return ctx.reply('Персонаж не найден!');
}
const inventory = character.inventory || [];
const equippedItems = character.equippedItems || [];
// Загружаем предметы из инвентаря
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } });
// Если инвентарь пустой
if (inventory.length === 0 && equippedItems.length === 0) {
if (inventory.length === 0) {
return ctx.reply('Ваш инвентарь пуст.');
}
let message = '*Ваш инвентарь:*\n\n';
// Снаряженные предметы
// Группируем предметы по их состоянию (снаряженные/обычные)
const equippedItems = inventory.filter((item) => item.equipped);
const unequippedItems = inventory.filter((item) => !item.equipped);
if (equippedItems.length > 0) {
message += '🛡️ *Снаряженные предметы:*\n';
for (const item of equippedItems) {
if (item) {
equippedItems.forEach((item) => {
message += `- ${item.name} (${item.type})\n`;
}
}
});
message += '\n';
}
// Предметы в инвентаре
if (inventory.length > 0) {
if (unequippedItems.length > 0) {
message += '🎒 *Предметы в инвентаре:*\n';
for (const item of inventory) {
if (item) {
unequippedItems.forEach((item) => {
message += `- ${item.name} (${item.type})\n`;
}
}
});
message += '\n';
}
// Кнопки для взаимодействия
const buttons = [];
for (const item of inventory) {
if (item) {
buttons.push(
const buttons = [
...unequippedItems.map((item) =>
Markup.button.callback(`🎯 Использовать ${item.name}`, `use_item_${item.id}`)
);
}
}
for (const item of equippedItems) {
if (item) {
buttons.push(
Markup.button.callback(`🚫 Снять ${item.name}`, `use_item_${item.id}`)
);
}
}
),
...equippedItems.map((item) =>
Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`)
),
];
await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
} catch (error) {
@ -857,66 +917,64 @@ rpg.action('inventory', async (ctx) => {
}
});
rpg.action(/use_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10);
const character = await CharacterModel.findByPk(ctx.from.id);
const item = await ItemsModel.findByPk(itemId);
const item = await InventoryModel.findByPk(itemId);
const inventory = character.inventory || [];
const isEquipped = character.equippedItems.some((equippedItem) => equippedItem.id === itemId); // Проверяем, снаряжен ли предмет
// Проверка наличия предмета в инвентаре
if (!inventory.some((invItem) => invItem.id === itemId) && !isEquipped) {
return ctx.reply('У вас нет этого предмета.');
if (!item || item.telegram_id != ctx.from.id) {
return ctx.reply('Этот предмет не найден в вашем инвентаре.');
}
// Если предмет уже снаряжен
if (isEquipped) {
// Снимаем предмет
const resultMessages = await character.removeEquippedItem(item); // Убираем предмет из снаряженных
return ctx.reply(`Вы сняли ${item.name}. ${resultMessages}`);
}
// Если предмет имеет временный эффект и уже активен
if (
item.effectData &&
Array.isArray(item.effectData) &&
item.effectData.some((effect) =>
character.activeEffects.some((activeEffect) => activeEffect.type === effect.type)
)
) {
return ctx.reply(`Эффект от ${item.name} уже активен.`);
}
// Обработка эффектов предмета
if (item.effectData && Array.isArray(item.effectData)) {
const resultMessages = processEffects(character, item.effectData, true); // true, так как мы снаряжаем предмет
// Удаляем предмет из инвентаря, если он одноразовый
if (item.type === 'consumable') {
await character.removeItemFromInventory(item);
}
// Если предмет не одноразовый, снаряжаем его
else {
await character.addEquippedItem(item); // Добавляем предмет в снаряженные
}
await character.save(); // Явно сохраняем изменения в базе данных
return ctx.reply(resultMessages);
}
ctx.reply('Этот предмет нельзя использовать.');
});
rpg.command('shop', async (ctx) => {
const character = await CharacterModel.findByPk(ctx.from.id);
if (!character) {
return ctx.reply('Персонаж не найден!');
return ctx.reply('Персонаж не найден.');
}
if (item.equipped) {
return ctx.reply(`${item.name} уже снаряжен.`);
}
// Применяем эффекты предмета
if (item.effectData) {
const resultMessages = processEffects(character, item.effectData, true);
await ctx.reply(resultMessages);
}
// Снаряжаем предмет
item.equipped = true;
await item.save();
ctx.reply(`Вы успешно снарядили ${item.name}.`);
});
rpg.action(/unequip_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10);
const character = await CharacterModel.findByPk(ctx.from.id);
const item = await InventoryModel.findByPk(itemId);
if (!item || item.telegram_id != ctx.from.id) {
return ctx.reply('Этот предмет не найден в вашем инвентаре.');
}
if (!item.equipped) {
return ctx.reply(`${item.name} не снаряжен.`);
}
if (item.effectData) {
const resultMessages = processEffects(character, item.effectData, false);
await ctx.reply(resultMessages);
}
item.equipped = false;
await item.save();
ctx.reply(`Вы успешно сняли ${item.name}.`);
});
rpg.action('shop', async (ctx) => {
const items = await ItemsModel.findAll();
if (items.length === 0) {
@ -925,130 +983,166 @@ rpg.command('shop', async (ctx) => {
let message = 'Добро пожаловать в магазин! Здесь вы можете купить предметы:\n\n';
const buttons = items.map((item) => {
return [Markup.button.callback(`${item.name} - ${item.price}`, `buy_item_${item.id}`)];
});
// Генерируем кнопки, каждая кнопка будет в отдельной строке
const buttons = items.map((item) => [
Markup.button.callback(`${item.name} - ${item.price}`, `buy_item_${item.id}`)
]);
// Отправляем сообщение с клавиатурой
await ctx.reply(message, Markup.inlineKeyboard(buttons));
});
rpg.action(/buy_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10);
const character = await CharacterModel.findByPk(ctx.from.id);
const item = await ItemsModel.findByPk(itemId);
if (!character || !item) {
return ctx.reply('Ошибка: Персонаж или предмет не найдены.');
if (!item) {
return ctx.reply('Предмет не найден.');
}
const character = await CharacterModel.findByPk(ctx.from.id);
if (!character) {
return ctx.reply('Персонаж не найден.');
}
if (character.balance < item.price) {
return ctx.reply('У вас недостаточно средств для покупки этого предмета.');
}
// Снимаем деньги с баланса персонажа
// Снимаем деньги с баланса
character.balance -= item.price;
// Добавляем предмет в инвентарь (в массив)
character.inventory = [...character.inventory, item];
// Добавляем предмет в инвентарь
await InventoryModel.create({
telegram_id: ctx.from.id,
name: item.name,
description: item.description,
effectData: item.effectData,
price: item.price,
rarity: item.rarity,
type: item.type,
duration: item.duration,
equipped: false,
});
await character.save();
// Отправляем сообщение об успешной покупке
await ctx.reply(`Вы успешно купили ${item.name} за ${item.price}₽!`);
// Можно добавить сюда логику для применения эффекта, если он есть
ctx.reply(`Вы успешно купили ${item.name} за ${item.price}₽!`);
});
////////////////////////////////////////////////////////////////////////////////////////////
CharacterModel.prototype.addEquippedItem = async function (item) {
// Проверяем, есть ли уже предмет в инвентаре
const isInInventory = this.inventory.some((invItem) => invItem.id === item.id);
if (!isInInventory) {
return; // Предмет должен быть в инвентаре
// Проверяем, находится ли предмет в инвентаре персонажа
const inventoryItem = await InventoryModel.findOne({
where: { telegram_id: this.telegram_id, id: item.id },
});
if (!inventoryItem) {
throw new Error('Предмет не найден в вашем инвентаре.');
}
// Проверяем, есть ли уже этот предмет в снаряженных
if (!this.equippedItems.some((equippedItem) => equippedItem.id === item.id)) {
this.equippedItems.push(item.id); // Добавляем только ID предмета
this.changed('equippedItems', true); // Помечаем, что поле изменилось
await this.save(); // Сохраняем изменения в базе данных
// Проверяем, не снаряжен ли уже этот предмет
if (inventoryItem.equipped) {
throw new Error('Этот предмет уже снаряжен.');
}
// Снаряжаем предмет
inventoryItem.equipped = true;
await inventoryItem.save();
// Применяем эффекты предмета
let resultMessages = [];
if (inventoryItem.effectData) {
resultMessages = processEffects(this, inventoryItem.effectData, true);
await this.save(); // Сохраняем изменения в характеристиках персонажа
}
return resultMessages;
};
CharacterModel.prototype.removeEquippedItem = async function (item) {
// Проверяем, снаряжен ли предмет
if (this.equippedItems.some((equippedItem) => equippedItem.id === item.id)) {
// Убираем эффект, если он связан с данным предметом
if (item.effectData && Array.isArray(item.effectData)) {
const resultMessages = processEffects(this, item.effectData, false); // false, так как мы снимаем
this.changed('equippedItems', true); // Помечаем изменение массива снаряженных
await this.save();
// Проверяем, находится ли предмет в инвентаре персонажа
const inventoryItem = await InventoryModel.findOne({
where: { telegram_id: this.telegram_id, id: item.id },
});
if (!inventoryItem || !inventoryItem.equipped) {
throw new Error('Этот предмет не снаряжен.');
}
// Снимаем предмет
inventoryItem.equipped = false;
await inventoryItem.save();
// Убираем эффекты предмета
let resultMessages = [];
if (inventoryItem.effectData) {
resultMessages = processEffects(this, inventoryItem.effectData, false);
await this.save(); // Сохраняем изменения в характеристиках персонажа
}
return resultMessages;
}
// Удаляем предмет из снаряженных
this.equippedItems = this.equippedItems.filter((equippedItem) => equippedItem.id !== item.id);
this.changed('equippedItems', true); // Помечаем изменение массива снаряженных
await this.save(); // Сохраняем изменения в базе данных
}
return null;
};
const processEffects = (character, effects, isEquipping) => {
let messages = [];
effects.forEach((effect) => {
// Если предмет снимается (isEquipping = false), эффекты снимаются
if (!isEquipping) {
// Снимаем эффекты
switch (effect.type) {
case 'damage_boost':
character.force -= effect.amount;
character.force = Math.max(0, character.force - effect.amount);
character.save()
messages.push(`Ваш урон уменьшен на ${effect.amount}.`);
break;
case 'max_health_boost':
character.max_hp -= effect.amount;
character.max_hp = Math.max(1, character.max_hp - effect.amount);
character.save()
messages.push(`Ваше максимальное здоровье уменьшено на ${effect.amount}.`);
break;
case 'stamina_penalty':
character.max_stamina += effect.amount;
character.save()
messages.push(`Ваша выносливость увеличена на ${effect.amount}.`);
break;
default:
messages.push('Эффект не распознан при снятии.');
messages.push('Неизвестный эффект при снятии.');
}
} else {
// Применяем эффект при снаряжении
// Применяем эффекты
switch (effect.type) {
case 'heal':
const maxHp = character.maxHp || 100;
character.hp = Math.min(maxHp, character.hp + effect.amount);
character.hp = Math.min(character.max_hp, character.hp + effect.amount);
character.save()
messages.push(`Вы восстановили ${effect.amount} HP.`);
break;
case 'damage_boost':
character.force += effect.amount;
character.save()
messages.push(`Ваш урон увеличен на ${effect.amount}.`);
break;
case 'max_health_boost':
character.max_hp += effect.amount;
character.save()
messages.push(`Ваше максимальное здоровье увеличено на ${effect.amount}.`);
break;
case 'stamina_penalty':
character.max_stamina -= effect.amount;
character.save()
messages.push(`Ваша выносливость уменьшена на ${effect.amount}.`);
break;
default:
messages.push('Эффект не распознан при надевании.');
messages.push('Неизвестный эффект при снаряжении.');
}
}
});
@ -1056,8 +1150,6 @@ const processEffects = (character, effects, isEquipping) => {
return messages.join('\n');
};
function generateKeyboard() {
const buttonsCount = 10;
const buttons = [];