Skip to content

Commit

Permalink
Merge pull request #39 from stt-datacore/v13-and-slash
Browse files Browse the repository at this point in the history
Slash Commands!
  • Loading branch information
ineffyble authored May 29, 2021
2 parents 6a7b5c8 + 5d72e30 commit adabf70
Show file tree
Hide file tree
Showing 25 changed files with 551 additions and 98 deletions.
18 changes: 8 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"dependencies": {
"as-table": "^1.0.55",
"chokidar": "^3.4.0",
"discord.js": "^12.5.3",
"discord-api-types": "^0.18.1",
"discord.js": "git+https://github.com/discordjs/discord.js.git#f8703e3e59839d7380795ecf719d5bac691860a4",
"dotenv": "^8.2.0",
"fuse.js": "^6.2.0",
"node-cache": "^5.1.1",
Expand Down
70 changes: 65 additions & 5 deletions src/commands/associate.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import fs from 'fs';
import { Message } from 'discord.js';
import yargs from 'yargs';
import { loadProfile, createUserFromMessage, associateUser } from '../utils/profile';
import { sendAndCache } from '../utils/discord';
import { loadProfile, createUserFromMessage, associateUser, getDbidFromDiscord, loadRemoteProfile } from '../utils/profile';
import { discordUserFromMessage, sendAndCache } from '../utils/discord';
import CONFIG from '../utils/config';
import { Profile } from '../models/Profile';

async function asyncHandler(message: Message, dbid: string, access_token?: string) {
async function asyncHandler(message: Message, dbid: string, devpull: boolean, access_token?: string) {
// This is just to break up the flow and make sure any exceptions end up in the .catch, not thrown during yargs command execution
await new Promise<void>(resolve => setImmediate(() => resolve()));

let user = await createUserFromMessage(message);
if (devpull){
if (process.env.NODE_ENV === 'production') {
sendAndCache(message, `This is a dev-only command.`, {asReply: true, ephemeral: true});
return;
}
dbid = await downloadProfile(message, dbid);
if (!dbid)
return;
}

let result = await associateUser(user, dbid, access_token);
if (result.error) {
sendAndCache(message, `Error: ${result.error}`);
Expand All @@ -23,17 +35,57 @@ async function asyncHandler(message: Message, dbid: string, access_token?: strin
sendAndCache(
message,
` I associated you with the captain profile '${profile.captainName}'. Remember to regularly update your profile online for accurate results!`,
true
{asReply: true}
);
}
}
}

async function downloadProfile(message: Message, dbid: string) {
let author = discordUserFromMessage(message);
if (isNaN(Number(dbid)))
dbid = await getDbidFromDiscord(author!.username, author!.discriminator);
if (!dbid) {
sendAndCache(message, `Sorry, I couldn't find a DBID associated with your Discord username ${author?.username}#${author?.discriminator}. Please manually enter your DBID.`)
throw(`Unable to find a DBID for Discord username ${author?.username}#${author?.discriminator}`);
}
let player_data = await loadRemoteProfile(dbid);
fs.writeFileSync(process.env.PROFILE_DATA_PATH + dbid, JSON.stringify(player_data, undefined, 4), 'utf8');

let captainName = player_data.player.character.display_name;

let shortCrewList = {
crew: player_data.player.character.crew.map((crew: any) => ({ id: crew.archetype_id, rarity: crew.rarity })),
c_stored_immortals: player_data.player.character.c_stored_immortals,
stored_immortals: player_data.player.character.stored_immortals
};

let res = await Profile.findAll({ where: { dbid } });
if (res.length === 0) {
await Profile.create({ dbid, shortCrewList, captainName, lastUpdate: new Date() });
} else {
await res[0].update(
{ dbid, shortCrewList, captainName, lastUpdate: new Date() },
{ where: { dbid } }
);
}

return dbid;
}

class Associate implements Definitions.Command {
name = 'associate';
command = 'associate <dbid> [test]';
aliases = [];
describe = 'Associate your discord user with a previously uploaded profile DBID';
options = [
{
name: 'dbid',
type: 'STRING',
description: 'your DBID',
required: true
}
];
builder(yp: yargs.Argv): yargs.Argv {
return yp
.positional('dbid', {
Expand All @@ -43,6 +95,10 @@ class Associate implements Definitions.Command {
.positional('test', {
describe: 'UNUSED',
type: 'string'
})
.option('dev', {
desc: '(DEV ONLY) Pull your profile from the Datacore.app.',
type: 'boolean',
});
}

Expand All @@ -52,9 +108,13 @@ class Associate implements Definitions.Command {
args.promisedResult = asyncHandler(
message,
args.dbid as string,
args.test ? (args.test as string) : undefined
args.dev as boolean,
args.test ? (args.test as string) : undefined,
);
}
}

export let AssociateCommand = new Associate();



20 changes: 20 additions & 0 deletions src/commands/behold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@ class Behold implements Definitions.Command {
command = 'behold <url>';
aliases = [];
describe = 'Analyzes a behold screenshot and returns crew details if identified';
options = [
{
name: 'url',
type: 'STRING',
description: 'address of a png or jpg image',
required: true,
},
{
name: 'threshold',
type: 'INTEGER',
description: 'lower the threshold for crew detection; the lower it is, the higher the chance for false positives',
required: false,
},
{
name: 'base',
type: 'BOOLEAN',
description: 'ignore user profile if available',
required: false,
},
];
builder(yp: yargs.Argv): yargs.Argv {
return yp
.positional('url', {
Expand Down
54 changes: 54 additions & 0 deletions src/commands/best.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,60 @@ class Best implements Definitions.Command {
command = 'best <type> <skill> [secondskill]';
aliases = [];
describe = 'Searches top crew according to base, gauntlet or average (voyages) skill rating';
options = [
{
name: 'type',
type: 'STRING',
description: 'type of search to do',
required: true,
choices: [
{ name: 'Base skill', value: 'base' },
{ name: 'Gauntlet', value: 'gauntlet' },
{ name: 'Voyage/Average/Combined', value: 'voyage' }
],
},
{
name: 'skill',
type: 'STRING',
description: 'skill to search',
required: true,
choices: [
{ name: 'Science', value: 'sci' },
{ name: 'Security', value: 'sec' },
{ name: 'Engineering', value: 'eng' },
{ name: 'Diplomacy', value: 'dip' },
{ name: 'Command', value: 'cmd' },
{ name: 'Medicine', value: 'med' },
]
},
{
name: 'secondskill',
type: 'STRING',
description: '(optional) second skill to search',
required: false,
choices: [
{ name: 'Science', value: 'sci' },
{ name: 'Security', value: 'sec' },
{ name: 'Engineering', value: 'eng' },
{ name: 'Diplomacy', value: 'dip' },
{ name: 'Command', value: 'cmd' },
{ name: 'Medicine', value: 'med' },
]
},
{
name: 'stars',
type: 'INTEGER',
description: 'limit the search to given number of stars or below',
required: false,
choices: [
{ name: '1', value: 1 },
{ name: '2', value: 2 },
{ name: '3', value: 3 },
{ name: '4', value: 4 },
{ name: '5', value: 5 },
]
}
];
builder(yp: yargs.Argv): yargs.Argv {
return yp
.positional('type', {
Expand Down
29 changes: 15 additions & 14 deletions src/commands/cheapestfffe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,25 +80,26 @@ async function asyncHandler(
}).sort((a: any, b: any) => a.requiredChronCost - b.requiredChronCost);


sendAndCache(message, `Cheapest candidates for immortalisation for **${user.profiles[0].captainName}**'s roster (last updated ${user.profiles[0].lastUpdate.toDateString()})`);

candidatesForImmortalisation.slice(0, 5).forEach((can: any) => {
const embeds = candidatesForImmortalisation.slice(0, 5).map((can: any) => {
const matched = crew.find((crew) => crew.symbol === can.symbol);
if (!matched) {
return;
}
let embed = new MessageEmbed()
.setTitle(`${matched.name} (Level ${can.level})`)
.setDescription(`Missing item costs:`)
.setThumbnail(`${CONFIG.ASSETS_URL}${matched.imageUrlPortrait}`)
.setColor(colorFromRarity(matched.max_rarity))
.addField(getEmoteOrString(message, 'chrons', 'Chrons'), Math.round(can.requiredChronCost), true)
.addField(getEmoteOrString(message, 'shuttle', 'Faction'), `${can.requiredFactionItems} items`, true)
.addField(getEmoteOrString(message, 'credits', 'Credits'), can.craftCost, true)
.setFooter(`${matched.name} is in ${matched.collections.length === 0 ? 'no collections' : `the following collections: ${matched.collections.join(', ')}`}`);
sendAndCache(message, embed);
});;
return new MessageEmbed()
.setTitle(`${matched.name} (Level ${can.level})`)
.setDescription(`Missing item costs:`)
.setThumbnail(`${CONFIG.ASSETS_URL}${matched.imageUrlPortrait}`)
.setColor(colorFromRarity(matched.max_rarity))
.addField(getEmoteOrString(message, 'chrons', 'Chrons'), Math.round(can.requiredChronCost), true)
.addField(getEmoteOrString(message, 'shuttle', 'Faction'), `${can.requiredFactionItems} items`, true)
.addField(getEmoteOrString(message, 'credits', 'Credits'), can.craftCost, true)
.setFooter(`${matched.name} is in ${matched.collections.length === 0 ? 'no collections' : `the following collections: ${matched.collections.join(', ')}`}`);
});

sendAndCache(message,
`Cheapest candidates for immortalisation for **${user.profiles[0].captainName}**'s roster (last updated ${user.profiles[0].lastUpdate.toDateString()})`,
{ embeds }
);
}

class CheapestFFFE implements Definitions.Command {
Expand Down
41 changes: 37 additions & 4 deletions src/commands/crewneed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ async function asyncHandler(message: Message, searchString: string, level: numbe
}

if (results === undefined && loadSpecial === 0) {
sendAndCache(message, `Sorry, I couldn't find a crew matching '${searchString}'`);
sendAndCache(message, `Sorry, I couldn't find a crew matching '${searchString}'`, { ephemeral: true});
} else if (results && results.length > 1) {
sendAndCache(
message,
`There are ${results.length} crew matching that: ${results.map((crew) => crew.name).join(', ')}. Which one did you mean?`
`There are ${results.length} crew matching that: ${results.map((crew) => crew.name).join(', ')}. Which one did you mean?`,
{ ephemeral: true}
);
} else {
if (loadSpecial > 0) {
Expand Down Expand Up @@ -201,7 +202,7 @@ async function asyncHandler(message: Message, searchString: string, level: numbe
true
);

sendAndCache(message, embed);
sendAndCache(message, '', {embeds: [embed]});
}
}
}
Expand All @@ -212,6 +213,38 @@ class CrewNeed implements Definitions.Command {
command = 'crewneed <crew...>';
aliases = ['need'];
describe = 'Shows a breakdown of items needed to craft equipment for a crew';
options = [
{
name: 'crew',
type: 'STRING',
description: 'name of crew or part of the name',
required: true,
},
{
name: 'level',
type: 'INTEGER',
description: 'starting level',
required: false,
},
{
name: 'item',
type: 'STRING',
description: 'filter to specific items',
required: false,
},
{
name: 'all',
type: 'BOOLEAN',
description: 'expand the entire recipe (including owned items)',
required: false,
},
{
name: 'base',
type: 'BOOLEAN',
description: 'return common stats (not adjusted for your profile)',
required: false,
}
];
builder(yp: yargs.Argv): yargs.Argv {
return yp
.positional('crew', {
Expand Down Expand Up @@ -241,7 +274,7 @@ class CrewNeed implements Definitions.Command {

handler(args: yargs.Arguments) {
let message = <Message>args.message;
let searchString = (<string[]>args.crew).join(' ');
let searchString = typeof(args.crew) === 'string' ? args.crew : (<string[]>args.crew).join(' ');
let level = args.level ? (args.level as number) : 0;
let all = args.all ? (args.all as boolean) : false;
let base = args.base ? (args.base as boolean) : false;
Expand Down
12 changes: 10 additions & 2 deletions src/commands/dilemma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ async function asyncHandler(message: Message, searchString: string) {
embed = embed.addField('Choice C', formatChoice(message, dilemma.choiceC));
}

sendAndCache(message, embed);
sendAndCache(message, '', {embeds: [embed]});
});
}
}
Expand All @@ -43,6 +43,14 @@ class Dilemma implements Definitions.Command {
command = 'dilemma <title...>';
aliases = ['dd'];
describe = 'Searches dilemmas with the given title';
options = [
{
name: 'title',
type: 'STRING',
description: "(part of) the dilemma's title",
required: true
}
];
builder(yp: yargs.Argv): yargs.Argv {
return yp.positional('title', {
describe: "(part of) the dilemma's title"
Expand All @@ -51,7 +59,7 @@ class Dilemma implements Definitions.Command {

handler(args: yargs.Arguments) {
let message = <Message>args.message;
let searchString = (<string[]>args.title).join(' ');
let searchString = typeof(args.title) === 'string' ? args.title : (<string[]>args.title).join(' ');

args.promisedResult = asyncHandler(message, searchString);
}
Expand Down
Loading

0 comments on commit adabf70

Please sign in to comment.