improve calcpayouts
This commit is contained in:
@@ -4,33 +4,131 @@ const torn = require('../../torn.js');
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('calcpayout')
|
||||
.setDescription('[WIP] Calculate war payout based on participation')
|
||||
.setDescription('Calculate war payout based on participation')
|
||||
.addIntegerOption(option =>
|
||||
option.setName('total')
|
||||
.setDescription('Full war earnings total before cuts')),
|
||||
.setDescription('Full war earnings total before cuts')
|
||||
.setRequired(true))
|
||||
.addIntegerOption(option =>
|
||||
option.setName('percentage')
|
||||
.setDescription('Percentage of leader cut (default 10)'))
|
||||
.addStringOption(option =>
|
||||
option.setName('method')
|
||||
.setDescription('Calculation method')
|
||||
.addChoices(
|
||||
{ name: 'Participation Based', value: 'flat' },
|
||||
{ name: 'Score Based', value: 'weighted' },
|
||||
{ name: 'Attack Based', value: 'attacks' },
|
||||
)),
|
||||
async execute(interaction) {
|
||||
const total = interaction.options.getInteger('total');
|
||||
const lastWarRaw = await torn.faction.rankedWars({ offset: 0, limit: 1, sort: 'DESC' });
|
||||
const lastWarID = lastWarRaw[0].id
|
||||
const lastWar = await torn.faction.rankedWarReport(lastWarID);
|
||||
const ourMembers = lastWar.factions.find(faction => faction.id === 53026).members; // TODO: dont hardcore faction ID
|
||||
let totalParticipants = 0;
|
||||
let message = `# War Payout Calculation for War against ${lastWar.factions.find(faction => faction.id !== 53026).name} with total earnings of $${total.toLocaleString()}:\n`;
|
||||
ourMembers.forEach(member => {
|
||||
if (member.id == 2993713) {
|
||||
console.log(`User ${member.name} is calculated separately.`);
|
||||
} else if (member.attacks > 0) {
|
||||
console.log(`${member.name} participated with ${member.attacks} attacks.`);
|
||||
totalParticipants++;
|
||||
message += `- ${member.name}: Participated with a score of ${member.score} from ${member.attacks} attacks.\n`;
|
||||
} else {
|
||||
console.log(`${member.name} did not participate.`);
|
||||
const percentage = interaction.options.getInteger('percentage') ?? 10;
|
||||
const method = interaction.options.getString('method') ?? 'flat';
|
||||
|
||||
// Calculate cuts
|
||||
const leaderCut = Math.ceil(total * (percentage / 100));
|
||||
const pool = total - leaderCut;
|
||||
|
||||
await interaction.deferReply();
|
||||
|
||||
try {
|
||||
const myFaction = await torn.faction.basic();
|
||||
const lastWarRaw = await torn.faction.rankedWars({ offset: 0, limit: 1, sort: 'DESC' });
|
||||
const lastWarID = lastWarRaw[0].id
|
||||
const lastWar = await torn.faction.rankedWarReport(lastWarID);
|
||||
const ourFactionId = myFaction.ID || myFaction.id; // API v1 vs v2 fallback checks
|
||||
const ourFaction = lastWar.factions.find(faction => faction.id === ourFactionId);
|
||||
const enemyFaction = lastWar.factions.find(faction => faction.id !== ourFactionId);
|
||||
|
||||
if (!ourFaction) {
|
||||
return interaction.editReply('Could not find our faction in the last war report.');
|
||||
}
|
||||
});
|
||||
message += `## OseanWorld. earned $${total.toLocaleString()} with Yameii earning 10% off the top for a total of $${Math.ceil(total * 0.1).toLocaleString()}, leaving ${Math.floor(total * 0.9).toLocaleString()} for ${totalParticipants} participants.\n`;
|
||||
message += `## Dividing that out gives each participant approximately $${Math.floor((total * 0.9) / totalParticipants).toLocaleString()} each.`;
|
||||
console.log(`there were ${totalParticipants} participants`);
|
||||
console.log(message)
|
||||
interaction.reply(message);
|
||||
|
||||
const members = ourFaction.members;
|
||||
const participants = [];
|
||||
const nonParticipants = [];
|
||||
let totalScore = 0;
|
||||
let totalAttacks = 0;
|
||||
|
||||
// Filter members
|
||||
for (const memberId in members) {
|
||||
const member = members[memberId];
|
||||
|
||||
if (member.id == myFaction.leader_id) {
|
||||
console.log(`User ${member.name} skipped (Leader exclusion).`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (member.attacks > 0) {
|
||||
participants.push(member);
|
||||
totalScore += member.score;
|
||||
totalAttacks += member.attacks;
|
||||
} else {
|
||||
nonParticipants.push(member);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort logic
|
||||
if (method === 'attacks') {
|
||||
participants.sort((a, b) => b.attacks - a.attacks);
|
||||
} else {
|
||||
participants.sort((a, b) => b.score - a.score);
|
||||
}
|
||||
|
||||
|
||||
let message = `# War Payout: ${ourFaction.name} vs ${enemyFaction.name}\n`;
|
||||
message += `**Total Earnings:** $${total.toLocaleString()}\n`;
|
||||
message += `**Leader Cut (${percentage}%):** $${leaderCut.toLocaleString()} (Yameii)\n`;
|
||||
message += `**Distributable Pool:** $${pool.toLocaleString()}\n`;
|
||||
|
||||
let methodText = 'Participation Based';
|
||||
if (method === 'weighted') methodText = 'Score Based';
|
||||
if (method === 'attacks') methodText = 'Attack Based';
|
||||
|
||||
message += `**Calculation Method:** ${methodText}\n`;
|
||||
message += `**Participants:** ${participants.length}\n\n`;
|
||||
|
||||
message += `## Payouts\n`;
|
||||
|
||||
if (method === 'weighted') {
|
||||
participants.forEach(member => {
|
||||
const share = (member.score / totalScore);
|
||||
const payout = Math.floor(pool * share);
|
||||
message += `- **${member.name}**: $${payout.toLocaleString()} (${(share * 100).toFixed(2)}% of pool | Score: ${member.score})\n`;
|
||||
});
|
||||
} else if (method === 'attacks') {
|
||||
participants.forEach(member => {
|
||||
const share = (member.attacks / totalAttacks);
|
||||
const payout = Math.floor(pool * share);
|
||||
message += `- **${member.name}**: $${payout.toLocaleString()} (${(share * 100).toFixed(2)}% of pool | Attacks: ${member.attacks})\n`;
|
||||
});
|
||||
} else {
|
||||
const payout = Math.floor(pool / participants.length);
|
||||
participants.forEach(member => {
|
||||
message += `- **${member.name}**: $${payout.toLocaleString()}\n`;
|
||||
});
|
||||
}
|
||||
|
||||
if (nonParticipants.length > 0) {
|
||||
message += `\n## Non-Participants\n`;
|
||||
message += nonParticipants.map(m => m.name).join(', ');
|
||||
}
|
||||
|
||||
// Discord message limit is 2000 chars. If we have many members, it might split.
|
||||
// For now, assuming it fits or valid first chunk.
|
||||
if (message.length > 2000) {
|
||||
const chunks = message.match(/[\s\S]{1,1900}/g) || [];
|
||||
for (const chunk of chunks) {
|
||||
if (chunk === chunks[0]) await interaction.editReply(chunk);
|
||||
else await interaction.followUp(chunk);
|
||||
}
|
||||
} else {
|
||||
await interaction.editReply(message);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await interaction.editReply('An error occurred while calculating payouts.');
|
||||
}
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user