Menu rework
Inventory system
Shop
This commit is contained in:
Degradin 2025-01-10 19:09:05 +03:00
parent 125b782a64
commit 7e6980207f
5 changed files with 156 additions and 43 deletions

View File

@ -1,5 +1,6 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../db');
const { faker } = require('@faker-js/faker');
const Inventory = sequelize.define('inventory', {
id: {
@ -18,6 +19,11 @@ const Inventory = sequelize.define('inventory', {
type: DataTypes.STRING,
allowNull: false,
},
text_id: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: faker.string.uuid()
},
description: {
type: DataTypes.TEXT,
allowNull: false,
@ -42,6 +48,10 @@ const Inventory = sequelize.define('inventory', {
type: DataTypes.INTEGER,
allowNull: true
}, // Длительность эффекта в секундах
canBeEquipped: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
equipped: {
type: DataTypes.BOOLEAN,
defaultValue: false

View File

@ -1,5 +1,6 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../db');
const { faker } = require('@faker-js/faker');
const Item = sequelize.define('item', {
id: {
@ -7,6 +8,11 @@ const Item = sequelize.define('item', {
autoIncrement: true,
primaryKey: true,
},
text_id: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: faker.string.uuid()
},
name: {
type: DataTypes.STRING,
allowNull: false,
@ -35,6 +41,10 @@ const Item = sequelize.define('item', {
type: DataTypes.INTEGER,
allowNull: true
}, // Длительность эффекта в секундах
canBeEquipped: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
});
module.exports = Item;

View File

@ -5,7 +5,9 @@ const World = sequelize.define('world', {
id: {type: DataTypes.INTEGER, primaryKey: true, unique: true},
balance: {type: DataTypes.INTEGER, defaultValue: 50000000},
transactionfee: {type: DataTypes.INTEGER, defaultValue: 1},
matPrice: {type: DataTypes.INTEGER, defaultValue: 100}
matPrice: {type: DataTypes.INTEGER, defaultValue: 100},
itemsInCrimeShop: { type: DataTypes.ARRAY(DataTypes.INTEGER), defaultValue: [] }
})
module.exports = World;

160
rpg.js
View File

@ -92,8 +92,10 @@ rpg.action('rpg_profile', async (ctx) => {
`;
// Отправляем сообщение
ctx.reply(profile.trim(), Markup.inlineKeyboard([
[Markup.button.callback('💼 Задачи', 'crime_missions')],
ctx.editMessageText(profile.trim(), Markup.inlineKeyboard([
[Markup.button.callback('💳 Карточки', 'view_cards')],
[Markup.button.callback('🎒 Инвентарь', 'inventory')],
[Markup.button.callback('🔙 В меню', 'crime_menu')],
]));
});
@ -105,7 +107,7 @@ const usersCrimeNet = new Set();
rpg.hears('CampFireGG.Crime', async (ctx) => {
const userId = ctx.from.id;
const character = await CharacterModel.findOne({ where: { telegram_id: userId } });
if (!usersCrimeNet.has(userId) && userId != 275416286){
if (!usersCrimeNet.has(userId) && character.level === 1){
// Если пользователь вводит команду впервые
usersCrimeNet.add(userId);
const username = ctx.from.username || 'User';
@ -171,8 +173,6 @@ 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('💰 Магазин', 'shop')],
])
);
@ -241,6 +241,7 @@ rpg.action('view_cards', async (ctx) => {
buttons.push([
Markup.button.callback(`💳 *${lastFourDigits}`, `brutecard_${card.id}`),
//Markup.button.callback(`💰 *${lastFourDigits}`, `limitbuy_${card.id}`)
Markup.button.callback('🔙 В меню', 'crime_menu'),
]);
});
@ -374,7 +375,7 @@ rpg.action(/brutecard_/, async (ctx) => {
}
// Проверяем наличие "Эмулятора картридера" в инвентаре
const emulator = inventory.find((item) => item.name === 'Эмулятор картридера');
const emulator = inventory.find((item) => item.text_id === 'cardreader_emulator');
if (!emulator) {
return ctx.reply('Для запуска брутфорса вам нужен "Эмулятор картридера".');
}
@ -393,13 +394,15 @@ rpg.action(/brutecard_/, async (ctx) => {
// Генерация кнопок
const buttons = [];
let fakePin = 1234
for (let i = 1; i <= buttonsCount; i++) {
if (i === winButton) {
// Если это победная кнопка (правильный ПИН)
buttons.push({ text: `${card.pin}`, callback_data: `brute_success_${cardId}` });
} else {
fakePin = faker.finance.pin()
// Если это неудачная кнопка (случайный ПИН)
buttons.push({ text: `${faker.finance.pin()}`, callback_data: `brute_fail_${cardId}` });
buttons.push({ text: `${fakePin}`, callback_data: `brute_fail_${cardId}_${i}` });
}
}
@ -462,12 +465,14 @@ rpg.action(/brute_fail_/, async (ctx) => {
const buttonsCount = 10;
const winButton = utils.rand(1, buttonsCount);
const buttons = [];
let fakePin = 1234
for (let i = 1; i <= buttonsCount; i++) {
fakePin = faker.finance.pin()
if (i === winButton) {
buttons.push({ text: `${card.pin}`, callback_data: `brute_success_${cardId}` });
} else {
buttons.push({ text: `${faker.finance.pin()}`, callback_data: `brute_fail_${cardId}` });
buttons.push({ text: `${fakePin}`, callback_data: `brute_fail_${cardId}_${i}` });
}
}
@ -501,9 +506,7 @@ rpg.action(/brute_fail_/, async (ctx) => {
rpg.action(/brute_success_/, async (ctx) => {
const cardId = ctx.match.input.split('_')[2];
console.log(cardId)
const card = await StolenCardsModel.findByPk(cardId);
console.log(card)
if (!card) {
return ctx.answerCbQuery('Карточка не найдена.');
}
@ -549,7 +552,7 @@ rpg.action('crime_missions', async (ctx) => {
//[{text: 'Угон', callback_data: `WIP`}],
// [{text: 'Ювелирка', callback_data: `WIP`}],
//[{text: 'Банк', callback_data: `WIP`}],
[{text: '🔙 Back to Menu', callback_data: `crime_menu`}]
[{text: '🔙 В меню', callback_data: `crime_menu`}]
]),
);
});
@ -623,9 +626,7 @@ rpg.action(`PHONE`, async (ctx) => {
}
let randPhone = utils.rand(1,10)
if (property.mobile.name) {
console.log(Math.round(phones[randPhone].price/100*70))
let dirtyMoney = Math.round(phones[randPhone].price/100*70)
console.log(character.intelligence + 10)
Exp(ctx, character, character.intelligence + 10)
character.dirtymoney += dirtyMoney
return await ctx.reply(`Вы сбыли украденный ${phones[randPhone].name} за Ð${utils.spaces(dirtyMoney)}`)
@ -726,8 +727,8 @@ rpg.action('crime_menu', async (ctx) => {
`💻 CampFireGG.Crime Menu`,
Markup.inlineKeyboard([
[Markup.button.callback('💼 Задачи', 'crime_missions')],
[Markup.button.callback('📊 Профиль', 'crime_stats')],
[Markup.button.callback('💰 ...', 'crime_market')],
[Markup.button.callback('📊 Профиль', 'rpg_profile')],
[Markup.button.callback('💰 Магазин', 'shop')],
])
);
});
@ -885,7 +886,7 @@ rpg.action('inventory', async (ctx) => {
const unequippedItems = inventory.filter((item) => !item.equipped);
if (equippedItems.length > 0) {
message += '🛡️ *Снаряженные предметы:*\n';
message += '🛡️ Снаряженные предметы:\n';
equippedItems.forEach((item) => {
message += `- ${item.name} (${item.type})\n`;
});
@ -893,7 +894,7 @@ rpg.action('inventory', async (ctx) => {
}
if (unequippedItems.length > 0) {
message += '🎒 *Предметы в инвентаре:*\n';
message += '🎒 Предметы в инвентаре:\n';
unequippedItems.forEach((item) => {
message += `- ${item.name} (${item.type})\n`;
});
@ -903,20 +904,50 @@ rpg.action('inventory', async (ctx) => {
// Кнопки для взаимодействия
const buttons = [
...unequippedItems.map((item) =>
Markup.button.callback(`🎯 Использовать ${item.name}`, `use_item_${item.id}`)
Markup.button.callback(`🔎 ${item.name}`, `view_item_${item.id}`)
),
...equippedItems.map((item) =>
Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`)
),
];
buttons.push(Markup.button.callback('🔙 В меню', 'crime_menu'));
await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
await ctx.editMessageText(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
} catch (error) {
console.error('Ошибка при выводе инвентаря:', error);
await ctx.reply('Произошла ошибка при отображении вашего инвентаря.');
}
});
rpg.action(/view_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10);
const item = await InventoryModel.findByPk(itemId);
if (!item || item.telegram_id != ctx.from.id) {
return ctx.reply('Этот предмет не найден в вашем инвентаре.');
}
const character = await CharacterModel.findByPk(ctx.from.id);
if (!character) {
return ctx.reply('Персонаж не найден.');
}
if (item.equipped) {
return ctx.reply(`${item.name} уже снаряжен.`);
}
const buttons = []
let message = ` ${item.name}\n`
message += ` 📜 ${item.description}\n\n 〰️Редкость: ${item.rarity}\n 🔤Тип: ${item.type}`
if (!item.equipped){
buttons.push([Markup.button.callback(`🎯 Использовать ${item.name}`, `use_item_${item.id}`)]);
}
if (item.equipped && item.canBeEquipped) {
buttons.push([Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`)]);
}
await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
});
rpg.action(/use_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10);
@ -936,17 +967,25 @@ rpg.action(/use_item_(\d+)/, async (ctx) => {
return ctx.reply(`${item.name} уже снаряжен.`);
}
if (!item.canBeEquipped) {
return ctx.answerCbQuery(`🚫 ${item.name} нельзя сейчас использовать.`);
}
// Применяем эффекты предмета
if (item.effectData) {
const resultMessages = processEffects(character, item.effectData, true);
await ctx.reply(resultMessages);
await ctx.answerCbQuery(resultMessages, {show_alert: true});
}
// Снаряжаем предмет
item.equipped = true;
await item.save();
ctx.reply(`Вы успешно снарядили ${item.name}.`);
if (item.canBeEquipped && item.type != 'consumable') {
item.equipped = true;
await item.save();
ctx.reply(`Вы снарядили ${item.name}.`);
}
if (item.canBeEquipped && item.type == 'consumable') {
await InventoryModel.destroy({ where: { id: item.id } });
ctx.reply(`Вы использовали ${item.name}.`);
}
});
rpg.action(/unequip_item_(\d+)/, async (ctx) => {
@ -955,47 +994,65 @@ rpg.action(/unequip_item_(\d+)/, async (ctx) => {
const item = await InventoryModel.findByPk(itemId);
if (!item || item.telegram_id != ctx.from.id) {
return ctx.reply('Этот предмет не найден в вашем инвентаре.');
return ctx.answerCbQuery('Этот предмет не найден в вашем инвентаре.');
}
if (!item.equipped) {
return ctx.reply(`${item.name} не снаряжен.`);
return ctx.answerCbQuery(`${item.name} не снаряжен.`);
}
if (item.effectData) {
const resultMessages = processEffects(character, item.effectData, false);
await ctx.reply(resultMessages);
await ctx.editMessageText(resultMessages);
}
item.equipped = false;
await item.save();
ctx.reply(`Вы успешно сняли ${item.name}.`);
ctx.answerCbQuery(`Вы успешно сняли ${item.name}.`);
});
rpg.action('shop', async (ctx) => {
const items = await ItemsModel.findAll();
// Получаем текущую запись мира
const world = await WorldModel.findOne({ where: { id: 1 } });
if (!world) {
return ctx.reply('Магазин недоступен.');
}
// Получаем ID предметов, доступных в магазине
const { itemsInCrimeShop } = world;
if (!itemsInCrimeShop || itemsInCrimeShop.length === 0) {
return ctx.reply('Магазин пуст!');
}
// Загружаем только те предметы, ID которых есть в массиве
const items = await ItemsModel.findAll({ where: { id: itemsInCrimeShop } });
if (items.length === 0) {
return ctx.reply('Магазин пуст!');
return ctx.reply('Магазин пуст!');
}
let message = 'Добро пожаловать в магазин! Здесь вы можете купить предметы:\n\n';
// Генерируем кнопки, каждая кнопка будет в отдельной строке
const buttons = items.map((item) => [
Markup.button.callback(`${item.name} - ${item.price}`, `buy_item_${item.id}`)
Markup.button.callback(`${item.name} - ${item.price}`, `buy_item_${item.id}`)
]);
buttons.push([Markup.button.callback('🔙 В меню', 'crime_menu')]);
// Отправляем сообщение с клавиатурой
await ctx.reply(message, Markup.inlineKeyboard(buttons));
await ctx.editMessageText(message, Markup.inlineKeyboard(buttons));
});
rpg.action(/buy_item_(\d+)/, async (ctx) => {
const itemId = parseInt(ctx.match[1], 10);
const item = await ItemsModel.findByPk(itemId);
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } });
if (inventory.length >= 15) {
return ctx.answerCbQuery('Инвентарь полон.', {show_alert: true});
}
if (!item) {
return ctx.reply('Предмет не найден.');
@ -1008,27 +1065,29 @@ rpg.action(/buy_item_(\d+)/, async (ctx) => {
}
if (character.balance < item.price) {
return ctx.reply('У вас недостаточно средств для покупки этого предмета.');
return ctx.answerCbQuery('У вас недостаточно средств для покупки этого предмета.', {show_alert: true});
}
// Снимаем деньги с баланса
character.balance -= item.price;
character.dirtymoney -= item.price;
// Добавляем предмет в инвентарь
await InventoryModel.create({
telegram_id: ctx.from.id,
name: item.name,
text_id: item.text_id,
description: item.description,
effectData: item.effectData,
price: item.price,
rarity: item.rarity,
type: item.type,
duration: item.duration,
equipped: false,
canBeEquipped: item.canBeEquipped,
equipped: false
});
await character.save();
ctx.reply(`Вы успешно купили ${item.name} за ${item.price}₽!`);
ctx.answerCbQuery(`Вы успешно купили ${item.name} за ${item.price}₽!`, {show_alert: true});
});
////////////////////////////////////////////////////////////////////////////////////////////
@ -1111,6 +1170,12 @@ const processEffects = (character, effects, isEquipping) => {
messages.push(`Ваша выносливость увеличена на ${effect.amount}.`);
break;
case 'intelligence_boost':
character.intelligence -= Math.max(0, character.intelligence - effect.amount);
character.save()
messages.push(`Ваш интеллект уменьшена на ${effect.amount}.`);
break;
default:
messages.push('Неизвестный эффект при снятии.');
}
@ -1126,7 +1191,7 @@ const processEffects = (character, effects, isEquipping) => {
case 'damage_boost':
character.force += effect.amount;
character.save()
messages.push(`Ваш урон увеличен на ${effect.amount}.`);
messages.push(`Ваша сила увеличена на ${effect.amount}.`);
break;
case 'max_health_boost':
@ -1141,6 +1206,18 @@ const processEffects = (character, effects, isEquipping) => {
messages.push(`Ваша выносливость уменьшена на ${effect.amount}.`);
break;
case 'stamina_recover':
character.stamina = Math.min(character.max_stamina, character.stamina + effect.amount);
character.save()
messages.push(`Вы восстановили ${effect.amount} стамины.`);
break;
case 'intelligence_boost':
character.intelligence += effect.amount;
character.save()
messages.push(`Ваш интеллект увеличен на ${effect.amount}.`);
break;
default:
messages.push('Неизвестный эффект при снаряжении.');
}
@ -1248,7 +1325,7 @@ const reduceStealedCards = async () => {
await card.destroy(); // Удаляем карточки
}
console.log(`Карточки для персонажа ${character.id} успешно обновлены.`);
console.log(`Карточки для персонажа ${character.name} успешно обновлены.`);
}
}
@ -1260,7 +1337,6 @@ const reduceStealedCards = async () => {
async function generateCard(userId, balance) {
console.log(balance)
if(!Number(balance)){
balance = faker.finance.amount({dec: 0})*100
console.log('Random balance: ' + balance)

15
signs Normal file
View File

@ -0,0 +1,15 @@
Ð
💳
💼
📊
💰
📛
⏏️
🛡️
🎒
🎯
🚫
📜
〰️
🔤