AeThex-Bot-Master/aethex-bot/commands/heist.js
sirpiglr c2a34f398e Add server mode configuration and dynamic status updates
Introduces a new server mode configuration system (Federation/Standalone) with associated command changes, dynamic status rotation for the bot, and adds new commands and features.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: b08e6ba5-7498-4b9f-b1c9-7dc11b362ddd
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/R9PkDi8
Replit-Helium-Checkpoint-Created: true
2025-12-09 23:26:33 +00:00

189 lines
7.3 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const { getServerMode, getEmbedColor, EMBED_COLORS } = require('../utils/modeHelper');
const { updateStandaloneXp } = require('../utils/standaloneXp');
const activeHeists = new Map();
const TARGETS = [
{ name: 'Corner Store', emoji: '🏪', difficulty: 0.7, minReward: 20, maxReward: 50 },
{ name: 'Gas Station', emoji: '⛽', difficulty: 0.6, minReward: 30, maxReward: 70 },
{ name: 'Jewelry Store', emoji: '💎', difficulty: 0.5, minReward: 50, maxReward: 120 },
{ name: 'Bank', emoji: '🏦', difficulty: 0.4, minReward: 80, maxReward: 200 },
{ name: 'Casino', emoji: '🎰', difficulty: 0.3, minReward: 100, maxReward: 300 },
{ name: 'Federal Reserve', emoji: '🏛️', difficulty: 0.2, minReward: 150, maxReward: 500 },
];
module.exports = {
data: new SlashCommandBuilder()
.setName('heist')
.setDescription('Start a group heist!')
.addStringOption(option =>
option.setName('target')
.setDescription('Choose your heist target')
.setRequired(true)
.addChoices(
{ name: '🏪 Corner Store (Easy)', value: '0' },
{ name: '⛽ Gas Station', value: '1' },
{ name: '💎 Jewelry Store', value: '2' },
{ name: '🏦 Bank (Medium)', value: '3' },
{ name: '🎰 Casino', value: '4' },
{ name: '🏛️ Federal Reserve (Hard)', value: '5' }
)
),
async execute(interaction, supabase, client) {
const targetIndex = parseInt(interaction.options.getString('target'));
const target = TARGETS[targetIndex];
const leader = interaction.user;
const mode = await getServerMode(supabase, interaction.guildId);
const guildId = interaction.guildId;
const heistKey = `${guildId}-heist`;
if (activeHeists.has(heistKey)) {
return interaction.reply({
content: 'There\'s already an active heist in this server! Wait for it to finish.',
ephemeral: true
});
}
const participants = new Set([leader.id]);
activeHeists.set(heistKey, {
target,
leader: leader.id,
participants,
usernames: { [leader.id]: leader.username }
});
const embed = new EmbedBuilder()
.setColor(getEmbedColor(mode))
.setTitle(`${target.emoji} Heist: ${target.name}`)
.setDescription(`${leader} is planning a heist!\n\nClick **Join Heist** to participate.\nMore participants = higher success chance!`)
.addFields(
{ name: '🎯 Target', value: target.name, inline: true },
{ name: '💰 Reward', value: `${target.minReward}-${target.maxReward} XP each`, inline: true },
{ name: '📊 Base Success', value: `${Math.round(target.difficulty * 100)}%`, inline: true },
{ name: '👥 Participants', value: `1. ${leader.username}` }
)
.setFooter({ text: 'Heist starts in 60 seconds!' })
.setTimestamp();
const row = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId(`heist_join_${guildId}`)
.setLabel('Join Heist')
.setStyle(ButtonStyle.Primary)
.setEmoji('🔫'),
new ButtonBuilder()
.setCustomId(`heist_start_${guildId}`)
.setLabel('Start Now')
.setStyle(ButtonStyle.Success)
.setEmoji('🚀')
);
const message = await interaction.reply({ embeds: [embed], components: [row], fetchReply: true });
const collector = message.createMessageComponentCollector({
filter: i => i.customId.startsWith('heist_'),
time: 60000
});
collector.on('collect', async (i) => {
const heistData = activeHeists.get(heistKey);
if (!heistData) return;
if (i.customId.startsWith('heist_join')) {
if (heistData.participants.has(i.user.id)) {
return i.reply({ content: 'You\'re already in this heist!', ephemeral: true });
}
heistData.participants.add(i.user.id);
heistData.usernames[i.user.id] = i.user.username;
const participantList = Array.from(heistData.participants)
.map((id, idx) => `${idx + 1}. ${heistData.usernames[id]}`)
.join('\n');
const bonusChance = (heistData.participants.size - 1) * 5;
const totalChance = Math.min(95, Math.round(target.difficulty * 100) + bonusChance);
embed.spliceFields(3, 1, { name: '👥 Participants', value: participantList });
embed.spliceFields(2, 1, { name: '📊 Success Chance', value: `${totalChance}%`, inline: true });
await i.update({ embeds: [embed] });
}
if (i.customId.startsWith('heist_start') && i.user.id === heistData.leader) {
collector.stop('started');
}
});
collector.on('end', async (collected, reason) => {
const heistData = activeHeists.get(heistKey);
if (!heistData) return;
activeHeists.delete(heistKey);
const participantCount = heistData.participants.size;
const bonusChance = (participantCount - 1) * 5;
const successChance = Math.min(95, target.difficulty * 100 + bonusChance) / 100;
const success = Math.random() < successChance;
if (success) {
const baseReward = Math.floor(Math.random() * (target.maxReward - target.minReward + 1)) + target.minReward;
const teamBonus = Math.floor(baseReward * (participantCount - 1) * 0.1);
const totalReward = baseReward + teamBonus;
for (const participantId of heistData.participants) {
if (mode === 'standalone') {
await updateStandaloneXp(supabase, participantId, guildId, totalReward, heistData.usernames[participantId]);
} else if (supabase) {
try {
const { data: profile } = await supabase
.from('user_profiles')
.select('xp')
.eq('discord_id', participantId)
.maybeSingle();
if (profile) {
await supabase
.from('user_profiles')
.update({ xp: (profile.xp || 0) + totalReward })
.eq('discord_id', participantId);
}
} catch (e) {}
}
}
const participantMentions = Array.from(heistData.participants)
.map(id => `<@${id}>`)
.join(', ');
const successEmbed = new EmbedBuilder()
.setColor(EMBED_COLORS.success)
.setTitle(`${target.emoji} Heist Successful!`)
.setDescription(`The crew pulled off the ${target.name} heist!`)
.addFields(
{ name: '👥 Crew', value: participantMentions },
{ name: '💰 Each Earned', value: `${totalReward} XP` }
)
.setTimestamp();
await interaction.editReply({ embeds: [successEmbed], components: [] });
} else {
const failEmbed = new EmbedBuilder()
.setColor(EMBED_COLORS.error)
.setTitle(`${target.emoji} Heist Failed!`)
.setDescription(`The ${target.name} heist went wrong! The crew escaped empty-handed.`)
.addFields({
name: '👥 Crew',
value: Array.from(heistData.participants).map(id => heistData.usernames[id]).join(', ')
})
.setTimestamp();
await interaction.editReply({ embeds: [failEmbed], components: [] });
}
});
},
};