mirror of
https://github.com/ION606/selmerBot.git
synced 2026-05-15 05:36:54 +00:00
Added the 'game tictactoe' command
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
//@ts-check
|
||||
const { MessageActionRow, MessageButton, MessageSelectMenu, Client, CommandInteractionOptionResolver } = require('discord.js');
|
||||
const { STATE } = require('../db/econ');
|
||||
const { winGame, getCustomEmoji } = require('./external_game_functions.js');
|
||||
const { changeTurn } = require('../turnManager.js');
|
||||
const { game_class_battle } = require('./game_classes');
|
||||
const { MongoClient } = require('mongodb');
|
||||
const { convertSnowflakeToDate } = require('../db/addons/snowflake');
|
||||
|
||||
|
||||
function postActionBar(thread, user_dbo) {
|
||||
user_dbo.find({'hpmp.hp': {$exists: true}}).toArray((err, docs) => {
|
||||
const hp = docs[0].hpmp.hp;
|
||||
const mp = docs[0].hpmp.mp;
|
||||
let row;
|
||||
|
||||
if (docs[0].gamesettings.battle.class != 'none' && docs[0].gamesettings.battle.ultimate) {
|
||||
row = new MessageActionRow()
|
||||
.addComponents(
|
||||
new MessageButton()
|
||||
.setCustomId('ATTACK')
|
||||
.setLabel('ATTACK')
|
||||
.setStyle('DANGER'),
|
||||
new MessageButton()
|
||||
.setCustomId('HEAL')
|
||||
.setLabel('HEAL')
|
||||
.setStyle('SUCCESS'),
|
||||
new MessageButton()
|
||||
.setCustomId('DEFEND')
|
||||
.setLabel('DEFEND')
|
||||
.setStyle('PRIMARY'),
|
||||
new MessageButton()
|
||||
.setCustomId('ULTIMATE')
|
||||
.setLabel('ULTIMATE')
|
||||
.setStyle('DANGER')
|
||||
);
|
||||
} else {
|
||||
//If the ultimate can't be used, change the menu
|
||||
row = new MessageActionRow()
|
||||
.addComponents(
|
||||
new MessageButton()
|
||||
.setCustomId('ATTACK')
|
||||
.setLabel('ATTACK')
|
||||
.setStyle('DANGER'),
|
||||
new MessageButton()
|
||||
.setCustomId('HEAL')
|
||||
.setLabel('HEAL')
|
||||
.setStyle('SUCCESS'),
|
||||
new MessageButton()
|
||||
.setCustomId('DEFEND')
|
||||
.setLabel('DEFEND')
|
||||
.setStyle('PRIMARY'),
|
||||
);
|
||||
}
|
||||
/*
|
||||
//UNDER DEVELOPMENT
|
||||
new MessageButton()
|
||||
.setCustomId('ITEMS')
|
||||
.setLabel('ITEMS')
|
||||
.setStyle('SECONDARY')
|
||||
*/
|
||||
|
||||
thread.send({ content: `Your turn <@${user_dbo.s.namespace.collection}>!\nHP: ${hp}\t|\tMP: ${mp}`, components: [row] });
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by "attack"
|
||||
* @param {game_class_battle} gclass
|
||||
*/
|
||||
function attack_special(client, user_dbo, other_dbo, bot, thread, xp_collection, interaction, gclass) {
|
||||
const atk = gclass.specialAttack;
|
||||
if (!atk) { return thread.send("You don't have a class, and so can't use an ultimate!"); }
|
||||
|
||||
user_dbo.find({'rank': {$exists: true}}).toArray((err, docs) => {
|
||||
const doc = docs[0];
|
||||
|
||||
//Check if the user can use ultimate
|
||||
if (atk.dmg.split('*')[0] == 'r') {
|
||||
const rank = doc.rank;
|
||||
const dmg = Number(atk.dmg.split('*')[1]) * rank;
|
||||
attack(client, user_dbo, other_dbo, bot, thread, xp_collection, interaction, dmg);
|
||||
}
|
||||
})
|
||||
|
||||
//Apply a "stunned" effect
|
||||
if (atk.prone == true) {
|
||||
other_dbo.updateOne({'state': {$exists: true}}, {$set: {state: STATE.PRONE}});
|
||||
thread.send(`<@${interaction.user.id}> was knocked prone and lost 1 turn!`);
|
||||
}
|
||||
|
||||
changeTurn(client, bot, interaction);
|
||||
}
|
||||
|
||||
|
||||
//Bow special phrase: Σ>―(´・ω・`)→
|
||||
function attack(client, user_dbo, other_dbo, bot, thread, xp_collection, interaction, preset_damage = 0) {
|
||||
//Get the weapon
|
||||
user_dbo.find({'equipped': {$exists: true}}).toArray(function(err, docs) {
|
||||
const doc = docs[0];
|
||||
const all_weapons = doc.equipped.weapons;
|
||||
const weapon = all_weapons.main;
|
||||
|
||||
var dmg = 0;
|
||||
|
||||
//No weapons (punch)
|
||||
if (preset_damage > 0) {
|
||||
dmg = preset_damage;
|
||||
} else {
|
||||
if (weapon == null) {
|
||||
dmg = doc.rank;
|
||||
} else {
|
||||
dmg = (doc.rank - 1) + Math.round(weapon.cost/5);
|
||||
}
|
||||
}
|
||||
|
||||
other_dbo.find({'equipped': {$exists: true}}).toArray(function (err, docs) {
|
||||
const odoc = docs[0];
|
||||
|
||||
//Handle defending
|
||||
if (odoc.state == STATE.DEFENDING) {
|
||||
var def = odoc.rank - doc.rank;
|
||||
//Make sure we don't go negative
|
||||
if (def < 0) { def = 0; }
|
||||
|
||||
dmg /= 2 + def;
|
||||
}
|
||||
|
||||
var new_hp = odoc.hpmp.hp -= dmg;
|
||||
if (new_hp <= 0) {
|
||||
winGame(client, bot, client.db(user_dbo.s.namespace.db), user_dbo, xp_collection, interaction.message);
|
||||
} else {
|
||||
other_dbo.updateOne({'equipped': {$exists: true}}, { $set: { 'hpmp.hp': new_hp, state: STATE.FIGHTING }});
|
||||
|
||||
//Change turns
|
||||
changeTurn(client, bot, interaction);
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
//Check for a "special" animation
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function heal(interaction, client, user_dbo, bot, thread, command, mongouri, items) {
|
||||
if (interaction.message.content.toLowerCase().indexOf('Which item would you like to use?') != -1) {
|
||||
// The person picked out an item
|
||||
//I think this is unecessary
|
||||
}
|
||||
|
||||
//Get the 'healing' items (stored in "{item}: num" format)
|
||||
user_dbo.find({'equipped': {$exists: true}}).toArray(async function(err, docs) {
|
||||
const doc = docs[0];
|
||||
const rawitems = doc.equipped.items;
|
||||
if (JSON.stringify(rawitems) == '{}') {
|
||||
interaction.editReply("You don't have any items!");
|
||||
return postActionBar(thread, user_dbo);
|
||||
}
|
||||
|
||||
console.log(rawitems);
|
||||
const items = rawitems.filter(function(f) { return (f.sect.toLowerCase() == 'hp') });
|
||||
|
||||
if (JSON.stringify(items) == '[]') {
|
||||
interaction.editReply("You don't have any healing items!");
|
||||
return postActionBar(thread, user_dbo);
|
||||
} else { console.log(JSON.stringify(items))}
|
||||
|
||||
var itemlist = [];
|
||||
|
||||
items.forEach(function(item) {
|
||||
let n = item.name;
|
||||
|
||||
let h = (doc.rank - 1) + Math.round(item.cost/10);
|
||||
|
||||
itemlist.push({label: n, description: `Restores ${h} health (${item.num})`, value: `${n}`});
|
||||
});
|
||||
|
||||
|
||||
//Find something to heal with
|
||||
const row = new MessageActionRow()
|
||||
.addComponents(
|
||||
new MessageSelectMenu()
|
||||
.setCustomId(`${interaction.user.id}|heal`)
|
||||
.setPlaceholder('Nothing selected')
|
||||
.addOptions(itemlist),
|
||||
);
|
||||
|
||||
await interaction.editReply({ content: 'Please choose a health potion!', components: [row] });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//Gets items by section/name, reacts with them to the message, when pressed, trigger a response
|
||||
function presentItems(interaction, client, user_dbo, bot, thread) {
|
||||
// throw 'THE "ITEM" COMMAND HAS NOT BEEN SET UP YET!';
|
||||
user_dbo.find({'equipped': {$exists: true}}).toArray(async function(err, docs) {
|
||||
const doc = docs[0];
|
||||
const items = doc.equipped.items;
|
||||
// const items = rawitems.filter(function(f) { return (f.sect.toLowerCase() == 'hp') });
|
||||
|
||||
|
||||
if (JSON.stringify(items) == '[]' || JSON.stringify(items) == '{}') {
|
||||
interaction.editReply("You don't have any items!");
|
||||
return postActionBar(thread, user_dbo);
|
||||
} else { console.log(JSON.stringify(items))}
|
||||
|
||||
var itemlist = [];
|
||||
|
||||
items.forEach(function(item) {
|
||||
let n = item.name;
|
||||
|
||||
|
||||
|
||||
itemlist.push({label: n, description: `${item.num} equipped!`, value: `${n}`});
|
||||
});
|
||||
|
||||
|
||||
//Find something to heal with
|
||||
const row = new MessageActionRow()
|
||||
.addComponents(
|
||||
new MessageSelectMenu()
|
||||
.setCustomId(`${interaction.user.id}|item`)
|
||||
.setPlaceholder('Nothing selected')
|
||||
.addOptions(itemlist)
|
||||
);
|
||||
|
||||
await interaction.editReply({ content: 'Please choose an item!', components: [row] });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function defend(client, interaction, user_dbo, bot, thread) {
|
||||
user_dbo.find({'equipped': {$exists: true}}).toArray(function(err, docs) {
|
||||
const doc = docs[0];
|
||||
const all_weapons = doc.equipped.weapons;
|
||||
|
||||
//They don't have a shield
|
||||
if (all_weapons == undefined) {
|
||||
thread.send("You don't have a shield equipped!");
|
||||
}
|
||||
const shield = all_weapons.secondary;
|
||||
|
||||
//Change state
|
||||
user_dbo.updateOne({state: {$exists: true}}, {$set: {state: STATE.DEFENDING}});
|
||||
|
||||
changeTurn(client, bot, interaction);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function usePotion(interaction, client, user_dbo, bot, thread) {
|
||||
const name = interaction.values[0];
|
||||
const cursor = user_dbo.find({'equipped.items': {$exists: true}});
|
||||
|
||||
let doc = cursor.next().then((result) => {
|
||||
var allitems = Array.from(result.equipped.items);
|
||||
let items = allitems.filter((it) => { return it.name == name; })[0];
|
||||
let ind = allitems.findIndex((it) => { return it.name == name; })
|
||||
|
||||
//Apply the item's effects
|
||||
if (name.toLowerCase().indexOf('hp') != -1) {
|
||||
let h = (result.rank - 1) + Math.round(items.cost/10);
|
||||
user_dbo.updateOne({"game": {$exists: true}}, { $set: {'hpmp.hp': (result.hpmp.hp + h)}})
|
||||
}
|
||||
|
||||
//Deal with the item itself
|
||||
//If there's more than 1, subtract 1
|
||||
if (items.num > 1) { items.num -= 1; allitems[ind] = items; }
|
||||
else { allitems.splice(ind, 1) }
|
||||
|
||||
user_dbo.updateOne({'equipped.items': {$exists: true}}, {$set: {'equipped.items': allitems}});
|
||||
})
|
||||
|
||||
|
||||
changeTurn(client, bot, interaction);
|
||||
postActionBar(thread, user_dbo);
|
||||
}
|
||||
|
||||
|
||||
function cast() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {MongoClient} client
|
||||
* @param {*} user_dbo
|
||||
* @param {*} other_dbo
|
||||
* @param {Client} bot
|
||||
* @param {*} thread
|
||||
* @param {String} command
|
||||
* @param {String} mongouri
|
||||
* @param {String[]} items
|
||||
* @param {*} interaction
|
||||
* @param {Map<string, Map>} xp_collection
|
||||
*/
|
||||
async function handle(client, user_dbo, other_dbo, bot, thread, command, mongouri, items, interaction, xp_collection) {
|
||||
|
||||
if (command == 'initalize') {
|
||||
return postActionBar(thread, user_dbo);
|
||||
} else if (command == 'attack') {
|
||||
attack(client, user_dbo, other_dbo, bot, thread, xp_collection, interaction);
|
||||
postActionBar(thread, other_dbo);
|
||||
} else if (command == 'items') {
|
||||
presentItems(interaction, client, user_dbo, bot, thread); //Maybe like wands?
|
||||
} else if (command == 'heal') {
|
||||
heal(interaction, client, user_dbo, bot, thread, command, mongouri, items); //.then(() => {postActionBar(thread, other_dbo)});
|
||||
} else if (command == 'usepotion') {
|
||||
usePotion(interaction, client, user_dbo, bot, thread);
|
||||
} else if (command == 'defend') {
|
||||
defend(client, interaction, user_dbo, bot, thread);
|
||||
postActionBar(thread, user_dbo);
|
||||
} else if (command == 'ultimate') {
|
||||
user_dbo.find({'gamesettings': {$exists: true}}).toArray((err, docs) => {
|
||||
var gclass = new game_class_battle(docs[0].gamesettings.battle.class);
|
||||
attack_special(client, user_dbo, other_dbo, bot, thread, xp_collection, interaction, gclass);
|
||||
postActionBar(thread, user_dbo);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = { handle, postActionBar }
|
||||
@@ -0,0 +1,90 @@
|
||||
//@ts-check
|
||||
const { addxp, STATE, BASE } = require("../db/econ");
|
||||
const turnManger = require('../turnManager.js');
|
||||
|
||||
|
||||
//#region game lose/win
|
||||
function loseGame(user_dbo, xp_collection, message, bot = null) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){
|
||||
const doc = docs[0];
|
||||
if (doc == undefined) { return message.reply("Oops! There's been an error! Please contact support if this problem persists!"); }
|
||||
if (doc.game == null) { return message.reply("You're not even in a game and you're trying to quit! Sad..."); }
|
||||
|
||||
var addbal;
|
||||
//If this function was called from "winGame", return
|
||||
if (doc.opponent) {
|
||||
//If remove some money (looting) [maybe implement a "friendly" game setting later with no looting]
|
||||
addbal = doc.rank * 2;
|
||||
if (doc.balance - addbal < 5) { addbal = addbal - doc.balance; }
|
||||
if (doc.balance > 5) {
|
||||
user_dbo.updateOne(doc, { $set: { balance: doc.balance - addbal}});
|
||||
}
|
||||
} else { message.channel.delete(); }
|
||||
|
||||
//Update the player's xp
|
||||
addxp(message, user_dbo, Math.ceil((BASE.XP * doc.rank)/2),xp_collection)
|
||||
user_dbo.updateOne({"game": {$exists: true}}, { $set: { game: null, opponent: null, state: STATE.IDLE, 'hpmp.hp': doc.hpmp.maxhp, 'hpmp.mp': doc.hpmp.maxmp }});
|
||||
|
||||
resolve(addbal);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
function winGame(client, bot, db, user_dbo, xp_collection, message) {
|
||||
user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){
|
||||
const doc = docs[0];
|
||||
|
||||
//Check for an opponent
|
||||
if (doc.opponent != null) {
|
||||
let other = db.collection(doc.opponent);
|
||||
let promise_temp = loseGame(other, xp_collection, message);
|
||||
|
||||
promise_temp.then(function(result) {
|
||||
var amt_taken = result;
|
||||
user_dbo.updateOne({'balance': {$exists: true}}, { $set: { balance: doc.balance + amt_taken}});
|
||||
});
|
||||
}
|
||||
|
||||
//Delete the bot's record of the game
|
||||
client.db('B|S' + bot.user.id).collection(user_dbo.s.namespace.db.substr(0, user_dbo.s.namespace.db.length - 6)).drop();
|
||||
|
||||
|
||||
//Update the player with xp
|
||||
user_dbo.updateOne({"game": {$exists: true}}, { $set: { game: null, opponent: null, state: STATE.IDLE, xp: doc.xp + (BASE.XP * doc.rank), 'hpmp.hp': doc.hpmp.maxhp, 'hpmp.mp': doc.hpmp.maxmp }});
|
||||
|
||||
const channel = bot.channels.cache.get(message.channel.parentId);
|
||||
channel.send(`<@${user_dbo.s.namespace.collection}> just won a game of "${docs[0].game}"!`);
|
||||
message.channel.delete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function equipItem(client, bot, db, dbo, message) {
|
||||
|
||||
if (!bot.inDebugMode) { return; }
|
||||
let items = [
|
||||
{ name: 'HP Potion', cost: 20, icon: 'CUSTOM|healing_potion', sect: 'HP', num: 2 },
|
||||
{ name: 'Super HP Potion', cost: 50, icon: 'CUSTOM|super_healing_potion', sect: 'HP', num: 2 },
|
||||
{ name: 'MP Potion', cost: 15, icon: 'CUSTOM|mana_potion', sect: 'MP', num: 2 }
|
||||
]
|
||||
for (let i = 1; i <= 10; i ++) {
|
||||
|
||||
items.push({ name: `${String.fromCharCode(i + 64)}`, cost: i * 10, icon: 'N/A', sect: 'N/A', num: i })
|
||||
}
|
||||
|
||||
dbo.updateMany({}, {$set: {'equipped.items': items}});
|
||||
}
|
||||
|
||||
function getCustomEmoji(bot, name) {
|
||||
let srv = bot.guilds.cache.get(bot.home_server).emojis.cache;
|
||||
// console.log(srv);
|
||||
let emj = srv.find((g) => { return g.name == name });
|
||||
// message.channel.send(`${emj}`);
|
||||
return `${emj}`;
|
||||
}
|
||||
|
||||
|
||||
module.exports = { winGame, loseGame, equipItem, getCustomEmoji }
|
||||
@@ -0,0 +1,398 @@
|
||||
// // @ts-check //Disabled
|
||||
|
||||
const { MongoClient, ServerApiVersion } = require('mongodb');
|
||||
let ecoimport = require("../db/econ.js");
|
||||
|
||||
//#region Game Imports
|
||||
const battle = require("./battle.js");
|
||||
const ttt = require('./tictactoe.js');
|
||||
|
||||
//#endregion
|
||||
|
||||
let snowflake = require("../db/addons/snowflake.js");
|
||||
const STATE = ecoimport.STATE;
|
||||
const BASE = ecoimport.BASE;
|
||||
|
||||
const { winGame, loseGame, equipItem } = require('./external_game_functions.js');
|
||||
const { chooseClass, presentClasses } = require('./game_classes.js');
|
||||
|
||||
//Has a list of all games (used to change player state)
|
||||
const allGames = ['battle', 'Tic Tac Toe'];
|
||||
// const { NULL } = require('mysql/lib/protocol/constants/types');
|
||||
|
||||
|
||||
//#region functions (NOT GAME SPECIFIC)
|
||||
|
||||
/** Adds the game type tag to the user(s) so the system can tell what game they're playing
|
||||
* @param other_dbo optional, include if the game has two players
|
||||
*/
|
||||
async function Initialize(bot, user_dbo, command, message, first, second, other_dbo = null) {
|
||||
return new Promise(async function(resolve, reject) {
|
||||
user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){
|
||||
let doc = docs[0];
|
||||
console.log(command);
|
||||
if (allGames.indexOf(command) != -1) {
|
||||
if (other_dbo != null) {
|
||||
user_dbo.updateOne( { "game": {$exists: true} }, { $set: { game: command, opponent: other_dbo.s.namespace.collection, state: STATE.FIGHTING }});
|
||||
other_dbo.updateOne({ "game": {$exists: true} }, { $set: { game: command, opponent: user_dbo.s.namespace.collection, state: STATE.FIGHTING }});
|
||||
} else {
|
||||
user_dbo.updateOne({ "game": {$exists: true} }, { $set: { game: command, state: STATE.FIGHTING }});
|
||||
}
|
||||
|
||||
} else { message.reply(`ERROR! ${command} IS NOT A GAME!`); }
|
||||
});
|
||||
|
||||
//Create a new thread for the game (maybe uneccesary???) - done before initialize
|
||||
let name_first = await bot.users.cache.get(first);
|
||||
let name_second = await bot.users.cache.get(second);
|
||||
|
||||
// message.reply(`${first} [${name_first}], ${second} [${name_second}]`); throw 'ERR';
|
||||
const threadname = `${name_first.username} VS ${name_second.username} [${command.toUpperCase()}]`;
|
||||
|
||||
const thread = await message.channel.threads.create({
|
||||
name: threadname,
|
||||
// type: 'GUILD_PRIVATE_THREAD',
|
||||
autoArchiveDuration: 60,
|
||||
reason: `N/A`,
|
||||
});
|
||||
|
||||
//Need lvl 2 boost for this
|
||||
// thread.add(first);
|
||||
// thread.add(second);
|
||||
|
||||
message.channel.send(`<@${first}> and <@${second}> have started a game of ***${command.toUpperCase()}!***`);
|
||||
|
||||
resolve(thread);
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//replies to the message with current game specifics
|
||||
function getGame(message, args, db) {
|
||||
let id;
|
||||
var temp;
|
||||
|
||||
if (args.length == 1 && String(args[0]).startsWith('<')) { id = args[0].substr(2, args[0].length - 3)}
|
||||
else { id = message.author.id; }
|
||||
var user_dbo = db.collection(message.author.id);
|
||||
|
||||
user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){
|
||||
const doc = docs[0];
|
||||
if (doc.game == null) {
|
||||
return message.reply(`<@${id}> is not currently playing a game!`);
|
||||
}
|
||||
|
||||
temp = `<@${id}> is currently playing "${doc.game}"`;
|
||||
|
||||
if (doc.opponent != null) {
|
||||
temp += ` with <@${doc.opponent}>`
|
||||
}
|
||||
|
||||
message.reply(temp);
|
||||
});
|
||||
}
|
||||
|
||||
function acceptIsValid(bot, other_discord, message, msg, tag_len) {
|
||||
|
||||
if (other_discord == undefined) {
|
||||
message.reply("This is not a valid invite!");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Make sure the bot was the one creating the invite
|
||||
let check0 = msg.author.bot;
|
||||
|
||||
//Author
|
||||
let tag = msg.content.substr(2, tag_len);
|
||||
let check1 = Number(tag) == Number(message.author.id);
|
||||
|
||||
//Time (within the last 5 min)
|
||||
let prev = snowflake.convertSnowflakeToDate(msg.id);
|
||||
let now = snowflake.convertSnowflakeToDate(message.id);
|
||||
// @ts-ignore
|
||||
let diff = now - prev;
|
||||
var minutes = Math.floor((diff/1000)/60);
|
||||
let check2 = minutes <= 5 || bot.inDebugMode;
|
||||
|
||||
if (!check0) { message.reply("really?"); }
|
||||
else if (!check1 && check2) { message.reply("_INVALID USER_"); }
|
||||
else if (check1 && !check2) { message.reply("_THIS INVITE EXPIRED!_"); }
|
||||
else if (!check1 && !check2) { message.reply("_THIS MESSAGE HAS AN INVALID USER AND HAS EXPIRED_")}
|
||||
|
||||
return (check0 && check1 && check2);
|
||||
}
|
||||
|
||||
|
||||
function hpmp(message, command, dbo) {
|
||||
// throw 'THIS HAS NOT BEEN UPDATED WITH THE MOST RECENT VERSION OF THE MONGODB STRUCTURE!';
|
||||
if (command == 'hp') {
|
||||
dbo.find({"hpmp": {$exists: true}}).toArray(function(err, doc) {
|
||||
return message.reply(`You have ${String(doc[0].hpmp.hp)} hp left!`);
|
||||
});
|
||||
} else if (command == 'mp') {
|
||||
dbo.find({"hpmp": {$exists: true}}).toArray(function(err, doc) {
|
||||
return message.reply(`You have ${String(doc[0].hpmp.hp)} mp left!`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function equip(message, args, command, dbo, bot, shop) {
|
||||
const inp = args[1];
|
||||
|
||||
//Check if the user is already in a game
|
||||
dbo.find({'game': {$exists: true}}).toArray(function(err, docs) {
|
||||
const doc = docs[0];
|
||||
|
||||
if (doc.game != null) {
|
||||
ret = true;
|
||||
console.log(doc.game);
|
||||
return message.reply('You can\'t equip while in a game!');
|
||||
}
|
||||
|
||||
//If the thing is a shield, add it to secondary
|
||||
if (inp.toLowerCase().indexOf('shield') != -1) {
|
||||
dbo.find({def: true}).toArray(function(err, docs) {
|
||||
if (docs[0] != undefined) {
|
||||
dbo.updateOne({}, {$set: {'equipped.weapons.secondary': docs[0]}});
|
||||
} else {
|
||||
message.reply("You don't own a shield!");
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
//Else, equip the weapon(s)
|
||||
|
||||
dbo.find({name: inp, sect: 'Weapons'}).toArray(function(err, docs) {
|
||||
if (docs[0] != undefined) {
|
||||
//Equip the weapon
|
||||
dbo.updateOne({}, {$set: {'equipped.weapons.main': docs[0]}});
|
||||
} else {
|
||||
message.reply(`You don't own any ${inp}s!`);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Game Handlers
|
||||
|
||||
function in_game_redirector(bot, interaction, threadname, doc, client, mongouri, items, xp_collection) {
|
||||
|
||||
//Maybe fix this later......
|
||||
let turn = doc.turn;
|
||||
const user1 = doc[turn];
|
||||
const user2 = doc[Number(!turn)];
|
||||
const db = client.db(interaction.guildId + "[ECON]");
|
||||
const dbo = db.collection(user1);
|
||||
const other = db.collection(user2);
|
||||
const thread = interaction.channel;
|
||||
|
||||
dbo.find({'game': {$exists: true}}).toArray(function (err, docs) {
|
||||
const game = docs[0].game
|
||||
|
||||
switch (game) {
|
||||
case 'battle': battle.handle(client, dbo, other, bot, thread, interaction.customId.toLowerCase(), mongouri, items, interaction, xp_collection);
|
||||
break;
|
||||
|
||||
case 'Tic Tac Toe': ttt.handle(client, db, dbo, other, bot, thread, null, doc, interaction, xp_collection);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
module.exports ={
|
||||
name: "game",
|
||||
description: "Play a game using Selmer Bot!",
|
||||
async execute(bot, message, args, command, Discord, mongouri, items, xp_collection) {
|
||||
|
||||
|
||||
//#region Setup
|
||||
const id = message.author.id;
|
||||
const server = message.guild.id;
|
||||
|
||||
// @ts-ignore
|
||||
const client = new MongoClient(mongouri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });
|
||||
if (client.writeConcern || client.writeConcern) {
|
||||
client.close();
|
||||
return message.reply("Something went wrong with the database, please try again later and contact support if this problem persists!");
|
||||
}
|
||||
|
||||
const botdb = client.db('B|S' + bot.user.id);
|
||||
const serverinbotdb = botdb.collection(server);
|
||||
|
||||
//Initialize if necessary
|
||||
ecoimport.CreateNewCollection(message, client, server, id);
|
||||
command = args[0];
|
||||
|
||||
//Check for a second person and create a second database entry if neccessary
|
||||
if (message.mentions.users.first() != undefined) {
|
||||
ecoimport.CreateNewCollection(message, client, server, message.mentions.users.first().id);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
client.connect(err => {
|
||||
const db = client.db(String(server) + "[ECON]");
|
||||
const dbo = db.collection(id);
|
||||
if (err) { return console.log(err); }
|
||||
|
||||
//Check if the client is currently in a game and act accordingly
|
||||
//#region Check Game
|
||||
dbo.find({"game": {$exists: true}}).toArray(async function(err, docs){
|
||||
if (err) { return console.log(err); }
|
||||
let doc = docs[0];
|
||||
let game = null;
|
||||
if (doc) { game = doc.game; }
|
||||
//#endregion
|
||||
|
||||
//#region non-game-specific commands
|
||||
//For TWO+ PLAYER games only!!!
|
||||
if (command == 'accept') {
|
||||
//Handle the messages
|
||||
if (message.reference == null) { return message.reply("Please reply to a valid battle request message!"); }
|
||||
let mid = message.reference.messageId;
|
||||
let msg = await message.channel.messages.fetch(mid);
|
||||
|
||||
//Check if the person actually challenged you
|
||||
//Get the length of any user tag
|
||||
let mentioned = msg.mentions.users.keys();
|
||||
|
||||
let tag_len = String(mentioned.next().value).length;
|
||||
|
||||
//<@tage_len>, <@ --2+tag_len+2+3 = 7+tag_len
|
||||
let other_tag = msg.content.substr(7+tag_len, tag_len);
|
||||
|
||||
const other_discord = msg.mentions.users.get(other_tag);
|
||||
|
||||
//Should also check if the player is already playing a game!!!
|
||||
if (!acceptIsValid(bot, other_discord, message, msg, tag_len)) { return; }
|
||||
|
||||
//Get the opponent
|
||||
const other = db.collection(other_discord.id);
|
||||
let startPos = msg.content.indexOf('"') + 1;
|
||||
let newCommand = msg.content.substr(startPos, msg.content.lastIndexOf('"') - startPos);
|
||||
|
||||
|
||||
//#region BOT SECTION
|
||||
|
||||
//Store both IDs in the database (for turns)
|
||||
let name_first = await bot.users.cache.get(id);
|
||||
let name_second = await bot.users.cache.get(other_discord.id);
|
||||
|
||||
// message.reply(`${first} [${name_first}], ${second} [${name_second}]`); throw 'ERR';
|
||||
const threadname = `${name_first.username} VS ${name_second.username} [${newCommand.toUpperCase()}]`;
|
||||
var newObj = {0: id, 1: other_discord.id, turn: 0, thread: threadname};
|
||||
|
||||
if (newCommand.replaceAll(" ", "").toLowerCase() == 'tictactoe') { newCommand = 'Tic Tac Toe'; }
|
||||
|
||||
if (newCommand === 'Tic Tac Toe') {
|
||||
//Create the new board
|
||||
let newboard = ["", "", "", "", "", "", "", "", ""];
|
||||
newObj.board = newboard;
|
||||
let symbols;
|
||||
|
||||
/*DOES NOT WORK
|
||||
if (msg.content.lastIndexOf('>') == msg.content.lenth) {
|
||||
symbols = ['X', 'O'];
|
||||
} else {
|
||||
symbols = msg.content.substring(msg.content.lastIndexOf('>') + 2).split(' ');
|
||||
}
|
||||
*/
|
||||
newObj.symbols = ['X', 'O'];
|
||||
}
|
||||
|
||||
serverinbotdb.insertOne(newObj);
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
//Need this for all 2 player games
|
||||
const result = Initialize(bot, dbo, newCommand, msg, id, other_discord.id, other);
|
||||
|
||||
if (newCommand == 'battle') {
|
||||
result.then(function (thread) {
|
||||
battle.handle(client, dbo, other, bot, thread, 'initalize', mongouri, items, null, xp_collection);
|
||||
});
|
||||
} else if (newCommand == 'Tic Tac Toe') {
|
||||
result.then(function (thread) {
|
||||
ttt.handle(client, db, dbo, other, bot, thread, 'initalize', mongouri, null, xp_collection);
|
||||
});
|
||||
}
|
||||
} else if (command == 'quit') {
|
||||
|
||||
const channel = bot.channels.cache.get(message.channel.parentId);
|
||||
//Remove the turn counter from the bot's database
|
||||
serverinbotdb.deleteOne({0: id} || {1: id});
|
||||
if (doc.opponent != null) {
|
||||
// let other = message.guild.members.cache.get(doc.opponent);
|
||||
let other = db.collection(doc.opponent);
|
||||
channel.send(`<@${message.author.id}> has quit a game of "${game}" with <@${doc.opponent}>!`);
|
||||
winGame(client, bot, db, other, xp_collection, message);
|
||||
} else {
|
||||
loseGame(dbo, xp_collection, message, bot);
|
||||
channel.send(`<@${message.author.id}> has quit a game of "${game}"!`);
|
||||
}
|
||||
}
|
||||
else if (command == 'status') {
|
||||
getGame(message, args, db);
|
||||
} else if (command == 'hp' || command == 'mp') {
|
||||
hpmp(message, command, dbo);
|
||||
} else if (command == 'equip') {
|
||||
// equipItem(client, bot, db, dbo, message);
|
||||
equip(message, args, command, dbo, bot, items);
|
||||
} else if (command == 'classes') {
|
||||
presentClasses(message, args[1]);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region game-specific commands
|
||||
else {
|
||||
//Make change to new name if necessary
|
||||
if (command.replaceAll(" ", "").toLowerCase() == 'tictactoe') { command = 'Tic Tac Toe'; }
|
||||
|
||||
if (game == 'battle' || command == 'battle') {
|
||||
if (!bot.inDebugMode) { return message.reply("This command is currently in development!"); }
|
||||
|
||||
//Handle sending the request and making sure the user exists here
|
||||
let other_discord = message.mentions.users.first();
|
||||
if (other_discord == undefined) {
|
||||
return message.reply(`${args[1]} is not a valid user!`);
|
||||
}
|
||||
|
||||
message.channel.send(`${other_discord}, <@${message.author.id}> has invited you to play _"battle"_. To accept, please reply to this message with _!game accept_`);
|
||||
} else if (game == 'Tic Tac Toe' || command == 'Tic Tac Toe') {
|
||||
let other_discord = message.mentions.users.first();
|
||||
if (other_discord == undefined) {
|
||||
return message.reply(`${args[1]} is not a valid user!`);
|
||||
}
|
||||
|
||||
message.channel.send(`${other_discord}, <@${message.author.id}> has invited you to play _"Tic Tac Toe"_. To accept, please reply to this message with _!game accept_`);
|
||||
}
|
||||
|
||||
//Catch statement (invalid command)
|
||||
else {
|
||||
if (command == undefined) { message.reply("Please specify a game or use _!game help_"); }
|
||||
else { message.reply(`'!game ${command}' is not a command!`); }
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
client.close();
|
||||
}, allGames, in_game_redirector
|
||||
}
|
||||
|
||||
|
||||
//#endregion
|
||||
@@ -0,0 +1,88 @@
|
||||
//Leave this as it's own file in case I want to expand the classes in the future
|
||||
|
||||
const { MessageActionRow, MessageSelectMenu } = require("discord.js");
|
||||
|
||||
|
||||
//#region multiplayer games
|
||||
|
||||
/**
|
||||
* A temporary container to keep track of what abilities each class has
|
||||
* @param {string} name - the name of the class ('fighter', 'wizard', etc.)
|
||||
* @property { Boolean } canUseWeapons
|
||||
* @property { Boolean } canUseSpells
|
||||
* @example var myClass = new game_class('wizard');
|
||||
*/
|
||||
class game_class_battle {
|
||||
constructor(name = 'none') {
|
||||
if (name == 'fighter') {
|
||||
this.canUseWeapons = true;
|
||||
this.canUseSpells = false;
|
||||
this.specialAttack = {
|
||||
icon: 'spatkfight',
|
||||
dmg: 'r*2.5',
|
||||
prone: false
|
||||
};
|
||||
this.description = 'More damage, less effects!';
|
||||
} else if (name == 'wizard') {
|
||||
this.canUseWeapons = false;
|
||||
this.canUseSpells = true;
|
||||
this.specialAttack = {
|
||||
icon: 'spatkwiz',
|
||||
dmg: 'r*2.0',
|
||||
prone: true
|
||||
}
|
||||
this.description = 'Less damage, more effects!';
|
||||
} else if (name == 'none') {
|
||||
//The player doesn't have a class
|
||||
this.canUseSpells = undefined;
|
||||
this.canUseWeapons = undefined;
|
||||
this.specialAttack = undefined;
|
||||
this.description = undefined;
|
||||
}
|
||||
|
||||
this.className = name;
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
//#region functions
|
||||
function presentClasses(message, game) {
|
||||
let classes;
|
||||
|
||||
if (game == 'battle') {
|
||||
classes = [new game_class_battle('fighter'), new game_class_battle('wizard')];
|
||||
} else {
|
||||
return message.reply('Please use the following format for this command: _!game class [game name]_');
|
||||
}
|
||||
|
||||
var classList = [];
|
||||
|
||||
classes.forEach(function(c) {
|
||||
let n = c.className;
|
||||
|
||||
classList.push({label: n, description: `${c.description}`, value: `${n}`});
|
||||
});
|
||||
|
||||
const row = new MessageActionRow()
|
||||
.addComponents(
|
||||
new MessageSelectMenu()
|
||||
.setCustomId(`${message.author.id}|class`)
|
||||
.setPlaceholder('none')
|
||||
.addOptions(classList)
|
||||
)
|
||||
|
||||
message.reply({ content: `Please choose your class <@${message.author.id}>`, components: [row] });
|
||||
}
|
||||
|
||||
|
||||
function chooseClass(user_dbo, message, game) {
|
||||
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
module.exports = { game_class_battle, presentClasses, chooseClass }
|
||||
@@ -0,0 +1,149 @@
|
||||
// @ts-check
|
||||
|
||||
const wait = require('node:timers/promises').setTimeout;
|
||||
const { MessageActionRow, MessageButton, MessageSelectMenu, Client, CommandInteractionOptionResolver } = require('discord.js');
|
||||
const { STATE } = require('../db/econ');
|
||||
const { winGame, getCustomEmoji } = require('./external_game_functions.js');
|
||||
const { changeTurn } = require('../turnManager.js');
|
||||
const { game_class_battle } = require('./game_classes');
|
||||
const { MongoClient } = require('mongodb');
|
||||
const { convertSnowflakeToDate } = require('../db/addons/snowflake');
|
||||
|
||||
//This function is blatantly stolen from https://alialaa.com/blog/tic-tac-toe-js
|
||||
function isTerminal(board) {
|
||||
//Return False if board in empty
|
||||
if (board.every(cell => !cell)) return false;
|
||||
let nums = [0, 0, 0]
|
||||
|
||||
//Checking Horizontal Wins
|
||||
if (board[0] === board[1] && board[0] === board[2] && board[0]) {
|
||||
nums = [0, 1, 2];
|
||||
return {'winner': board[0], 'direction': 'H', 'row': 1, 'nums': nums};
|
||||
}
|
||||
if (board[3] === board[4] && board[3] === board[5] && board[3]) {
|
||||
nums = [3, 4, 5];
|
||||
return {'winner': board[3], 'direction': 'H', 'row': 2, 'nums': nums};
|
||||
}
|
||||
if (board[6] === board[7] && board[6] === board[8] && board[6]) {
|
||||
nums = [6, 7, 8];
|
||||
return {'winner': board[6], 'direction': 'H', 'row': 3, 'nums': nums};
|
||||
}
|
||||
|
||||
//Checking Vertical Wins
|
||||
if (board[0] === board[3] && board[0] === board[6] && board[0]) {
|
||||
nums = [0, 3, 6];
|
||||
return {'winner': board[0], 'direction': 'V', 'column': 1, 'nums': nums};
|
||||
}
|
||||
if (board[1] === board[4] && board[1] === board[7] && board[1]) {
|
||||
nums = [1, 4, 7];
|
||||
return {'winner': board[1], 'direction': 'V', 'column': 2, 'nums': nums};
|
||||
}
|
||||
if (board[2] === board[5] && board[2] === board[8] && board[2]) {
|
||||
nums = [2, 5, 8];
|
||||
return {'winner': board[2], 'direction': 'V', 'column': 3, 'nums': nums};
|
||||
}
|
||||
|
||||
//Checking Diagonal Wins
|
||||
if (board[0] === board[4] && board[0] === board[8] && board[0]) {
|
||||
nums = [0, 4, 8];
|
||||
return {'winner': board[0], 'direction': 'D', 'diagonal': 'main', 'nums': nums};
|
||||
}
|
||||
if (board[2] === board[4] && board[2] === board[6] && board[2]) {
|
||||
nums = [2, 4, 6];
|
||||
return {'winner': board[2], 'direction': 'D', 'diagonal': 'counter', 'nums': nums};
|
||||
}
|
||||
|
||||
//If no winner but the board is full, then it's a draw
|
||||
if (board.every(cell => cell)) {
|
||||
return {'winner': 'draw'};
|
||||
}
|
||||
|
||||
//return false otherwise
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//I know it's sloppy, but when 'initial' is true, 'interaction' will actually be 'thread'
|
||||
function postActionBar(interaction, user_dbo, board, won, initial = false) {
|
||||
let componentlist = [];
|
||||
let newRow = new MessageActionRow();
|
||||
|
||||
for (let i = 0; i < 9; i ++) {
|
||||
let button;
|
||||
|
||||
if (!won) {
|
||||
if (!board[i]) {
|
||||
button = new MessageButton()
|
||||
.setCustomId(`ttt|${i}`)
|
||||
.setLabel('-')
|
||||
.setStyle('SUCCESS')
|
||||
} else {
|
||||
button = new MessageButton()
|
||||
.setCustomId(`ttt|${i}`)
|
||||
.setLabel(board[i])
|
||||
.setStyle('DANGER')
|
||||
.setDisabled(true);
|
||||
}
|
||||
} else {
|
||||
if (i in won.nums) {
|
||||
button = new MessageButton()
|
||||
.setCustomId(`ttt|${i}`)
|
||||
.setLabel('W')
|
||||
.setStyle('SUCCESS')
|
||||
} else {
|
||||
button = new MessageButton()
|
||||
.setCustomId(`ttt|${i}`)
|
||||
.setLabel('F')
|
||||
.setStyle('DANGER')
|
||||
.setDisabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
newRow.addComponents(button);
|
||||
|
||||
if ((i + 1) % 3 == 0) {
|
||||
//Add the row to the list of rows
|
||||
componentlist.push(newRow);
|
||||
newRow = new MessageActionRow();
|
||||
}
|
||||
}
|
||||
|
||||
console.log(componentlist);
|
||||
|
||||
if (initial) {
|
||||
interaction.send({ content: `Your turn <@${user_dbo.s.namespace.collection}>!`, components: componentlist });
|
||||
} else {
|
||||
interaction.update({ content: `Your turn <@${user_dbo.s.namespace.collection}>!`, components: componentlist });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function handle(client, db, dbo, other, bot, thread, command, doc, interaction, xp_collection) {
|
||||
|
||||
if (command == 'initalize') {
|
||||
let board = ["", "", "", "", "", "", "", "", ""];
|
||||
postActionBar(thread, dbo, board, false,true);
|
||||
} else {
|
||||
//Change the board
|
||||
let square = Number(interaction.customId.split('|')[1]);
|
||||
let symbol = doc.symbols[doc.turn];
|
||||
let board = doc.board;
|
||||
board[square] = symbol;
|
||||
client.db('B|S' + bot.user.id).collection(dbo.s.namespace.db.substr(0, dbo.s.namespace.db.length - 6)).updateOne({'board': {$exists: true}}, {$set: {board: board}});
|
||||
|
||||
//Check if the game is over
|
||||
let won = isTerminal(board);
|
||||
|
||||
if (!won) {
|
||||
changeTurn(client, bot, interaction);
|
||||
postActionBar(interaction, other, board, false);
|
||||
changeTurn(client, bot, interaction);
|
||||
} else {
|
||||
postActionBar(interaction, dbo, board, won);
|
||||
await wait(7000);
|
||||
winGame(client, bot, db, dbo, xp_collection, interaction.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { handle }
|
||||
Reference in New Issue
Block a user