v5.3
Menu rework Inventory system Shop
This commit is contained in:
parent
125b782a64
commit
7e6980207f
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
160
rpg.js
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user