Compare commits
3 Commits
c99a96c201
...
1957991182
| Author | SHA1 | Date | |
|---|---|---|---|
| 1957991182 | |||
| a126de21d4 | |||
| 71e53c8014 |
@@ -0,0 +1,14 @@
|
|||||||
|
const {
|
||||||
|
showNutHub
|
||||||
|
} = require("../../utils/nutHub");
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutHubBack",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return showNutHub(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
showNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutHubBlackjack",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return showNutBlackjack(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
const {
|
||||||
|
startNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutBlackjackBet10",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return startNutBlackjack(
|
||||||
|
interaction,
|
||||||
|
10
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
const {
|
||||||
|
startNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutBlackjackBet100",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return startNutBlackjack(
|
||||||
|
interaction,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
const {
|
||||||
|
startNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutBlackjackBet1000",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return startNutBlackjack(
|
||||||
|
interaction,
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
const {
|
||||||
|
startNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutBlackjackBet50",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return startNutBlackjack(
|
||||||
|
interaction,
|
||||||
|
50
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
const {
|
||||||
|
startNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutBlackjackBet500",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return startNutBlackjack(
|
||||||
|
interaction,
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
doubleNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutBlackjackDouble",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return doubleNutBlackjack(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
hitNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutBlackjackHit",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return hitNutBlackjack(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
standNutBlackjack
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutBlackjack"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutBlackjackStand",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return standNutBlackjack(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
showNutHeist
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutHeist"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutHubHeist",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return showNutHeist(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// buttons/nutHub/heistHack.js
|
||||||
|
|
||||||
|
const {
|
||||||
|
performNutHeist
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutHeist"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutHeistHack",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return performNutHeist(
|
||||||
|
interaction,
|
||||||
|
"Hack"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// buttons/nutHub/heistSmash.js
|
||||||
|
|
||||||
|
const {
|
||||||
|
performNutHeist
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutHeist"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutHeistSmash",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return performNutHeist(
|
||||||
|
interaction,
|
||||||
|
"Smash"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// buttons/nutHub/heistSneak.js
|
||||||
|
|
||||||
|
const {
|
||||||
|
performNutHeist
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutHeist"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutHeistSneak",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return performNutHeist(
|
||||||
|
interaction,
|
||||||
|
"Sneak"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// buttons/nutHub/roulette.js
|
||||||
|
|
||||||
|
const {
|
||||||
|
showNutRoulette
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutRoulette"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutHubRoulette",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return showNutRoulette(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteBet10.js
|
||||||
|
const {
|
||||||
|
chooseNutRouletteBet
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteBet10",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return chooseNutRouletteBet(
|
||||||
|
interaction,
|
||||||
|
10
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteBet100.js
|
||||||
|
const {
|
||||||
|
chooseNutRouletteBet
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteBet100",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return chooseNutRouletteBet(
|
||||||
|
interaction,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteBet1000.js
|
||||||
|
const {
|
||||||
|
chooseNutRouletteBet
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteBet1000",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return chooseNutRouletteBet(
|
||||||
|
interaction,
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteBet50.js
|
||||||
|
const {
|
||||||
|
chooseNutRouletteBet
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteBet50",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return chooseNutRouletteBet(
|
||||||
|
interaction,
|
||||||
|
50
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteBet500.js
|
||||||
|
const {
|
||||||
|
chooseNutRouletteBet
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteBet500",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return chooseNutRouletteBet(
|
||||||
|
interaction,
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteBlack.js
|
||||||
|
const {
|
||||||
|
playNutRoulette
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteBlack",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return playNutRoulette(
|
||||||
|
interaction,
|
||||||
|
"Black"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteEven.js
|
||||||
|
const {
|
||||||
|
playNutRoulette
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteEven",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return playNutRoulette(
|
||||||
|
interaction,
|
||||||
|
"Even"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteOdd.js
|
||||||
|
const {
|
||||||
|
playNutRoulette
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteOdd",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return playNutRoulette(
|
||||||
|
interaction,
|
||||||
|
"Odd"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteRed.js
|
||||||
|
const {
|
||||||
|
playNutRoulette
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteRed",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return playNutRoulette(
|
||||||
|
interaction,
|
||||||
|
"Red"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// buttons/nutHub/rouletteZero.js
|
||||||
|
const {
|
||||||
|
playNutRoulette
|
||||||
|
} = require("../../utils/nutRoulette");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: "nutRouletteZero",
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
return playNutRoulette(
|
||||||
|
interaction,
|
||||||
|
"Zero"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
playNutSlots
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutSlots"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutSlotsBet10",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return playNutSlots(
|
||||||
|
interaction,
|
||||||
|
10
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
playNutSlots
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutSlots"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutSlotsBet100",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return playNutSlots(
|
||||||
|
interaction,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
playNutSlots
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutSlots"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutSlotsBet1000",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return playNutSlots(
|
||||||
|
interaction,
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
playNutSlots
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutSlots"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutSlotsBet50",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return playNutSlots(
|
||||||
|
interaction,
|
||||||
|
50
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const {
|
||||||
|
playNutSlots
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutSlots"
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutSlotsBet500",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return playNutSlots(
|
||||||
|
interaction,
|
||||||
|
500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// buttons/nutHub/slots.js
|
||||||
|
|
||||||
|
const {
|
||||||
|
showNutSlots
|
||||||
|
} = require(
|
||||||
|
"../../utils/nutSlots"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutHubSlots",
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return showNutSlots(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -13,11 +13,11 @@ module.exports = {
|
|||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
const db = mClient.db(process.env.M_DB)
|
||||||
const nutsColl = db.collection('items_nuts')
|
const nutsColl = db.collection('items_nuts')
|
||||||
await nutsColl.findOneAndUpdate({ userID: from.id }, { $inc: { nuts: -amount } }, { upsert: true })
|
await nutsColl.findOneAndUpdate({ userId: from.id }, { $inc: { nuts: -amount } }, { upsert: true })
|
||||||
await nutsColl.findOneAndUpdate({ userID: to.id }, { $inc: { nuts: +amount } }, { upsert: true })
|
await nutsColl.findOneAndUpdate({ userId: to.id }, { $inc: { nuts: +amount } }, { upsert: true })
|
||||||
|
|
||||||
const yourBalance = await nutsColl.findOne({ userID: from.id })
|
const yourBalance = await nutsColl.findOne({ userId: from.id })
|
||||||
const theirBalance = await nutsColl.findOne({ userID: to.id })
|
const theirBalance = await nutsColl.findOne({ userId: to.id })
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setTitle('Gib Nuss!')
|
.setTitle('Gib Nuss!')
|
||||||
.setDescription(`Willst du wirklich **${amount}** Nüsse an <@${to.id}> senden?`)
|
.setDescription(`Willst du wirklich **${amount}** Nüsse an <@${to.id}> senden?`)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ module.exports = {
|
|||||||
const db = mClient.db(process.env.M_DB)
|
const db = mClient.db(process.env.M_DB)
|
||||||
const nutsColl = db.collection('items_nuts')
|
const nutsColl = db.collection('items_nuts')
|
||||||
|
|
||||||
const yourBalance = await nutsColl.findOne({ userID: from.id })
|
const yourBalance = await nutsColl.findOne({ userId: from.id })
|
||||||
const theirBalance = await nutsColl.findOne({ userID: to.id })
|
const theirBalance = await nutsColl.findOne({ userId: to.id })
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setTitle('Gib Nuss!')
|
.setTitle('Gib Nuss!')
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ module.exports = {
|
|||||||
let fields
|
let fields
|
||||||
nutsData.forEach((data) => {
|
nutsData.forEach((data) => {
|
||||||
skip++
|
skip++
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userID}> : ${data.nuts} Nuts\r\n`)
|
fields = (fields ? fields : '') + (`${skip}. <@${data.userId}> : ${data.nuts} Nuts\r\n`)
|
||||||
})
|
})
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setTitle('Nuts Leaderboard')
|
.setTitle('Nuts Leaderboard')
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ module.exports = {
|
|||||||
let fields
|
let fields
|
||||||
nutsData.forEach((data) => {
|
nutsData.forEach((data) => {
|
||||||
skip++
|
skip++
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userID}> : ${data.nuts} Nuts\r\n`)
|
fields = (fields ? fields : '') + (`${skip}. <@${data.userId}> : ${data.nuts} Nuts\r\n`)
|
||||||
})
|
})
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setTitle('Nuts Leaderboard')
|
.setTitle('Nuts Leaderboard')
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module.exports = {
|
|||||||
const db = mClient.db(process.env.M_DB)
|
const db = mClient.db(process.env.M_DB)
|
||||||
const nutsColl = db.collection('items_nuts')
|
const nutsColl = db.collection('items_nuts')
|
||||||
|
|
||||||
const self = await nutsColl.find({ userID: interaction.user.id }).toArray()
|
const self = await nutsColl.find({ userId: interaction.user.id }).toArray()
|
||||||
const all = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).toArray()
|
const all = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).toArray()
|
||||||
|
|
||||||
function findIndex(){
|
function findIndex(){
|
||||||
@@ -16,7 +16,7 @@ module.exports = {
|
|||||||
for (let i = 0; i < all.length; i++) {
|
for (let i = 0; i < all.length; i++) {
|
||||||
index++
|
index++
|
||||||
if (all[i].nuts === self[0].nuts) {
|
if (all[i].nuts === self[0].nuts) {
|
||||||
return index
|
return index - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ module.exports = {
|
|||||||
let fields
|
let fields
|
||||||
nutsData.forEach((data) => {
|
nutsData.forEach((data) => {
|
||||||
skip++
|
skip++
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userID}> : ${data.nuts} Nuts\r\n`)
|
fields = (fields ? fields : '') + (`${skip}. <@${data.userId}> : ${data.nuts} Nuts\r\n`)
|
||||||
})
|
})
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setTitle('Nuts Leaderboard')
|
.setTitle('Nuts Leaderboard')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const ping = require("../../../src/ping")
|
const ping = require("../../../utils/ping")
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'ping',
|
name: 'ping',
|
||||||
|
|||||||
@@ -1,54 +1,158 @@
|
|||||||
const { EmbedBuilder } = require('discord.js')
|
const {
|
||||||
const { mClient } = require('../../../index')
|
EmbedBuilder
|
||||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
} = require("discord.js");
|
||||||
require('dotenv').config()
|
|
||||||
|
const {
|
||||||
|
getNutBalance
|
||||||
|
} = require(
|
||||||
|
"../../../utils/nutEconomy"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
function delay(ms) {
|
||||||
|
return new Promise(
|
||||||
|
resolve =>
|
||||||
|
setTimeout(
|
||||||
|
resolve,
|
||||||
|
ms
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'checknuts',
|
name:
|
||||||
description: 'get nuts',
|
"checknuts",
|
||||||
aliases: ['chn'],
|
|
||||||
async execute(message, args) {
|
description:
|
||||||
var target = message.author
|
"get nuts",
|
||||||
var addressing = `Du hast`
|
|
||||||
if (args[0]) {
|
aliases: [
|
||||||
if (!args[0].startsWith('<@' || !args[0].endsWith('>'))) { return message.reply('Invalid User Specification') }
|
"chn"
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
message,
|
||||||
|
args
|
||||||
|
) {
|
||||||
|
let target =
|
||||||
|
message.author;
|
||||||
|
|
||||||
|
|
||||||
|
let addressing =
|
||||||
|
"Du hast";
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
args[0]
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!args[0].startsWith("<@")
|
||||||
|
||
|
||||||
|
!args[0].endsWith(">")
|
||||||
|
) {
|
||||||
|
return message.reply(
|
||||||
|
"Invalid User Specification"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
target = await message.guild.members.fetch(args[0].slice(2, -1))
|
target =
|
||||||
|
await message.guild.members.fetch(
|
||||||
|
args[0].slice(
|
||||||
|
2,
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return message.reply({
|
return message.reply({
|
||||||
content: `User: ${args[0]} nicht gefunden!`
|
content:
|
||||||
}).then(async (msg) => {
|
`User: ${args[0]} nicht gefunden!`
|
||||||
await delay(4000)
|
|
||||||
message.delete()
|
|
||||||
msg.delete()
|
|
||||||
})
|
})
|
||||||
|
.then(
|
||||||
|
async msg => {
|
||||||
|
await delay(
|
||||||
|
4000
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
message.delete();
|
||||||
|
msg.delete();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.user.id !== message.author.id) {
|
|
||||||
if (!target.user.globalName) {
|
|
||||||
addressing = `${target.user.username} hat`
|
|
||||||
} else {
|
|
||||||
addressing = `${target.user.globalName} hat`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_nuts')
|
|
||||||
var nutsData = await nutsColl.findOne({ userID: target.id })
|
|
||||||
|
|
||||||
let content
|
if (
|
||||||
if (!nutsData) {
|
target.user.id !==
|
||||||
content = `${addressing} noch keine Nüsse gesammelt :(`
|
message.author.id
|
||||||
} else {
|
) {
|
||||||
content = `${addressing} bereits **${nutsData.nuts}** Nüsse gesammelt!`
|
if (
|
||||||
|
!target.user.globalName
|
||||||
|
) {
|
||||||
|
addressing =
|
||||||
|
`${target.user.username} hat`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Checknuts!')
|
else {
|
||||||
.setThumbnail(target.displayAvatarURL())
|
addressing =
|
||||||
.setDescription(content)
|
`${target.user.globalName} hat`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const targetId =
|
||||||
|
target.id
|
||||||
|
??
|
||||||
|
target.user?.id;
|
||||||
|
|
||||||
|
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
targetId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
let content;
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
balance <=
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
content =
|
||||||
|
`${addressing} noch keine Nüsse gesammelt :(`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
else {
|
||||||
|
content =
|
||||||
|
`${addressing} bereits **${balance}** Nüsse gesammelt!`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"Checknuts!"
|
||||||
|
)
|
||||||
|
.setThumbnail(
|
||||||
|
target.displayAvatarURL()
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
content
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
return message.reply({
|
return message.reply({
|
||||||
embeds: [embed]
|
embeds: [
|
||||||
})
|
embed
|
||||||
|
]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
@@ -1,31 +1,88 @@
|
|||||||
const { EmbedBuilder } = require('discord.js')
|
const {
|
||||||
const { mClient } = require('../../../index')
|
EmbedBuilder
|
||||||
require('dotenv').config()
|
} = require("discord.js");
|
||||||
module.exports = {
|
|
||||||
name: 'nutsCooldown',
|
|
||||||
description: 'shows nut cooldown',
|
|
||||||
aliases: ['ncd'],
|
|
||||||
async execute(message, args) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_cooldowns')
|
|
||||||
const cooldown = await nutsColl.findOne({ userID: message.author.id })
|
|
||||||
|
|
||||||
let content = `Du kannst wieder nussen! :)`
|
const {
|
||||||
let thumbnail = 'https://cdn-icons-png.flaticon.com/512/7451/7451659.png'
|
getCooldown,
|
||||||
let title = 'Go Nuts!'
|
getUnixTime
|
||||||
if (cooldown) {
|
} = require(
|
||||||
content = `<t:${cooldown.cooldown}:R> kannst du wieder nussen! ;)`
|
"../../../utils/nutEconomy"
|
||||||
thumbnail = 'https://cdn.discordapp.com/attachments/1152723542836772914/1152987472788193361/No-nuts-PhotoRoom.png-PhotoRoom.png'
|
);
|
||||||
title = 'To Nut or Not to Nut...'
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"nutsCooldown",
|
||||||
|
|
||||||
|
description:
|
||||||
|
"shows nut cooldown",
|
||||||
|
|
||||||
|
aliases: [
|
||||||
|
"ncd"
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
message,
|
||||||
|
args
|
||||||
|
) {
|
||||||
|
const cooldown =
|
||||||
|
await getCooldown(
|
||||||
|
message.author.id,
|
||||||
|
"nut"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const now =
|
||||||
|
getUnixTime();
|
||||||
|
|
||||||
|
|
||||||
|
let content =
|
||||||
|
"Du kannst wieder nussen! :)";
|
||||||
|
|
||||||
|
|
||||||
|
let thumbnail =
|
||||||
|
"https://cdn-icons-png.flaticon.com/512/7451/7451659.png";
|
||||||
|
|
||||||
|
|
||||||
|
let title =
|
||||||
|
"Go Nuts!";
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
cooldown >
|
||||||
|
now
|
||||||
|
) {
|
||||||
|
content =
|
||||||
|
`<t:${cooldown}:R> kannst du wieder nussen! ;)`;
|
||||||
|
|
||||||
|
|
||||||
|
thumbnail =
|
||||||
|
"https://cdn.discordapp.com/attachments/1152723542836772914/1152987472788193361/No-nuts-PhotoRoom.png-PhotoRoom.png";
|
||||||
|
|
||||||
|
|
||||||
|
title =
|
||||||
|
"To Nut or Not to Nut...";
|
||||||
}
|
}
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setThumbnail(thumbnail)
|
const embed =
|
||||||
.setTitle(title)
|
new EmbedBuilder()
|
||||||
.setDescription(content)
|
.setThumbnail(
|
||||||
|
thumbnail
|
||||||
|
)
|
||||||
|
.setTitle(
|
||||||
|
title
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
content
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
await message.reply({
|
await message.reply({
|
||||||
embeds: [embed]
|
embeds: [
|
||||||
})
|
embed
|
||||||
|
]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
+118
-51
@@ -1,64 +1,131 @@
|
|||||||
const { mClient } = require('../../../index')
|
const {
|
||||||
require('dotenv').config()
|
getCollections,
|
||||||
|
changeNuts,
|
||||||
|
claimCooldown,
|
||||||
|
randomInteger
|
||||||
|
} = require(
|
||||||
|
"../../../utils/nutEconomy"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'nuts',
|
name:
|
||||||
description: 'get nuts',
|
"nuts",
|
||||||
aliases: ['n', 'nget', 'nutsget'],
|
|
||||||
async execute(message, args) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_nuts')
|
|
||||||
const nutsStatsColl = db.collection('stats_nuts')
|
|
||||||
const cdColl = db.collection('items_cooldowns')
|
|
||||||
const cdData = await cdColl.findOne({ userID: message.author.id })
|
|
||||||
|
|
||||||
if (cdData?.cooldown > (Date.now() / 1000)) {
|
description:
|
||||||
return await message.reply({
|
"get nuts",
|
||||||
content: `Du kannst erst <t:${Math.floor(cdData?.cooldown)}:R> wieder nussen :(`,
|
|
||||||
})
|
aliases: [
|
||||||
|
"n",
|
||||||
|
"nget",
|
||||||
|
"nutsget"
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
message,
|
||||||
|
args
|
||||||
|
) {
|
||||||
|
const {
|
||||||
|
db
|
||||||
|
} =
|
||||||
|
getCollections();
|
||||||
|
|
||||||
|
|
||||||
|
const nutsStatsColl =
|
||||||
|
db.collection(
|
||||||
|
"stats_nuts"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const cooldown =
|
||||||
|
await claimCooldown(
|
||||||
|
message.author.id,
|
||||||
|
"nut",
|
||||||
|
60 * 60
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!cooldown.claimed
|
||||||
|
) {
|
||||||
|
return message.reply({
|
||||||
|
content:
|
||||||
|
`Du kannst erst <t:${cooldown.next}:R> wieder nussen :(`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let cd = Math.floor((Date.now() + 3600000) / 1000)
|
|
||||||
await cdColl.findOneAndUpdate({
|
|
||||||
userID: message.author.id
|
|
||||||
}, {
|
|
||||||
$set: {
|
|
||||||
cooldown: cd,
|
|
||||||
application: 'nuts'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
upsert: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const amount = Math.floor(Math.random() * 10)
|
const amount =
|
||||||
|
randomInteger(
|
||||||
|
0,
|
||||||
|
9
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
await changeNuts(
|
||||||
|
message.author.id,
|
||||||
|
amount
|
||||||
|
);
|
||||||
|
|
||||||
await nutsColl.findOneAndUpdate({
|
|
||||||
userID: message.author.id
|
|
||||||
}, {
|
|
||||||
$inc: { nuts: amount }
|
|
||||||
}, {
|
|
||||||
upsert: true
|
|
||||||
})
|
|
||||||
|
|
||||||
await nutsStatsColl.findOneAndUpdate(
|
await nutsStatsColl.findOneAndUpdate(
|
||||||
{ userID: message.author.id },
|
{
|
||||||
{ $inc: { [`stat.${amount}`]: 1 } },
|
userId:
|
||||||
{ upsert: true }
|
message.author.id
|
||||||
)
|
},
|
||||||
|
{
|
||||||
|
$inc: {
|
||||||
|
[`stat.${amount}`]:
|
||||||
|
1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
upsert:
|
||||||
|
true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
await nutsStatsColl.findOneAndUpdate(
|
await nutsStatsColl.findOneAndUpdate(
|
||||||
{ userID: "__global" },
|
{
|
||||||
{ $inc: { [`stat.${amount}`]: 1 } },
|
userId:
|
||||||
{ upsert: true }
|
"__global"
|
||||||
)
|
},
|
||||||
// Helper for singular/plural
|
{
|
||||||
const formatNut = (amount) => `${amount === 1 ? 'eine' : amount} ${amount === 1 ? 'Nuss' : 'Nüsse'}`
|
$inc: {
|
||||||
|
[`stat.${amount}`]:
|
||||||
|
1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
upsert:
|
||||||
|
true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
let nutText = `Du hast ${formatNut(amount)} bekommen! :chestnut:`
|
|
||||||
if (amount <= 0) {
|
const formatNut =
|
||||||
nutText = `Du hast keine Nuss bekommen! :yoink_help:`
|
amount =>
|
||||||
|
`${amount === 1 ? "eine" : amount} ${amount === 1 ? "Nuss" : "Nüsse"}`;
|
||||||
|
|
||||||
|
|
||||||
|
let nutText =
|
||||||
|
`Du hast ${formatNut(amount)} bekommen! :chestnut:`;
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
amount <=
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
nutText =
|
||||||
|
"Du hast keine Nuss bekommen! :yoink_help:";
|
||||||
}
|
}
|
||||||
return await message.reply({
|
|
||||||
content: nutText
|
|
||||||
})
|
return message.reply({
|
||||||
|
content:
|
||||||
|
nutText
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
@@ -1,78 +1,224 @@
|
|||||||
const { EmbedBuilder } = require('discord.js')
|
const {
|
||||||
const { mClient } = require('../../../index')
|
EmbedBuilder
|
||||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
} = require("discord.js");
|
||||||
require('dotenv').config()
|
|
||||||
module.exports = {
|
|
||||||
name: 'givenuts',
|
|
||||||
description: 'give nuts',
|
|
||||||
aliases: ['gn'],
|
|
||||||
async execute(message, args) {
|
|
||||||
const from = message.author
|
|
||||||
if (args[0] == `<@${message.author.id}>` || !args[0]) {
|
|
||||||
return message.reply({
|
|
||||||
content: "Du musst einen anderen User erwähnen"
|
|
||||||
}).then(async (msg) => {
|
|
||||||
await delay(4000)
|
|
||||||
message.delete()
|
|
||||||
msg.delete()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (!args[0].startsWith('<@' || !args[0].endsWith('>'))) { return message.reply('Invalid User Specification') }
|
|
||||||
try {
|
|
||||||
target = await message.guild.members.fetch(args[0].slice(2, -1))
|
|
||||||
} catch (error) {
|
|
||||||
return message.reply({
|
|
||||||
content: `User: ${args[0]} nicht gefunden!`
|
|
||||||
}).then(async (msg) => {
|
|
||||||
await delay(4000)
|
|
||||||
message.delete()
|
|
||||||
msg.delete()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const to = target
|
|
||||||
|
|
||||||
try {
|
const {
|
||||||
var amount = Number(args[1])
|
getNutBalance,
|
||||||
} catch (error) {
|
transferNuts
|
||||||
console.log(error)
|
} = require(
|
||||||
return message.reply({
|
"../../../utils/nutEconomy"
|
||||||
content: 'Du musst eine Menge angeben!'
|
);
|
||||||
}).then(async (msg) => {
|
|
||||||
await delay(4000)
|
|
||||||
message.delete()
|
|
||||||
msg.delete()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (!amount) {
|
|
||||||
return message.reply({content : 'Danke für nichts, du Hu-'})
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_nuts')
|
|
||||||
const yourBalance = await nutsColl.findOne({ userID: from.id })
|
|
||||||
if (amount <= 0) {
|
|
||||||
return await message.reply({
|
|
||||||
content: `Hier wird nicht geklaut >:(\r\nDas gibt **${yourBalance.nuts}** Abzug!`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (yourBalance.nuts < amount) {
|
|
||||||
return await message.reply({
|
|
||||||
content: 'Du kannst nicht mehr geben als du hast!',
|
|
||||||
ephemeral: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
var content = `Du sendest **${amount}** Nüsse an <@${target.id}>`
|
|
||||||
|
|
||||||
if (amount == 1) {
|
function delay(ms) {
|
||||||
content = `Du sendest **eine** Nuss an <@${target.id}>`
|
return new Promise(
|
||||||
}
|
resolve =>
|
||||||
await nutsColl.findOneAndUpdate({ userID: from.id }, { $inc: { nuts: -amount } }, { upsert: true })
|
setTimeout(
|
||||||
await nutsColl.findOneAndUpdate({ userID: to.id }, { $inc: { nuts: +amount } }, { upsert: true })
|
resolve,
|
||||||
|
ms
|
||||||
const embed = new EmbedBuilder()
|
)
|
||||||
.setTitle('Gib Nuss!')
|
);
|
||||||
.setDescription(content)
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
return message.reply({ embeds: [embed] })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name:
|
||||||
|
"givenuts",
|
||||||
|
|
||||||
|
description:
|
||||||
|
"give nuts",
|
||||||
|
|
||||||
|
aliases: [
|
||||||
|
"gn"
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
message,
|
||||||
|
args
|
||||||
|
) {
|
||||||
|
const from =
|
||||||
|
message.author;
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
args[0] ==
|
||||||
|
`<@${message.author.id}>`
|
||||||
|
||
|
||||||
|
!args[0]
|
||||||
|
) {
|
||||||
|
return message.reply({
|
||||||
|
content:
|
||||||
|
"Du musst einen anderen User erwähnen"
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
async msg => {
|
||||||
|
await delay(
|
||||||
|
4000
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
message.delete();
|
||||||
|
msg.delete();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!args[0].startsWith("<@")
|
||||||
|
||
|
||||||
|
!args[0].endsWith(">")
|
||||||
|
) {
|
||||||
|
return message.reply(
|
||||||
|
"Invalid User Specification"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let target;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
target =
|
||||||
|
await message.guild.members.fetch(
|
||||||
|
args[0].slice(
|
||||||
|
2,
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return message.reply({
|
||||||
|
content:
|
||||||
|
`User: ${args[0]} nicht gefunden!`
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
async msg => {
|
||||||
|
await delay(
|
||||||
|
4000
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
message.delete();
|
||||||
|
msg.delete();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const to =
|
||||||
|
target;
|
||||||
|
|
||||||
|
|
||||||
|
let amount;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
amount =
|
||||||
|
Number(
|
||||||
|
args[1]
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return message.reply({
|
||||||
|
content:
|
||||||
|
"Du musst eine Menge angeben!"
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
async msg => {
|
||||||
|
await delay(
|
||||||
|
4000
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
message.delete();
|
||||||
|
msg.delete();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!amount
|
||||||
|
) {
|
||||||
|
return message.reply({
|
||||||
|
content:
|
||||||
|
"Danke für nichts, du Hu-"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const yourBalance =
|
||||||
|
await getNutBalance(
|
||||||
|
from.id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
amount <=
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
return message.reply({
|
||||||
|
content:
|
||||||
|
`Hier wird nicht geklaut >:(\r\nDas gibt **${yourBalance}** Abzug!`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
yourBalance <
|
||||||
|
amount
|
||||||
|
) {
|
||||||
|
return message.reply({
|
||||||
|
content:
|
||||||
|
"Du kannst nicht mehr geben als du hast!"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let content =
|
||||||
|
`Du sendest **${amount}** Nüsse an <@${target.id}>`;
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
amount ==
|
||||||
|
1
|
||||||
|
) {
|
||||||
|
content =
|
||||||
|
`Du sendest **eine** Nuss an <@${target.id}>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await transferNuts(
|
||||||
|
from.id,
|
||||||
|
to.id,
|
||||||
|
amount
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"Gib Nuss!"
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
content
|
||||||
|
)
|
||||||
|
.setThumbnail(
|
||||||
|
target.displayAvatarURL()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return message.reply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,49 +1,162 @@
|
|||||||
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js')
|
const {
|
||||||
const { mClient } = require('../../../index')
|
EmbedBuilder,
|
||||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
ActionRowBuilder,
|
||||||
require('dotenv').config()
|
ButtonBuilder,
|
||||||
|
ButtonStyle
|
||||||
|
} = require("discord.js");
|
||||||
|
|
||||||
|
const {
|
||||||
|
getCollections
|
||||||
|
} = require(
|
||||||
|
"../../../utils/nutEconomy"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'nutsleaderboard',
|
name:
|
||||||
description: 'show nuts leaderboard',
|
"nutsleaderboard",
|
||||||
aliases: ['nl', 'tn', 'topnuts'],
|
|
||||||
async execute(message, args) {
|
description:
|
||||||
const row = new ActionRowBuilder()
|
"show nuts leaderboard",
|
||||||
|
|
||||||
|
aliases: [
|
||||||
|
"nl",
|
||||||
|
"tn",
|
||||||
|
"topnuts"
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
message,
|
||||||
|
args
|
||||||
|
) {
|
||||||
|
const row =
|
||||||
|
new ActionRowBuilder()
|
||||||
.addComponents(
|
.addComponents(
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
.setLabel('◄')
|
.setLabel(
|
||||||
.setStyle(ButtonStyle.Primary)
|
"◄"
|
||||||
.setCustomId('nuts_leaderboard_left')
|
|
||||||
)
|
)
|
||||||
.addComponents(
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
)
|
||||||
|
.setCustomId(
|
||||||
|
"nuts_leaderboard_left"
|
||||||
|
),
|
||||||
|
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
.setLabel('🧑')
|
.setLabel(
|
||||||
.setStyle(ButtonStyle.Primary)
|
"🧑"
|
||||||
.setCustomId('nuts_leaderboard_self')
|
|
||||||
)
|
)
|
||||||
.addComponents(
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
)
|
||||||
|
.setCustomId(
|
||||||
|
"nuts_leaderboard_self"
|
||||||
|
),
|
||||||
|
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
.setLabel('►')
|
.setLabel(
|
||||||
.setStyle(ButtonStyle.Primary)
|
"►"
|
||||||
.setCustomId('nuts_leaderboard_right')
|
|
||||||
)
|
)
|
||||||
const db = mClient.db(process.env.M_DB)
|
.setStyle(
|
||||||
const nutsColl = db.collection('items_nuts')
|
ButtonStyle.Primary
|
||||||
let skip = 0
|
)
|
||||||
const nutsData = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).skip(skip).limit(5).toArray()
|
.setCustomId(
|
||||||
let fields
|
"nuts_leaderboard_right"
|
||||||
let placements = skip + 1
|
)
|
||||||
nutsData.forEach((data) => {
|
);
|
||||||
fields = (fields ? fields : '') + (`${placements}. <@${data.userID}> : ${data.nuts} Nuts\r\n`)
|
|
||||||
})
|
|
||||||
const embed = new EmbedBuilder()
|
const {
|
||||||
.setTitle('Nuts Leaderboard')
|
nuts
|
||||||
.setThumbnail(message.guild.iconURL({ dynamic: true}))
|
} =
|
||||||
.setDescription(fields.toString())
|
getCollections();
|
||||||
.setColor('#5865F2') // Discord's blurple color
|
|
||||||
.setFooter({ text: 'Use ◄ ► to navigate' });
|
|
||||||
await message.reply({
|
const skip =
|
||||||
embeds: [embed],
|
0;
|
||||||
components: [row]
|
|
||||||
})
|
|
||||||
|
const nutsData =
|
||||||
|
await nuts
|
||||||
|
.find({
|
||||||
|
nuts: {
|
||||||
|
$gt:
|
||||||
|
0
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.sort({
|
||||||
|
nuts:
|
||||||
|
-1
|
||||||
|
})
|
||||||
|
.skip(
|
||||||
|
skip
|
||||||
|
)
|
||||||
|
.limit(
|
||||||
|
5
|
||||||
|
)
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
|
||||||
|
let fields;
|
||||||
|
|
||||||
|
|
||||||
|
let placements =
|
||||||
|
skip +
|
||||||
|
1;
|
||||||
|
|
||||||
|
|
||||||
|
nutsData.forEach(
|
||||||
|
data => {
|
||||||
|
fields =
|
||||||
|
(
|
||||||
|
fields
|
||||||
|
?
|
||||||
|
fields
|
||||||
|
:
|
||||||
|
""
|
||||||
|
)
|
||||||
|
+
|
||||||
|
`${placements}. <@${data.userId}> : ${data.nuts} Nuts\r\n`;
|
||||||
|
|
||||||
|
|
||||||
|
placements++;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"Nuts Leaderboard"
|
||||||
|
)
|
||||||
|
.setThumbnail(
|
||||||
|
message.guild.iconURL({
|
||||||
|
dynamic:
|
||||||
|
true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
fields.toString()
|
||||||
|
)
|
||||||
|
.setColor(
|
||||||
|
"#5865F2"
|
||||||
|
)
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
"Use ◄ ► to navigate"
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
await message.reply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components: [
|
||||||
|
row
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
const { SlashCommandBuilder } = require("discord.js");
|
const { SlashCommandBuilder } = require("discord.js");
|
||||||
const ping = require("../../../src/ping");
|
const ping = require("../../../utils/ping");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const { mClient } = require('../../..');
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB); // adjust if needed
|
const db = mClient.db(process.env.M_DB); // adjust if needed
|
||||||
const coll = db.collection('items_daily_numbers');
|
const coll = db.collection('items_ezd');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// commands/applications/nutHub.js
|
||||||
|
|
||||||
|
const {
|
||||||
|
SlashCommandBuilder
|
||||||
|
} = require("discord.js");
|
||||||
|
|
||||||
|
const {
|
||||||
|
showNutHub
|
||||||
|
} = require(
|
||||||
|
"../../../utils/nutHub"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data:
|
||||||
|
new SlashCommandBuilder()
|
||||||
|
.setName(
|
||||||
|
"nuthub"
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
"open the Nut Hub"
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
return showNutHub(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
+1409
-349
File diff suppressed because it is too large
Load Diff
+167
-29
@@ -60,83 +60,199 @@ async function selectMenuHandler(interaction) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getParticipantWeight(participant, now = Date.now()) {
|
||||||
|
// Never selected before -> strongly favor them
|
||||||
|
if (!participant.lastExpertAt) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastExpertAt = new Date(participant.lastExpertAt).getTime();
|
||||||
|
|
||||||
|
// Invalid date safety
|
||||||
|
if (Number.isNaN(lastExpertAt)) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
const daysSinceExpert = Math.max(
|
||||||
|
0,
|
||||||
|
(now - lastExpertAt) / (24 * 60 * 60 * 1000)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Square-root weighting prevents very old participants
|
||||||
|
* from completely dominating the random selection.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* 1 day -> ~1.41
|
||||||
|
* 7 days -> ~2.83
|
||||||
|
* 30 days -> ~5.57
|
||||||
|
*/
|
||||||
|
return Math.sqrt(daysSinceExpert + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function weightedRandom(participants) {
|
||||||
|
if (!participants.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const weightedParticipants = participants.map(participant => ({
|
||||||
|
participant,
|
||||||
|
weight: getParticipantWeight(participant)
|
||||||
|
}));
|
||||||
|
|
||||||
|
const totalWeight = weightedParticipants.reduce(
|
||||||
|
(total, item) => total + item.weight,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
let random = Math.random() * totalWeight;
|
||||||
|
|
||||||
|
for (const item of weightedParticipants) {
|
||||||
|
random -= item.weight;
|
||||||
|
|
||||||
|
if (random <= 0) {
|
||||||
|
return item.participant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floating-point safety fallback
|
||||||
|
return weightedParticipants[weightedParticipants.length - 1].participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectWgeParticipant(
|
||||||
|
participateColl,
|
||||||
|
{ excludeUserId = null } = {}
|
||||||
|
) {
|
||||||
|
const filter = {
|
||||||
|
status: true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (excludeUserId) {
|
||||||
|
filter.userID = {
|
||||||
|
$ne: excludeUserId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const participants = await participateColl
|
||||||
|
.find(filter)
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
return weightedRandom(participants);
|
||||||
|
}
|
||||||
|
|
||||||
async function modalSubmitHandler(interaction) {
|
async function modalSubmitHandler(interaction) {
|
||||||
if (interaction.customId !== 'wgeBaseModal') return;
|
if (interaction.customId !== 'wgeBaseModal') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const db = mClient.db('neo-db');
|
const db = mClient.db('neo-db');
|
||||||
|
|
||||||
const wgeColl = db.collection('timer_wge');
|
const wgeColl = db.collection('timer_wge');
|
||||||
const participateColl = db.collection('items_wge');
|
const participateColl = db.collection('items_wge');
|
||||||
const historyWgeColl = db.collection('history_wge');
|
const historyWgeColl = db.collection('history_wge');
|
||||||
|
|
||||||
const assigningUser = interaction.user;
|
const assigningUser = interaction.user;
|
||||||
const selectedUserId = interaction.components[0].component.values[0];
|
|
||||||
const topic = interaction.fields.getTextInputValue('wgeTopicInput');
|
|
||||||
const defaultAssignedTime = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
||||||
|
|
||||||
// Get current running WGE so we can exclude the current expert
|
const selectedUserId =
|
||||||
|
interaction.components[0].component.values[0];
|
||||||
|
|
||||||
|
const topic = interaction.fields.getTextInputValue(
|
||||||
|
'wgeTopicInput'
|
||||||
|
);
|
||||||
|
|
||||||
|
const defaultAssignedTime =
|
||||||
|
7 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
// Get current running WGE so the previous expert
|
||||||
|
// cannot immediately be selected again.
|
||||||
const prevWge = await wgeColl.findOne({
|
const prevWge = await wgeColl.findOne({
|
||||||
debug: false,
|
debug: false,
|
||||||
state: 'running'
|
state: 'running'
|
||||||
});
|
});
|
||||||
|
|
||||||
let assignedUser;
|
let assignedUser;
|
||||||
|
let selectedParticipant;
|
||||||
|
|
||||||
// Random assignment
|
// ---------------------------------
|
||||||
|
// RANDOM / WEIGHTED ASSIGNMENT
|
||||||
|
// ---------------------------------
|
||||||
if (selectedUserId === process.env.D_ID) {
|
if (selectedUserId === process.env.D_ID) {
|
||||||
const randomParticipant = await participateColl.aggregate([
|
selectedParticipant = await selectWgeParticipant(
|
||||||
|
participateColl,
|
||||||
{
|
{
|
||||||
$match: {
|
excludeUserId: prevWge?.assignedUser
|
||||||
status: true,
|
|
||||||
...(prevWge && {
|
|
||||||
userID: { $ne: prevWge.assignedUser }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
);
|
||||||
{ $sample: { size: 1 } }
|
|
||||||
]).toArray();
|
|
||||||
|
|
||||||
if (randomParticipant.length === 0) {
|
if (!selectedParticipant) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: 'There are no eligible participants available.',
|
content:
|
||||||
|
'There are no eligible participants available.',
|
||||||
|
flags: MessageFlags.Ephemeral
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = await interaction.guild.members
|
||||||
|
.fetch(selectedParticipant.userID)
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
|
if (!member) {
|
||||||
|
return interaction.reply({
|
||||||
|
content:
|
||||||
|
'The selected participant could not be found in the server.',
|
||||||
flags: MessageFlags.Ephemeral
|
flags: MessageFlags.Ephemeral
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = await interaction.guild.members.fetch(randomParticipant[0].userID);
|
|
||||||
assignedUser = member.user;
|
assignedUser = member.user;
|
||||||
}
|
}
|
||||||
// Manual assignment
|
|
||||||
|
// ---------------------------------
|
||||||
|
// MANUAL ASSIGNMENT
|
||||||
|
// ---------------------------------
|
||||||
else {
|
else {
|
||||||
const participant = await participateColl.findOne({
|
selectedParticipant = await participateColl.findOne({
|
||||||
userID: selectedUserId,
|
userID: selectedUserId,
|
||||||
status: true
|
status: true
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!participant) {
|
if (!selectedParticipant) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: `<@${selectedUserId}> is not participating!`,
|
content:
|
||||||
|
`<@${selectedUserId}> is not participating!`,
|
||||||
flags: MessageFlags.Ephemeral
|
flags: MessageFlags.Ephemeral
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevWge && selectedUserId === prevWge.assignedUser) {
|
if (
|
||||||
|
prevWge &&
|
||||||
|
selectedUserId === prevWge.assignedUser
|
||||||
|
) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: `<@${selectedUserId}> was the previous expert and cannot be selected again this round.`,
|
content:
|
||||||
|
`<@${selectedUserId}> was the previous expert and cannot be selected again this round.`,
|
||||||
flags: MessageFlags.Ephemeral
|
flags: MessageFlags.Ephemeral
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
assignedUser = { id: selectedUserId };
|
assignedUser = {
|
||||||
|
id: selectedUserId
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Archive previous WGE
|
// ---------------------------------
|
||||||
|
// ARCHIVE PREVIOUS WGE
|
||||||
|
// ---------------------------------
|
||||||
if (prevWge) {
|
if (prevWge) {
|
||||||
await historyWgeColl.insertOne({
|
await historyWgeColl.insertOne({
|
||||||
assignedUser: prevWge.assignedUser,
|
assignedUser: prevWge.assignedUser,
|
||||||
assigningUser: prevWge.assigningUser,
|
assigningUser: prevWge.assigningUser,
|
||||||
|
|
||||||
timeRemaining: prevWge.timeRemaining,
|
timeRemaining: prevWge.timeRemaining,
|
||||||
|
|
||||||
topic: prevWge.topic,
|
topic: prevWge.topic,
|
||||||
debug: prevWge.debug,
|
debug: prevWge.debug,
|
||||||
|
|
||||||
createdAt: prevWge.createdAt
|
createdAt: prevWge.createdAt
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -150,7 +266,28 @@ async function modalSubmitHandler(interaction) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new WGE
|
const assignedAt = new Date();
|
||||||
|
|
||||||
|
// ---------------------------------
|
||||||
|
// UPDATE PARTICIPANT STATISTICS
|
||||||
|
// ---------------------------------
|
||||||
|
await participateColl.updateOne(
|
||||||
|
{
|
||||||
|
_id: selectedParticipant._id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
lastExpertAt: assignedAt
|
||||||
|
},
|
||||||
|
$inc: {
|
||||||
|
expertCount: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// ---------------------------------
|
||||||
|
// CREATE NEW WGE
|
||||||
|
// ---------------------------------
|
||||||
await wgeColl.insertOne({
|
await wgeColl.insertOne({
|
||||||
assignedUser: assignedUser.id,
|
assignedUser: assignedUser.id,
|
||||||
assigningUser: assigningUser.id,
|
assigningUser: assigningUser.id,
|
||||||
@@ -169,10 +306,11 @@ async function modalSubmitHandler(interaction) {
|
|||||||
topic,
|
topic,
|
||||||
debug: false,
|
debug: false,
|
||||||
|
|
||||||
createdAt: new Date()
|
createdAt: assignedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: `<@${assignedUser.id}> is the next expert! Their topic is **${topic}**`
|
content:
|
||||||
|
`<@${assignedUser.id}> is the next expert! Their topic is **${topic}**`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ module.exports = {
|
|||||||
)?.[1];
|
)?.[1];
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
const numberedColl = db.collection("items_daily_numbers");
|
const numberedColl = db.collection("items_ezd");
|
||||||
|
|
||||||
const today = new Date().toLocaleDateString("en-CA", {
|
const today = new Date().toLocaleDateString("en-CA", {
|
||||||
timeZone: "Europe/Berlin"
|
timeZone: "Europe/Berlin"
|
||||||
|
|||||||
+202
-52
@@ -1,78 +1,219 @@
|
|||||||
const { mClient } = require("..");
|
const { mClient } = require('..');
|
||||||
|
|
||||||
async function getMember(client, userId) {
|
async function getMember(client, userId) {
|
||||||
const guild = client.guilds.cache.get(process.env.D_GuildID);
|
const guild = client.guilds.cache.get(process.env.D_GuildID);
|
||||||
if (!guild) return null;
|
|
||||||
|
|
||||||
// cache first (fast path)
|
if (!guild) {
|
||||||
let member = guild.members.cache.get(userId);
|
return null;
|
||||||
|
|
||||||
// fallback (safe path)
|
|
||||||
if (!member) {
|
|
||||||
member = await guild.members.fetch(userId).catch(() => null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return member;
|
return (
|
||||||
|
guild.members.cache.get(userId) ||
|
||||||
|
await guild.members.fetch(userId).catch(() => null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function getParticipantWeight(participant, now = Date.now()) {
|
||||||
|
// Never selected before -> strongly favor them
|
||||||
|
if (!participant.lastExpertAt) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastExpertAt = new Date(participant.lastExpertAt).getTime();
|
||||||
|
|
||||||
|
// Invalid date safety
|
||||||
|
if (Number.isNaN(lastExpertAt)) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
const daysSinceExpert = Math.max(
|
||||||
|
0,
|
||||||
|
(now - lastExpertAt) / (24 * 60 * 60 * 1000)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Square-root weighting prevents very old participants
|
||||||
|
* from completely dominating the random selection.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* 1 day -> ~1.41
|
||||||
|
* 7 days -> ~2.83
|
||||||
|
* 30 days -> ~5.57
|
||||||
|
*/
|
||||||
|
return Math.sqrt(daysSinceExpert + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function weightedRandom(participants) {
|
||||||
|
if (!participants.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const weightedParticipants = participants.map(participant => ({
|
||||||
|
participant,
|
||||||
|
weight: getParticipantWeight(participant)
|
||||||
|
}));
|
||||||
|
|
||||||
|
const totalWeight = weightedParticipants.reduce(
|
||||||
|
(total, item) => total + item.weight,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
let random = Math.random() * totalWeight;
|
||||||
|
|
||||||
|
for (const item of weightedParticipants) {
|
||||||
|
random -= item.weight;
|
||||||
|
|
||||||
|
if (random <= 0) {
|
||||||
|
return item.participant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floating-point safety fallback
|
||||||
|
return weightedParticipants[weightedParticipants.length - 1].participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectWgeParticipant(
|
||||||
|
participateColl,
|
||||||
|
{ excludeUserId = null } = {}
|
||||||
|
) {
|
||||||
|
const filter = {
|
||||||
|
status: true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (excludeUserId) {
|
||||||
|
filter.userID = {
|
||||||
|
$ne: excludeUserId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const participants = await participateColl
|
||||||
|
.find(filter)
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
return weightedRandom(participants);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'timerComplete',
|
name: 'timerComplete',
|
||||||
|
|
||||||
async execute(timer, client) {
|
async execute(timer, client) {
|
||||||
const member = await getMember(client, timer.assignedUser);
|
const db = mClient.db('neo-db');
|
||||||
if (!member) return;
|
|
||||||
|
|
||||||
await member.send(
|
const wgeColl = db.collection('timer_wge');
|
||||||
|
const participateColl = db.collection('items_wge');
|
||||||
|
const channelColl = db.collection('config_channels');
|
||||||
|
|
||||||
|
const guild = client.guilds.cache.get(process.env.D_GuildID);
|
||||||
|
|
||||||
|
if (!guild) {
|
||||||
|
console.error('timerComplete: Guild not found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify previous expert
|
||||||
|
const previousMember = await getMember(
|
||||||
|
client,
|
||||||
|
timer.assignedUser
|
||||||
|
);
|
||||||
|
|
||||||
|
if (previousMember) {
|
||||||
|
await previousMember.send(
|
||||||
`❌ Timer ran out: **${timer.topic}** ...Re-assigning randomly...`
|
`❌ Timer ran out: **${timer.topic}** ...Re-assigning randomly...`
|
||||||
).catch(() => { });
|
).catch(error => {
|
||||||
|
console.error(
|
||||||
|
`timerComplete: Failed to DM ${timer.assignedUser}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Reset Timer, Reassign Randomly
|
// Get configured WGE channel
|
||||||
const db = mClient.db('neo-db')
|
const wgeChannelConfig = await channelColl.findOne({
|
||||||
const wgeColl = db.collection('timer_wge')
|
purpose: 'wge',
|
||||||
|
guildID: process.env.D_GuildID
|
||||||
|
});
|
||||||
|
|
||||||
// Randomizer Function
|
if (!wgeChannelConfig) {
|
||||||
const participateColl = db.collection('items_wge')
|
console.error(
|
||||||
const randomParticipant = await participateColl.aggregate([
|
'timerComplete: WGE channel configuration not found.'
|
||||||
{ $match: { status: true } },
|
);
|
||||||
{ $sample: { size: 1 } }
|
return;
|
||||||
]).toArray()
|
}
|
||||||
|
|
||||||
if (!randomParticipant.length) { return interaction.reply({ content: 'No one else is participating!' }) }
|
const channel = client.channels.cache.get(
|
||||||
|
wgeChannelConfig.channelID
|
||||||
|
);
|
||||||
|
|
||||||
const wge = await wgeColl.findOne({
|
if (!channel) {
|
||||||
$and: [
|
console.error('timerComplete: WGE channel not found.');
|
||||||
{ debug: false },
|
return;
|
||||||
{ state: 'running' }
|
}
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
const channelColl = db.collection('config_channels')
|
// Weighted random selection.
|
||||||
const guild = await client.guilds.cache.get(process.env.D_GuildID);
|
// Previous expert is explicitly excluded.
|
||||||
const wgeChannel = await channelColl.findOne({
|
const selectedParticipant = await selectWgeParticipant(
|
||||||
$and: [
|
participateColl,
|
||||||
{ purpose: 'wge' },
|
{
|
||||||
{ guildID: process.env.D_GuildID }
|
excludeUserId: timer.assignedUser
|
||||||
]
|
}
|
||||||
})
|
);
|
||||||
|
|
||||||
const channel = await client.channels.cache.get(wgeChannel.channelID)
|
if (!selectedParticipant) {
|
||||||
|
await channel.send({
|
||||||
|
content:
|
||||||
|
`The timer for <@${timer.assignedUser}> has run out, ` +
|
||||||
|
`but there are currently no other participating users available for reassignment.`
|
||||||
|
});
|
||||||
|
|
||||||
random = await guild.members.fetch(randomParticipant[0].userID)
|
return;
|
||||||
wgeAssignedUser = random.user
|
}
|
||||||
|
|
||||||
|
const newMember = await guild.members
|
||||||
|
.fetch(selectedParticipant.userID)
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
|
if (!newMember) {
|
||||||
|
console.error(
|
||||||
|
`timerComplete: Could not fetch selected user ${selectedParticipant.userID}.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newAssignedUser = newMember.user;
|
||||||
|
|
||||||
|
const wgeDefaultAssignedTime =
|
||||||
|
7 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
const assignedAt = new Date();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update participant statistics.
|
||||||
|
*
|
||||||
|
* $inc automatically creates expertCount with value 1
|
||||||
|
* if the field does not exist yet.
|
||||||
|
*/
|
||||||
|
await participateColl.updateOne(
|
||||||
|
{
|
||||||
|
_id: selectedParticipant._id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
lastExpertAt: assignedAt
|
||||||
|
},
|
||||||
|
$inc: {
|
||||||
|
expertCount: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove the expired timer
|
||||||
await wgeColl.deleteOne({
|
await wgeColl.deleteOne({
|
||||||
_id: wge._id
|
_id: timer._id
|
||||||
})
|
});
|
||||||
|
|
||||||
const wgeDefaultAssignedTime = 7 * 24 * 60 * 60 * 1000; // 7 days in ms
|
|
||||||
|
|
||||||
channel.send({
|
|
||||||
content: `The Timer for <@${wge.assignedUser}> has run out! Assigning randomly... \r\n<@${wgeAssignedUser.id}> is the next expert! Their topic still is **${wge.topic}**`
|
|
||||||
})
|
|
||||||
|
|
||||||
|
// Create new timer
|
||||||
await wgeColl.insertOne({
|
await wgeColl.insertOne({
|
||||||
assignedUser: wgeAssignedUser.id,
|
assignedUser: newAssignedUser.id,
|
||||||
assigningUser: wge.assigningUser,
|
assigningUser: timer.assigningUser,
|
||||||
|
|
||||||
startedAt: Date.now(),
|
startedAt: Date.now(),
|
||||||
timeRemaining: wgeDefaultAssignedTime,
|
timeRemaining: wgeDefaultAssignedTime,
|
||||||
@@ -85,11 +226,20 @@ module.exports = {
|
|||||||
complete: false
|
complete: false
|
||||||
},
|
},
|
||||||
|
|
||||||
topic: wge.topic,
|
topic: timer.topic,
|
||||||
debug: false,
|
debug: false,
|
||||||
|
|
||||||
createdAt: new Date()
|
createdAt: assignedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await channel.send({
|
||||||
|
content:
|
||||||
|
`The timer for <@${timer.assignedUser}> has run out! Assigning randomly...\n` +
|
||||||
|
`<@${newAssignedUser.id}> is the next expert! Their topic is still **${timer.topic}**`
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`timerComplete: Reassigned WGE from ${timer.assignedUser} to ${newAssignedUser.id}.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1,11 +1,49 @@
|
|||||||
const { Client, GatewayIntentBits, Collection, Partials } = require('discord.js')
|
const {
|
||||||
const { MongoClient } = require('mongodb')
|
Client,
|
||||||
require('dotenv').config()
|
GatewayIntentBits,
|
||||||
const mClient = new MongoClient(process.env.M_URI)
|
Collection,
|
||||||
exports.mClient = mClient;
|
Partials
|
||||||
const fs = require('node:fs')
|
} = require("discord.js");
|
||||||
|
|
||||||
const client = new Client({
|
const {
|
||||||
|
MongoClient
|
||||||
|
} = require("mongodb");
|
||||||
|
|
||||||
|
const fs =
|
||||||
|
require("node:fs");
|
||||||
|
|
||||||
|
require("dotenv").config();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* MONGODB
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
const mClient =
|
||||||
|
new MongoClient(
|
||||||
|
process.env.M_URI
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Export this BEFORE handlers/commands are loaded.
|
||||||
|
*
|
||||||
|
* utils/nutEconomy.js imports mClient from index.js.
|
||||||
|
*/
|
||||||
|
exports.mClient =
|
||||||
|
mClient;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* DISCORD CLIENT
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
const client =
|
||||||
|
new Client({
|
||||||
intents: [
|
intents: [
|
||||||
GatewayIntentBits.Guilds,
|
GatewayIntentBits.Guilds,
|
||||||
GatewayIntentBits.GuildMembers,
|
GatewayIntentBits.GuildMembers,
|
||||||
@@ -14,20 +52,161 @@ const client = new Client({
|
|||||||
GatewayIntentBits.GuildMessageReactions,
|
GatewayIntentBits.GuildMessageReactions,
|
||||||
GatewayIntentBits.GuildVoiceStates,
|
GatewayIntentBits.GuildVoiceStates,
|
||||||
GatewayIntentBits.DirectMessages,
|
GatewayIntentBits.DirectMessages,
|
||||||
GatewayIntentBits.MessageContent,
|
GatewayIntentBits.MessageContent
|
||||||
],
|
],
|
||||||
partials: [Partials.Channel, Partials.Message, Partials.User, Partials.GuildMember, Partials.Reaction]
|
|
||||||
});
|
|
||||||
exports.client = client
|
|
||||||
|
|
||||||
client.commands = new Collection() // slash commands collection
|
partials: [
|
||||||
client.legacyCommands = new Collection() // legacy commands collection
|
Partials.Channel,
|
||||||
client.aliases = new Collection() // list of command aliases
|
Partials.Message,
|
||||||
client.buttons = new Collection() // list of buttons
|
Partials.User,
|
||||||
client.selectMenus = new Collection() // list of selectMenus
|
Partials.GuildMember,
|
||||||
|
Partials.Reaction
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
fs.readdirSync('./handlers').forEach((handler) => {
|
|
||||||
require(`./handlers/${handler}`)(client)
|
|
||||||
});
|
|
||||||
|
|
||||||
client.login(process.env.D_Token)
|
exports.client =
|
||||||
|
client;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* COLLECTIONS
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
client.commands =
|
||||||
|
new Collection();
|
||||||
|
|
||||||
|
client.legacyCommands =
|
||||||
|
new Collection();
|
||||||
|
|
||||||
|
client.aliases =
|
||||||
|
new Collection();
|
||||||
|
|
||||||
|
client.buttons =
|
||||||
|
new Collection();
|
||||||
|
|
||||||
|
client.selectMenus =
|
||||||
|
new Collection();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* STARTUP
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function start() {
|
||||||
|
try {
|
||||||
|
/*
|
||||||
|
* Connect Mongo first.
|
||||||
|
*/
|
||||||
|
|
||||||
|
await mClient.connect();
|
||||||
|
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"[MongoDB] Connected"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load handlers only after MongoDB is ready.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const handlers =
|
||||||
|
fs.readdirSync(
|
||||||
|
"./handlers"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
for (
|
||||||
|
const handler
|
||||||
|
of handlers
|
||||||
|
) {
|
||||||
|
require(
|
||||||
|
`./handlers/${handler}`
|
||||||
|
)(
|
||||||
|
client
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally connect to Discord.
|
||||||
|
*/
|
||||||
|
|
||||||
|
await client.login(
|
||||||
|
process.env.D_Token
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
"Failed to start bot:",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
process.exit(
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* SHUTDOWN
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function shutdown(
|
||||||
|
signal
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
`[System] ${signal} received, shutting down...`
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.destroy();
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
await mClient.close();
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
|
||||||
|
process.exit(
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
process.on(
|
||||||
|
"SIGINT",
|
||||||
|
() =>
|
||||||
|
shutdown(
|
||||||
|
"SIGINT"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
process.on(
|
||||||
|
"SIGTERM",
|
||||||
|
() =>
|
||||||
|
shutdown(
|
||||||
|
"SIGTERM"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* START
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
start();
|
||||||
File diff suppressed because it is too large
Load Diff
+1013
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,777 @@
|
|||||||
|
// utils/nutHeist.js
|
||||||
|
|
||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ButtonStyle,
|
||||||
|
MessageFlags
|
||||||
|
} = require("discord.js");
|
||||||
|
|
||||||
|
const {
|
||||||
|
getNutBalance,
|
||||||
|
transferNuts,
|
||||||
|
claimCooldown
|
||||||
|
} = require("./nutEconomy");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* CONFIG
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
const HEIST_COOLDOWN =
|
||||||
|
60 * 60;
|
||||||
|
|
||||||
|
const HEIST_ACTIONS = {
|
||||||
|
Sneak: {
|
||||||
|
label:
|
||||||
|
"Sneak",
|
||||||
|
|
||||||
|
emoji:
|
||||||
|
"🥷",
|
||||||
|
|
||||||
|
successChance:
|
||||||
|
0.55,
|
||||||
|
|
||||||
|
minReward:
|
||||||
|
10,
|
||||||
|
|
||||||
|
maxReward:
|
||||||
|
100,
|
||||||
|
|
||||||
|
minLoss:
|
||||||
|
5,
|
||||||
|
|
||||||
|
maxLoss:
|
||||||
|
40
|
||||||
|
},
|
||||||
|
|
||||||
|
Hack: {
|
||||||
|
label:
|
||||||
|
"Hack",
|
||||||
|
|
||||||
|
emoji:
|
||||||
|
"💻",
|
||||||
|
|
||||||
|
successChance:
|
||||||
|
0.40,
|
||||||
|
|
||||||
|
minReward:
|
||||||
|
50,
|
||||||
|
|
||||||
|
maxReward:
|
||||||
|
250,
|
||||||
|
|
||||||
|
minLoss:
|
||||||
|
20,
|
||||||
|
|
||||||
|
maxLoss:
|
||||||
|
100
|
||||||
|
},
|
||||||
|
|
||||||
|
Smash: {
|
||||||
|
label:
|
||||||
|
"Smash",
|
||||||
|
|
||||||
|
emoji:
|
||||||
|
"💥",
|
||||||
|
|
||||||
|
successChance:
|
||||||
|
0.25,
|
||||||
|
|
||||||
|
minReward:
|
||||||
|
150,
|
||||||
|
|
||||||
|
maxReward:
|
||||||
|
500,
|
||||||
|
|
||||||
|
minLoss:
|
||||||
|
50,
|
||||||
|
|
||||||
|
maxLoss:
|
||||||
|
200
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* HELPERS
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function randomInteger(
|
||||||
|
min,
|
||||||
|
max
|
||||||
|
) {
|
||||||
|
return Math.floor(
|
||||||
|
Math.random() *
|
||||||
|
(
|
||||||
|
max -
|
||||||
|
min +
|
||||||
|
1
|
||||||
|
)
|
||||||
|
) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getHeistOwner(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const footer =
|
||||||
|
interaction.message
|
||||||
|
?.embeds?.[0]
|
||||||
|
?.footer
|
||||||
|
?.text;
|
||||||
|
|
||||||
|
const parts =
|
||||||
|
footer?.split(":")
|
||||||
|
??
|
||||||
|
[];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Coming from Nut Hub.
|
||||||
|
*
|
||||||
|
* nutHub:<userId>
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] ===
|
||||||
|
"nutHub"
|
||||||
|
) {
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Coming from Heist.
|
||||||
|
*
|
||||||
|
* nutHeist:<userId>
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] ===
|
||||||
|
"nutHeist"
|
||||||
|
) {
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function buildHeistButtons() {
|
||||||
|
return [
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHeistSneak"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Sneak"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🥷"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Success
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHeistHack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Hack"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"💻"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHeistSmash"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Smash"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"💥"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Danger
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubBack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Nut Hub"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"◀️"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function buildReturnButtons() {
|
||||||
|
return [
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubHeist"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Heist Menu"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🏦"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubBack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Nut Hub"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"◀️"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* TEMPORARY EPHEMERAL MESSAGE
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
options
|
||||||
|
) {
|
||||||
|
const reply =
|
||||||
|
await interaction.reply({
|
||||||
|
...options,
|
||||||
|
|
||||||
|
flags:
|
||||||
|
MessageFlags.Ephemeral
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ephemeral messages cannot truly be given
|
||||||
|
* a Discord-side expiration time.
|
||||||
|
*
|
||||||
|
* We attempt to delete the reply after 5 seconds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
setTimeout(
|
||||||
|
async () => {
|
||||||
|
try {
|
||||||
|
await interaction.deleteReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
catch {
|
||||||
|
// Ignore expired/deleted interaction.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
5000
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* SHOW HEIST MENU
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function showNutHeist(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const ownerId =
|
||||||
|
getHeistOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
ownerId !==
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Das ist nicht deine Nut-Hub-Session."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await interaction.deferUpdate();
|
||||||
|
|
||||||
|
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
interaction.user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🏦 Nut Vault Heist"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
"Arthonor bewacht seinen Vorrat an Nüssen.",
|
||||||
|
"",
|
||||||
|
"Wähle deinen Ansatz.",
|
||||||
|
"",
|
||||||
|
"### 🥷 Sneak",
|
||||||
|
"**55%** Erfolgschance",
|
||||||
|
"Kleine Beute, geringes Risiko.",
|
||||||
|
"",
|
||||||
|
"### 💻 Hack",
|
||||||
|
"**40%** Erfolgschance",
|
||||||
|
"Mittlere Beute, mittleres Risiko.",
|
||||||
|
"",
|
||||||
|
"### 💥 Smash",
|
||||||
|
"**25%** Erfolgschance",
|
||||||
|
"Große Beute, hohes Risiko.",
|
||||||
|
"",
|
||||||
|
`Ein Heist hat **${Math.floor(HEIST_COOLDOWN / 60)} Minuten Cooldown**.`
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields({
|
||||||
|
name:
|
||||||
|
"Deine Nüsse",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`**${balance.toLocaleString()} 🥜**`
|
||||||
|
})
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutHeist:${interaction.user.id}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildHeistButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* PERFORM HEIST
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function performNutHeist(
|
||||||
|
interaction,
|
||||||
|
actionName
|
||||||
|
) {
|
||||||
|
const ownerId =
|
||||||
|
getHeistOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prevent another player from using
|
||||||
|
* somebody else's Heist menu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
ownerId !==
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Das ist nicht dein Heist."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const action =
|
||||||
|
HEIST_ACTIONS[
|
||||||
|
actionName
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!action
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Unbekannte Heist-Aktion."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acknowledge immediately.
|
||||||
|
*/
|
||||||
|
|
||||||
|
await interaction.deferUpdate();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ========================================================
|
||||||
|
* CLAIM SHARED HEIST COOLDOWN
|
||||||
|
* ========================================================
|
||||||
|
*
|
||||||
|
* Sneak / Hack / Smash all use the same field:
|
||||||
|
*
|
||||||
|
* items_cooldowns
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* userId: "...",
|
||||||
|
* nut: ...,
|
||||||
|
* heist: ...
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
const cooldown =
|
||||||
|
await claimCooldown(
|
||||||
|
interaction.user.id,
|
||||||
|
"heist",
|
||||||
|
HEIST_COOLDOWN
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!cooldown.claimed
|
||||||
|
) {
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🏦 Vault Locked Down"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
"Arthonor ist noch auf der Hut.",
|
||||||
|
"",
|
||||||
|
`Du kannst <t:${cooldown.next}:R> wieder einen Heist versuchen.`
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutHeist:${interaction.user.id}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildReturnButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ========================================================
|
||||||
|
* ROLL RESULT
|
||||||
|
* ========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
const success =
|
||||||
|
Math.random() <
|
||||||
|
action.successChance;
|
||||||
|
|
||||||
|
|
||||||
|
const playerId =
|
||||||
|
interaction.user.id;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arthonor himself acts as the vault.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const vaultId =
|
||||||
|
interaction.client.user.id;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ========================================================
|
||||||
|
* SUCCESS
|
||||||
|
* ========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
success
|
||||||
|
) {
|
||||||
|
let reward =
|
||||||
|
randomInteger(
|
||||||
|
action.minReward,
|
||||||
|
action.maxReward
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Never steal more Nuts than
|
||||||
|
* Arthonor currently owns.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const vaultBalance =
|
||||||
|
await getNutBalance(
|
||||||
|
vaultId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
reward =
|
||||||
|
Math.min(
|
||||||
|
reward,
|
||||||
|
vaultBalance
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
reward <=
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🏦 The Vault Is Empty"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
`${action.emoji} **${action.label}** succeeded...`,
|
||||||
|
"",
|
||||||
|
"but Arthonor's Nut stash is empty.",
|
||||||
|
"",
|
||||||
|
"You escape with nothing."
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutHeist:${playerId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildReturnButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await transferNuts(
|
||||||
|
vaultId,
|
||||||
|
playerId,
|
||||||
|
reward
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
playerId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"💰 Heist Successful!"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
`${action.emoji} **${action.label}** worked!`,
|
||||||
|
"",
|
||||||
|
`You stole **${reward.toLocaleString()} 🥜** from Arthonor's stash.`
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields({
|
||||||
|
name:
|
||||||
|
"Deine Nüsse",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`**${balance.toLocaleString()} 🥜**`
|
||||||
|
})
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutHeist:${playerId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildReturnButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ========================================================
|
||||||
|
* FAILURE
|
||||||
|
* ========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
let loss =
|
||||||
|
randomInteger(
|
||||||
|
action.minLoss,
|
||||||
|
action.maxLoss
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't take more than the player owns.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const playerBalance =
|
||||||
|
await getNutBalance(
|
||||||
|
playerId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
loss =
|
||||||
|
Math.min(
|
||||||
|
loss,
|
||||||
|
playerBalance
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
loss >
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
await transferNuts(
|
||||||
|
playerId,
|
||||||
|
vaultId,
|
||||||
|
loss
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
playerId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🚨 Heist Failed!"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
loss > 0
|
||||||
|
? [
|
||||||
|
`${action.emoji} **${action.label}** went wrong.`,
|
||||||
|
"",
|
||||||
|
"Arthonor caught you.",
|
||||||
|
"",
|
||||||
|
`You lost **${loss.toLocaleString()} 🥜**.`
|
||||||
|
].join("\n")
|
||||||
|
|
||||||
|
: [
|
||||||
|
`${action.emoji} **${action.label}** went wrong.`,
|
||||||
|
"",
|
||||||
|
"Arthonor caught you...",
|
||||||
|
"",
|
||||||
|
"but you didn't have any Nuts for him to take."
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields({
|
||||||
|
name:
|
||||||
|
"Deine Nüsse",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`**${balance.toLocaleString()} 🥜**`
|
||||||
|
})
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutHeist:${playerId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildReturnButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* EXPORTS
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
showNutHeist,
|
||||||
|
performNutHeist
|
||||||
|
};
|
||||||
+240
@@ -0,0 +1,240 @@
|
|||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ButtonStyle,
|
||||||
|
MessageFlags
|
||||||
|
} = require("discord.js");
|
||||||
|
|
||||||
|
const {
|
||||||
|
getNutBalance
|
||||||
|
} = require("./nutEconomy");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* SHOW HUB
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function showNutHub(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
interaction.user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
buildNutHubEmbed(
|
||||||
|
interaction.user,
|
||||||
|
balance
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const components =
|
||||||
|
buildNutHubButtons();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Slash command / fresh interaction.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
!interaction.replied &&
|
||||||
|
!interaction.deferred
|
||||||
|
) {
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Existing game/menu message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return interaction.update({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* EMBED
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function buildNutHubEmbed(
|
||||||
|
user,
|
||||||
|
balance
|
||||||
|
) {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🥜 Nut Hub"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
`Willkommen, ${user}!`,
|
||||||
|
"",
|
||||||
|
"Hier werden Nüsse gewonnen, verloren und gelegentlich konfisziert.",
|
||||||
|
"",
|
||||||
|
"### 🎰 Nut Slots",
|
||||||
|
"Dreh die Walzen und jag den Jackpot.",
|
||||||
|
"",
|
||||||
|
"### 🃏 Nut Blackjack",
|
||||||
|
"Schlag den Dealer ohne über 21 zu kommen.",
|
||||||
|
"",
|
||||||
|
"### 🎡 Nut Roulette",
|
||||||
|
"Setz auf Rot, Schwarz, Ungerade, Gerade oder Zero.",
|
||||||
|
"",
|
||||||
|
"### 🏦 Nut Heist",
|
||||||
|
"Versuch dich direkt am Nut Vault des Bots.",
|
||||||
|
"",
|
||||||
|
"*Choose wisely. The house has very large nuts.*"
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields({
|
||||||
|
name:
|
||||||
|
"Deine Nüsse",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`**${balance.toLocaleString()} 🥜**`
|
||||||
|
})
|
||||||
|
|
||||||
|
.setThumbnail(
|
||||||
|
user.displayAvatarURL({
|
||||||
|
size:
|
||||||
|
256
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutHub:${user.id}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* BUTTONS
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function buildNutHubButtons() {
|
||||||
|
return [
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubSlots"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Slots"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🎰"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubBlackjack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Blackjack"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🃏"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Success
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubRoulette"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Roulette"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🎡"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubHeist"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Vault Heist"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🏦"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Danger
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* OWNERSHIP
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getNutHubOwner(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const footer =
|
||||||
|
interaction.message
|
||||||
|
?.embeds?.[0]
|
||||||
|
?.footer
|
||||||
|
?.text;
|
||||||
|
|
||||||
|
|
||||||
|
const parts =
|
||||||
|
footer?.split(":")
|
||||||
|
??
|
||||||
|
[];
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] !==
|
||||||
|
"nutHub"
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
showNutHub,
|
||||||
|
buildNutHubEmbed,
|
||||||
|
buildNutHubButtons,
|
||||||
|
getNutHubOwner
|
||||||
|
};
|
||||||
@@ -0,0 +1,975 @@
|
|||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ButtonStyle
|
||||||
|
} = require("discord.js");
|
||||||
|
|
||||||
|
const {
|
||||||
|
getNutBalance,
|
||||||
|
transferNuts,
|
||||||
|
temporaryEphemeralReply
|
||||||
|
} = require("./nutEconomy");
|
||||||
|
|
||||||
|
|
||||||
|
const ROULETTE_BETS = [
|
||||||
|
10,
|
||||||
|
50,
|
||||||
|
100,
|
||||||
|
500,
|
||||||
|
1000
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const CHOICES = {
|
||||||
|
Red: {
|
||||||
|
name:
|
||||||
|
"Red",
|
||||||
|
|
||||||
|
emoji:
|
||||||
|
"🔴",
|
||||||
|
|
||||||
|
multiplier:
|
||||||
|
2
|
||||||
|
},
|
||||||
|
|
||||||
|
Black: {
|
||||||
|
name:
|
||||||
|
"Black",
|
||||||
|
|
||||||
|
emoji:
|
||||||
|
"⚫",
|
||||||
|
|
||||||
|
multiplier:
|
||||||
|
2
|
||||||
|
},
|
||||||
|
|
||||||
|
Odd: {
|
||||||
|
name:
|
||||||
|
"Odd",
|
||||||
|
|
||||||
|
emoji:
|
||||||
|
"1️⃣",
|
||||||
|
|
||||||
|
multiplier:
|
||||||
|
2
|
||||||
|
},
|
||||||
|
|
||||||
|
Even: {
|
||||||
|
name:
|
||||||
|
"Even",
|
||||||
|
|
||||||
|
emoji:
|
||||||
|
"2️⃣",
|
||||||
|
|
||||||
|
multiplier:
|
||||||
|
2
|
||||||
|
},
|
||||||
|
|
||||||
|
Zero: {
|
||||||
|
name:
|
||||||
|
"Zero",
|
||||||
|
|
||||||
|
emoji:
|
||||||
|
"🟢",
|
||||||
|
|
||||||
|
multiplier:
|
||||||
|
36
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const RED_NUMBERS =
|
||||||
|
new Set([
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
12,
|
||||||
|
14,
|
||||||
|
16,
|
||||||
|
18,
|
||||||
|
19,
|
||||||
|
21,
|
||||||
|
23,
|
||||||
|
25,
|
||||||
|
27,
|
||||||
|
30,
|
||||||
|
32,
|
||||||
|
34,
|
||||||
|
36
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* MENU
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function showNutRoulette(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const ownerId =
|
||||||
|
getRouletteOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
ownerId !==
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Das ist nicht deine Nut-Hub-Session."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
interaction.user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🎡 Nut Roulette"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
"European Roulette — **0 bis 36**.",
|
||||||
|
"",
|
||||||
|
"🔴 **Red** — x2",
|
||||||
|
"⚫ **Black** — x2",
|
||||||
|
"1️⃣ **Odd** — x2",
|
||||||
|
"2️⃣ **Even** — x2",
|
||||||
|
"🟢 **Zero** — x36",
|
||||||
|
"",
|
||||||
|
"Choose your wager."
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields({
|
||||||
|
name:
|
||||||
|
"Deine Nüsse",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${balance.toLocaleString()} 🥜`
|
||||||
|
})
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutRouletteMenu:${interaction.user.id}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.update({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildBetButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* WAGER
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function chooseNutRouletteBet(
|
||||||
|
interaction,
|
||||||
|
bet
|
||||||
|
) {
|
||||||
|
const ownerId =
|
||||||
|
getRouletteOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
ownerId !==
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Das ist nicht dein Roulette-Tisch."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!ROULETTE_BETS.includes(
|
||||||
|
bet
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Dieser Einsatz ist ungültig."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
interaction.user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
balance <
|
||||||
|
bet
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
`Du brauchst **${bet.toLocaleString()} Nüsse**.`
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🎡 Nut Roulette"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
`Einsatz: **${bet.toLocaleString()} 🥜**`,
|
||||||
|
"",
|
||||||
|
"Wo sollen deine Nüsse landen?",
|
||||||
|
"",
|
||||||
|
"🔴 Red",
|
||||||
|
"⚫ Black",
|
||||||
|
"1️⃣ Odd",
|
||||||
|
"2️⃣ Even",
|
||||||
|
"🟢 Zero"
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutRouletteBet:${interaction.user.id}:${bet}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.update({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildChoiceButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* PLAY
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function playNutRoulette(
|
||||||
|
interaction,
|
||||||
|
choiceKey
|
||||||
|
) {
|
||||||
|
const choice =
|
||||||
|
CHOICES[
|
||||||
|
choiceKey
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
if (!choice) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Diese Roulette-Wette existiert nicht."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const footer =
|
||||||
|
interaction.message
|
||||||
|
?.embeds?.[0]
|
||||||
|
?.footer
|
||||||
|
?.text;
|
||||||
|
|
||||||
|
|
||||||
|
const parts =
|
||||||
|
footer?.split(":")
|
||||||
|
??
|
||||||
|
[];
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] !==
|
||||||
|
"nutRouletteBet"
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Diese Roulette-Wette ist nicht mehr gültig."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ownerId =
|
||||||
|
parts[1];
|
||||||
|
|
||||||
|
|
||||||
|
const bet =
|
||||||
|
Number(
|
||||||
|
parts[2]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
ownerId !==
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Das ist nicht dein Roulette-Tisch."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const playerId =
|
||||||
|
interaction.user.id;
|
||||||
|
|
||||||
|
|
||||||
|
const houseId =
|
||||||
|
interaction.client.user.id;
|
||||||
|
|
||||||
|
|
||||||
|
const [
|
||||||
|
playerBalance,
|
||||||
|
houseBalance
|
||||||
|
] =
|
||||||
|
await Promise.all([
|
||||||
|
getNutBalance(
|
||||||
|
playerId
|
||||||
|
),
|
||||||
|
|
||||||
|
getNutBalance(
|
||||||
|
houseId
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
playerBalance <
|
||||||
|
bet
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Du hast nicht mehr genug Nüsse."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const maxPayout =
|
||||||
|
bet *
|
||||||
|
choice.multiplier;
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
houseBalance +
|
||||||
|
bet <
|
||||||
|
maxPayout
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Der Nut Vault kann diesen Einsatz nicht absichern."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await transferNuts(
|
||||||
|
playerId,
|
||||||
|
houseId,
|
||||||
|
bet
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pseudo animation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
await interaction.update({
|
||||||
|
embeds: [
|
||||||
|
buildSpinEmbed(
|
||||||
|
choice,
|
||||||
|
bet,
|
||||||
|
randomRouletteNumber(),
|
||||||
|
"Das Rad beginnt sich zu drehen..."
|
||||||
|
)
|
||||||
|
],
|
||||||
|
|
||||||
|
components: []
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
await delay(
|
||||||
|
650
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
buildSpinEmbed(
|
||||||
|
choice,
|
||||||
|
bet,
|
||||||
|
randomRouletteNumber(),
|
||||||
|
"Round and round..."
|
||||||
|
)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
await delay(
|
||||||
|
650
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
buildSpinEmbed(
|
||||||
|
choice,
|
||||||
|
bet,
|
||||||
|
randomRouletteNumber(),
|
||||||
|
"Die Kugel wird langsamer..."
|
||||||
|
)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
await delay(
|
||||||
|
750
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const result =
|
||||||
|
randomRouletteNumber();
|
||||||
|
|
||||||
|
|
||||||
|
const won =
|
||||||
|
didBetWin(
|
||||||
|
choiceKey,
|
||||||
|
result
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const payout =
|
||||||
|
won
|
||||||
|
? bet *
|
||||||
|
choice.multiplier
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
payout >
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
await transferNuts(
|
||||||
|
houseId,
|
||||||
|
playerId,
|
||||||
|
payout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
playerId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const profit =
|
||||||
|
payout -
|
||||||
|
bet;
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
won
|
||||||
|
? "🎉 Nut Roulette — WIN!"
|
||||||
|
: "🎡 Nut Roulette"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
"## Die Kugel landet auf...",
|
||||||
|
"",
|
||||||
|
`# ${formatRouletteNumber(result)}`,
|
||||||
|
"",
|
||||||
|
`${choice.emoji} Deine Wette: **${choice.name}**`,
|
||||||
|
"",
|
||||||
|
won
|
||||||
|
? `🎉 **${payout.toLocaleString()} Nüsse gewonnen!**`
|
||||||
|
: "Das Haus gewinnt."
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields(
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Einsatz",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${bet.toLocaleString()} 🥜`,
|
||||||
|
|
||||||
|
inline:
|
||||||
|
true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Payout",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${payout.toLocaleString()} 🥜`,
|
||||||
|
|
||||||
|
inline:
|
||||||
|
true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Profit",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${profit >= 0 ? "+" : ""}${profit.toLocaleString()} 🥜`,
|
||||||
|
|
||||||
|
inline:
|
||||||
|
true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Deine Nüsse",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${balance.toLocaleString()} 🥜`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutRouletteResult:${playerId}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildResultButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* RULES
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function didBetWin(
|
||||||
|
choice,
|
||||||
|
number
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
number ===
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
return choice ===
|
||||||
|
"Zero";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (choice) {
|
||||||
|
case "Red":
|
||||||
|
return RED_NUMBERS.has(
|
||||||
|
number
|
||||||
|
);
|
||||||
|
|
||||||
|
case "Black":
|
||||||
|
return !RED_NUMBERS.has(
|
||||||
|
number
|
||||||
|
);
|
||||||
|
|
||||||
|
case "Odd":
|
||||||
|
return number %
|
||||||
|
2 ===
|
||||||
|
1;
|
||||||
|
|
||||||
|
case "Even":
|
||||||
|
return number %
|
||||||
|
2 ===
|
||||||
|
0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatRouletteNumber(
|
||||||
|
number
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
number ===
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
return "🟢 0";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
RED_NUMBERS.has(
|
||||||
|
number
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return `🔴 ${number}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return `⚫ ${number}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* DISPLAY
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function buildSpinEmbed(
|
||||||
|
choice,
|
||||||
|
bet,
|
||||||
|
number,
|
||||||
|
text
|
||||||
|
) {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🎡 Nut Roulette"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
"## 🎡 Spinning...",
|
||||||
|
"",
|
||||||
|
`### ${formatRouletteNumber(number)}`,
|
||||||
|
"",
|
||||||
|
`**${text}**`
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields(
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Wette",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${choice.emoji} ${choice.name}`,
|
||||||
|
|
||||||
|
inline:
|
||||||
|
true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Einsatz",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${bet.toLocaleString()} 🥜`,
|
||||||
|
|
||||||
|
inline:
|
||||||
|
true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* BUTTONS
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function buildBetButtons() {
|
||||||
|
return [
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
...ROULETTE_BETS.map(
|
||||||
|
bet =>
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
`nutRouletteBet${bet}`
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
bet.toLocaleString()
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🥜"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
bet >=
|
||||||
|
500
|
||||||
|
? ButtonStyle.Primary
|
||||||
|
: ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubBack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Nut Hub"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"◀️"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function buildChoiceButtons() {
|
||||||
|
return [
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutRouletteRed"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Red"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🔴"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Danger
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutRouletteBlack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Black"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"⚫"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutRouletteOdd"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Odd"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"1️⃣"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutRouletteEven"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Even"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"2️⃣"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutRouletteZero"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Zero"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🟢"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Success
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function buildResultButtons() {
|
||||||
|
return [
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubRoulette"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Play Again"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🎡"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubBack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Nut Hub"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"◀️"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* OWNERSHIP
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getRouletteOwner(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const footer =
|
||||||
|
interaction.message
|
||||||
|
?.embeds?.[0]
|
||||||
|
?.footer
|
||||||
|
?.text;
|
||||||
|
|
||||||
|
|
||||||
|
const parts =
|
||||||
|
footer?.split(":")
|
||||||
|
??
|
||||||
|
[];
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] ===
|
||||||
|
"nutHub"
|
||||||
|
) {
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] ===
|
||||||
|
"nutRouletteMenu"
|
||||||
|
||
|
||||||
|
parts[0] ===
|
||||||
|
"nutRouletteResult"
|
||||||
|
) {
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] ===
|
||||||
|
"nutRouletteBet"
|
||||||
|
) {
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function randomRouletteNumber() {
|
||||||
|
return Math.floor(
|
||||||
|
Math.random() *
|
||||||
|
37
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function delay(
|
||||||
|
ms
|
||||||
|
) {
|
||||||
|
return new Promise(
|
||||||
|
resolve =>
|
||||||
|
setTimeout(
|
||||||
|
resolve,
|
||||||
|
ms
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
showNutRoulette,
|
||||||
|
chooseNutRouletteBet,
|
||||||
|
playNutRoulette
|
||||||
|
};
|
||||||
@@ -0,0 +1,795 @@
|
|||||||
|
const {
|
||||||
|
EmbedBuilder,
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
ButtonStyle
|
||||||
|
} = require("discord.js");
|
||||||
|
|
||||||
|
const {
|
||||||
|
getNutBalance,
|
||||||
|
transferNuts,
|
||||||
|
temporaryEphemeralReply,
|
||||||
|
randomItem
|
||||||
|
} = require("./nutEconomy");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* CONFIG
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SLOT_BETS = [
|
||||||
|
10,
|
||||||
|
50,
|
||||||
|
100,
|
||||||
|
500,
|
||||||
|
1000
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* NUT SYMBOLS
|
||||||
|
* ============================================================
|
||||||
|
*
|
||||||
|
* All symbols are nut-themed.
|
||||||
|
*
|
||||||
|
* 🌰 Chestnut
|
||||||
|
* 🥜 Peanuts
|
||||||
|
* 🥥 Coconut
|
||||||
|
* 🍩 Doughnut
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SYMBOLS = [
|
||||||
|
"🌰",
|
||||||
|
"🥜",
|
||||||
|
"🥥",
|
||||||
|
"🍩"
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Weighted reel.
|
||||||
|
*
|
||||||
|
* Chestnuts are the common symbol.
|
||||||
|
* Peanuts are less common.
|
||||||
|
* Coconuts are rare.
|
||||||
|
* Doughnuts are the jackpot symbol.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const REEL = [
|
||||||
|
"🌰",
|
||||||
|
"🌰",
|
||||||
|
"🌰",
|
||||||
|
"🌰",
|
||||||
|
"🌰",
|
||||||
|
|
||||||
|
"🥜",
|
||||||
|
"🥜",
|
||||||
|
"🥜",
|
||||||
|
"🥜",
|
||||||
|
|
||||||
|
"🥥",
|
||||||
|
"🥥",
|
||||||
|
|
||||||
|
"🍩"
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Triple-symbol payouts.
|
||||||
|
*
|
||||||
|
* Payout includes the original wager.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const PAYOUTS = {
|
||||||
|
"🌰":
|
||||||
|
1.5,
|
||||||
|
|
||||||
|
"🥜":
|
||||||
|
2,
|
||||||
|
|
||||||
|
"🥥":
|
||||||
|
4,
|
||||||
|
|
||||||
|
"🍩":
|
||||||
|
10
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* SHOW SLOTS
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function showNutSlots(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
|
||||||
|
const ownerId =
|
||||||
|
getNutSlotsOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
ownerId !==
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Das ist nicht deine Nut-Hub-Session."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acknowledge the button immediately.
|
||||||
|
*/
|
||||||
|
await interaction.deferUpdate();
|
||||||
|
|
||||||
|
|
||||||
|
const balance =
|
||||||
|
await getNutBalance(
|
||||||
|
interaction.user.id
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🎰 Nut Slots"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
"Dreh die Walzen und jag den **Nut Jackpot**.",
|
||||||
|
"",
|
||||||
|
"### 🥜 Payouts",
|
||||||
|
"🌰 🌰 🌰 — **×1.5**",
|
||||||
|
"🥜 🥜 🥜 — **×2**",
|
||||||
|
"🥥 🥥 🥥 — **×4**",
|
||||||
|
"🍩 🍩 🍩 — **×10**",
|
||||||
|
"",
|
||||||
|
"Choose your wager."
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields({
|
||||||
|
name:
|
||||||
|
"Deine Nüsse",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`**${balance.toLocaleString()} 🥜**`
|
||||||
|
})
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutSlots:${interaction.user.id}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildSlotBetButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* PLAY
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function playNutSlots(
|
||||||
|
interaction,
|
||||||
|
bet
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!SLOT_BETS.includes(
|
||||||
|
bet
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Dieser Einsatz ist nicht verfügbar."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ownerId =
|
||||||
|
getNutSlotsOwner(
|
||||||
|
interaction
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
ownerId !==
|
||||||
|
interaction.user.id
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Das ist nicht deine Slots-Session."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const playerId =
|
||||||
|
interaction.user.id;
|
||||||
|
|
||||||
|
|
||||||
|
const houseId =
|
||||||
|
interaction.client.user.id;
|
||||||
|
|
||||||
|
|
||||||
|
const [
|
||||||
|
playerBalance,
|
||||||
|
houseBalance
|
||||||
|
] =
|
||||||
|
await Promise.all([
|
||||||
|
getNutBalance(
|
||||||
|
playerId
|
||||||
|
),
|
||||||
|
|
||||||
|
getNutBalance(
|
||||||
|
houseId
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
playerBalance <
|
||||||
|
bet
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
`Du brauchst **${bet.toLocaleString()} Nüsse** für diesen Einsatz.`
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum possible return = x10.
|
||||||
|
*
|
||||||
|
* After receiving the wager, the house must
|
||||||
|
* still be able to cover the total payout.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const maxPayout =
|
||||||
|
bet *
|
||||||
|
10;
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
houseBalance +
|
||||||
|
bet <
|
||||||
|
maxPayout
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Der Nut Vault kann diesen Einsatz aktuell nicht absichern."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
await transferNuts(
|
||||||
|
playerId,
|
||||||
|
houseId,
|
||||||
|
bet
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
if (
|
||||||
|
error.message ===
|
||||||
|
"INSUFFICIENT_NUTS"
|
||||||
|
) {
|
||||||
|
return temporaryEphemeralReply(
|
||||||
|
interaction,
|
||||||
|
{
|
||||||
|
content:
|
||||||
|
"Dein Nut-Bestand hat sich verändert."
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initial animation state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
await interaction.update({
|
||||||
|
embeds: [
|
||||||
|
buildSpinEmbed(
|
||||||
|
bet,
|
||||||
|
[
|
||||||
|
"❔",
|
||||||
|
"❔",
|
||||||
|
"❔"
|
||||||
|
],
|
||||||
|
"Die Walzen drehen..."
|
||||||
|
)
|
||||||
|
],
|
||||||
|
|
||||||
|
components: []
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
await delay(
|
||||||
|
500
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
buildSpinEmbed(
|
||||||
|
bet,
|
||||||
|
[
|
||||||
|
randomReelSymbol(),
|
||||||
|
"❔",
|
||||||
|
"❔"
|
||||||
|
],
|
||||||
|
"Die erste Walze stoppt..."
|
||||||
|
)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
await delay(
|
||||||
|
500
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const first =
|
||||||
|
randomReelSymbol();
|
||||||
|
|
||||||
|
|
||||||
|
const second =
|
||||||
|
randomReelSymbol();
|
||||||
|
|
||||||
|
|
||||||
|
await interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
buildSpinEmbed(
|
||||||
|
bet,
|
||||||
|
[
|
||||||
|
first,
|
||||||
|
second,
|
||||||
|
"❔"
|
||||||
|
],
|
||||||
|
"Noch eine..."
|
||||||
|
)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
await delay(
|
||||||
|
600
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Final actual result.
|
||||||
|
*
|
||||||
|
* Generate all three here so animation values
|
||||||
|
* don't alter game odds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const result = [
|
||||||
|
randomReelSymbol(),
|
||||||
|
randomReelSymbol(),
|
||||||
|
randomReelSymbol()
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const multiplier =
|
||||||
|
getSlotMultiplier(
|
||||||
|
result
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const payout =
|
||||||
|
Math.floor(
|
||||||
|
bet *
|
||||||
|
multiplier
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
payout >
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
await transferNuts(
|
||||||
|
houseId,
|
||||||
|
playerId,
|
||||||
|
payout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const balanceAfter =
|
||||||
|
await getNutBalance(
|
||||||
|
playerId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const profit =
|
||||||
|
payout -
|
||||||
|
bet;
|
||||||
|
|
||||||
|
|
||||||
|
const embed =
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
multiplier >
|
||||||
|
0
|
||||||
|
? "🎰 Nut Slots — WIN!"
|
||||||
|
: "🎰 Nut Slots"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
"## " +
|
||||||
|
result.join(
|
||||||
|
" "
|
||||||
|
),
|
||||||
|
"",
|
||||||
|
multiplier >
|
||||||
|
0
|
||||||
|
? `🎉 **x${multiplier}**`
|
||||||
|
: "Die Nüsse bleiben beim Haus."
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields(
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Einsatz",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${bet.toLocaleString()} 🥜`,
|
||||||
|
|
||||||
|
inline:
|
||||||
|
true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Payout",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${payout.toLocaleString()} 🥜`,
|
||||||
|
|
||||||
|
inline:
|
||||||
|
true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Profit",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${profit >= 0 ? "+" : ""}${profit.toLocaleString()} 🥜`,
|
||||||
|
|
||||||
|
inline:
|
||||||
|
true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name:
|
||||||
|
"Deine Nüsse",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${balanceAfter.toLocaleString()} 🥜`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
.setFooter({
|
||||||
|
text:
|
||||||
|
`nutSlots:${interaction.user.id}`
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
embeds: [
|
||||||
|
embed
|
||||||
|
],
|
||||||
|
|
||||||
|
components:
|
||||||
|
buildSlotResultButtons()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* PAYOUT
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getSlotMultiplier(
|
||||||
|
result
|
||||||
|
) {
|
||||||
|
const [
|
||||||
|
first,
|
||||||
|
second,
|
||||||
|
third
|
||||||
|
] = result;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Triple.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
first === second &&
|
||||||
|
second === third
|
||||||
|
) {
|
||||||
|
return PAYOUTS[first] ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Two matching symbols.
|
||||||
|
*
|
||||||
|
* Half the wager is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (
|
||||||
|
first === second ||
|
||||||
|
first === third ||
|
||||||
|
second === third
|
||||||
|
) {
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nut Salad:
|
||||||
|
*
|
||||||
|
* Chestnut + Peanut + Coconut
|
||||||
|
* in any order.
|
||||||
|
*
|
||||||
|
* Returns the wager.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const nutSalad =
|
||||||
|
new Set(
|
||||||
|
result
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
nutSalad.size === 3 &&
|
||||||
|
nutSalad.has("🌰") &&
|
||||||
|
nutSalad.has("🥜") &&
|
||||||
|
nutSalad.has("🥥")
|
||||||
|
) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* DISPLAY
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function buildSpinEmbed(
|
||||||
|
bet,
|
||||||
|
symbols,
|
||||||
|
status
|
||||||
|
) {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setTitle(
|
||||||
|
"🎰 Nut Slots"
|
||||||
|
)
|
||||||
|
|
||||||
|
.setDescription(
|
||||||
|
[
|
||||||
|
"## " +
|
||||||
|
symbols.join(
|
||||||
|
" "
|
||||||
|
),
|
||||||
|
"",
|
||||||
|
`**${status}**`
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
.addFields({
|
||||||
|
name:
|
||||||
|
"Einsatz",
|
||||||
|
|
||||||
|
value:
|
||||||
|
`${bet.toLocaleString()} 🥜`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* BUTTONS
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function buildSlotBetButtons() {
|
||||||
|
return [
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
...SLOT_BETS.map(
|
||||||
|
bet =>
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
`nutSlotsBet${bet}`
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
bet.toLocaleString()
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🥜"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
bet >=
|
||||||
|
500
|
||||||
|
? ButtonStyle.Primary
|
||||||
|
: ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubBack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Nut Hub"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"◀️"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function buildSlotResultButtons() {
|
||||||
|
return [
|
||||||
|
new ActionRowBuilder()
|
||||||
|
.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubSlots"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Play Again"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"🎰"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Primary
|
||||||
|
),
|
||||||
|
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(
|
||||||
|
"nutHubBack"
|
||||||
|
)
|
||||||
|
.setLabel(
|
||||||
|
"Nut Hub"
|
||||||
|
)
|
||||||
|
.setEmoji(
|
||||||
|
"◀️"
|
||||||
|
)
|
||||||
|
.setStyle(
|
||||||
|
ButtonStyle.Secondary
|
||||||
|
)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* SESSION OWNER
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getNutSlotsOwner(
|
||||||
|
interaction
|
||||||
|
) {
|
||||||
|
const footer =
|
||||||
|
interaction.message
|
||||||
|
?.embeds?.[0]
|
||||||
|
?.footer
|
||||||
|
?.text;
|
||||||
|
|
||||||
|
|
||||||
|
const parts =
|
||||||
|
footer?.split(":")
|
||||||
|
??
|
||||||
|
[];
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] ===
|
||||||
|
"nutHub"
|
||||||
|
) {
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
parts[0] ===
|
||||||
|
"nutSlots"
|
||||||
|
) {
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* RANDOM
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
function randomReelSymbol() {
|
||||||
|
return randomItem(
|
||||||
|
REEL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function delay(
|
||||||
|
ms
|
||||||
|
) {
|
||||||
|
return new Promise(
|
||||||
|
resolve =>
|
||||||
|
setTimeout(
|
||||||
|
resolve,
|
||||||
|
ms
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
showNutSlots,
|
||||||
|
playNutSlots
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user