Bastion is a Discord bot written in the NodeJS module discord.io, with a focus on functions related to the Yu-Gi-Oh! card game and a simulator of it, YGOPro Percy. The name comes from an intellectual character in the related anime. All commands are case-insensitive.
You can install a copy of Bastion yourself, more information on how below, but if you'd rather just use my copy, here's the invite link. For support and feedback, my Discord server is here, and you can support me on Patreon here.
Bastion's primary purpose is a database of card information. Basic knowledge about relevant terms will be assumed in this section and the next. Note that Bastion's prefix is customisable - more information on that in the configuration section - this section assumes the default prefix of ".".
A few general notes on card searching: My copy of Bastion references a card database with official cards, including recently revealed unreleased cards, anime cards from YGOPro Percy, and custom cards from the G2 YGO Custom Server. Bastion will search for the nearest guess if you don't type an exact name. Bastion has a system for hardcoded shortcuts - if you type a common abbreviation for a card name, it will try to convert it to the full name. Price data comes from the http://yugiohprices.com API. "Status" is a term I use for what YGOPro developers call "OT" - a designation that reflects whether a card is legal in the OCG, TCG, both, or other options for unofficial cards like Anime, Illegal and Custom.
Usage: @Bastion#3599
Mentioning Bastion will provide a link to this readme.
Usage: {card name|ID[,lang,lang]}
This command searches for a card by the name or YGOPro ID specified in the brackets and returns the card's name, all of its IDs in YGOPro, any archetypes its a member of, its status, its lowest, average, and highest prices if available, its types, its attribute if it's a monster, any stats, and its card text. If you enter two valid language codes (e.g. "en", "ja", "es"), Bastion will search by the first language and output in the second.
As an example, {dark magician}
returns the following output:
Usage: <card name|ID[,lang,lang]>
This command works the same way as the above command, but also displays an image of the card's artwork.
As an example, <stardust dragon>
returns the following output:
Usage: .id [card name|ID]
, .notext [card name|ID]
, .effect [card name|ID]
Using these commands, you can search like the above two, but it will return only the card IDs, just the stats etc. without card text, or only card text respectively. None of these options display the image.
Usage: .randcard [opts]
The .randcard
command will select a random card and display its information as if you searched it. The command accepts options that allow you to specify the status, level, type, or attribute of the card, as well as optionally display an image by including "image" or display cards in different languages by including the language code for that language.
As an example, .randcard tcg/ocg 4 image
returns the following output:
Usage: .script [name|id]
The .script
command searches for a card by name or YGOPro ID and returns a link to its script for YGOPro, as well as embedding it if short enough.
As an example, .script macro cosmos
returns the following output:
Usage: .matches [name]|[args]
The .matches
command simulates a search for cards by name and returns the 10 closest matches for your search term. If you specify arguments after a |
, (the same kinds as .randcard
), it will only show matches that fit that critera. This command ignores cards with the same name, for example alternate artworks, however it will allow Anime versions of existing cards, etc., unless you specify a status as an arg.
As an example, .matches junk warrior
returns the following output:
Usage: .set [name|setcode]
The .set
command searches for an archetype, or "setcode" by either its name or its hexadecimal value in YGOPro (0xba
for example) and returns both.
As an example, .set 0xba
returns the following output:
Usage: .deck [language]
and upload file
The .deck
command reads the contents of a YGOPro .ydk
file uploaded with the message, and sends a direct message to the user listing the contents of the deck in the specified language (English by default).
Usage: .strings [card name|ID]
The .strings
command searches for a card by name or YGOPro ID, and returns the database strings for that card - i.e., the customs messages assigned to it that a script can call on for effect descriptions or dialog boxes.
Usage: .skill [skill name]
The .skill
command searches for a Skill, from Yu-Gi-Oh! Duel Links, and returns its name, description, and a list of which characters can obtain the Skill and how.
Usage: .f [function name]
, .c [constant name]
, .param [parameter name]
Bastion can return information about YGOPro's Lua API with the above commands. All results that match your query will be displayed, in pages of 9. Type or edit .p[page number]
to change pages. Entries will be displayed with a corresponding number - type or edit .d[number]
to see a more detailed description of that entry, if available.
Usage: .skill [name]
The .skill
command searches for a character skill from Yu-Gi-Oh! Duel Links by name, and returns its name, the description of what it does, and which characters can obtain it and how.
Usage: .trivia [options]
For fun, Bastion can play a game where it will provide the art of a card, and players have 30 seconds to give its name, with a hint at 10 seconds. The command accepts any number of the following options:
Status: By default, the game will display TCG/OCG cards, but you can specify OCG
, TCG
, Anime
(which will include Video Game and Illegal cards), and Custom
.
Rounds: If you include a number as an option, the game will run that many times and track the total scores of each player over the course of the game.
Hard Mode: If you include hard
as an option, Bastion will display only a quarter of the card image, for added difficulty.
Language: If you include a language code as an option, Bastion will use that language for the card name.
You can end the game prematurely by typing ".tq", or pass a round by typing ".tskip".
Usage: .tlock
The .tlock
command tells Bastion that on the server you use the command, he should only allow .trivia
in the channels in which you've used the command. Only users with the "Manage Messages" permission can use the command. You can use the command in multiple channels to allow trivia in multiple channels. Using the command in a channel already registered will remove it from the list. If there are no channels in the list, trivia will be allowed anywhere.
If you so choose, you can run a copy of Bastion yourself! This section will assume some basic familiarity with NodeJS and the command line.
All of Bastion's dependencies are properly documented in the package.json, so you can just download that, put it in a folder, and run npm install
. If npm install
fails, you might need to install Git before trying again (having GitHub Desktop isn't enough). To run the bot, the script expects some certain files - a configuration file, a banlist file, a shortcuts file, a setcodes file, an emotes file, a skills file, any number of SQLite databases containing card data, in the format YGOPro uses, and optionally 3 files with information about YGOPro's API with a customizable name. Once it's setup, you can use node bastion.js
to run it once, or on Windows, use autorun.bat
to have it automatically restart upon a crash.
By default, the configuration file is called config.json
, and is expected to be found in a subfolder of the local directory called config
, i.e. config/config.json
. The script expects config.json
to contain a JSON object with the following properties:
{
"token": "",
"prefix": ".",
"longStr": "...\n__Type \".long\" to be PMed the rest!__",
"maxSearches": 3,
"imageUrl": "",
"imageUrlAnime": "",
"imageUrlCustom": "",
"imageSize": 100,
"imageExt": "png",
"scriptUrl": "",
"scriptUrlAnime": "",
"scriptUrlCustom": "",
"dbs": {
"en": [ "cards.cdb" ]
},
"dbMemory": 33554432,
"triviaTimeLimit": 30000,
"triviaHintTime": 10000,
"triviaMaxRounds": 20,
"triviaLocks": {},
"botOwner": "169299769695535105",
"scriptFunctions": "functions.json",
"scriptConstants": "constants.json",
"scriptParams": "parameters.json",
"skillDB": "skills.json",
"emoteMode": 0,
"emotesDB": null,
"helpMessage": "I am a Yu-Gi-Oh! card bot made by AlphaKretin#7990.\nPrice data is from the <https://yugiohprices.com> API.\nYou can find my help file and source here: <https://github.com/AlphaKretin/bastion-bot/>\nYou can support my development on Patreon here: <https://www.patreon.com/alphakretinbots>\nType `.commands` to be DMed a short summary of my commands without going to an external website.",
"messageMode": 0,
"embedColor": 1,
"embedColorDB": null
}
token
is the Discord User token that the discord.io module will use to log in to Discord. You can obtain a bot token through the Discord Developers website. This field is required.
prefix
is the text that Bastion will look for at the start of messages to indicate that it's a bot command. For example, if prefix
is "b$", .randcard
becomes b$randcard
. This field is optional - if it is missing, Bastion will default to what you see above.
longStr
is the message Bastion will append to an output that's split up due to violating Discord's character limit, instructing the user how to see the rest. This field is optional - if it is missing, Bastion will default to what you see above.
maxSearches
is the number of different cards Bastion will allow a user to search at once - if a message contains more queries, Bastion won't search anything, instead returning an error message. This field is optional - if it is missing, Bastion will default to what you see above.
imageUrl
is a link to a source for card images - either official ones, or all of them. Bastion will append the ID of the card, then ".", then imageExt
. This field is optional - if it is missing, functions that require images will be disabled and the following fields will be ignored: imageUrlAnime
, imageUrlCustom
, imageSize
, triviaTimeLimit
, triviaHintTime
, triviaMaxRounds
and triviaLocks
.
imageUrlAnime
is a link to a source for anime card images. Bastion will append the ID of the card, hen ".", then imageExt
. This field is optional - if it is missing, Bastion will default to imageUrl
.
imageUrlCustom
is a link to a source for custom card images. Bastion will append the ID of the card, hen ".", then imageExt
. This field is optional - if it is missing, Bastion will default to imageUrl
.
imageExt
is the file type Bastion will expect your image source to contain, as a file extension starting with the .
. This field is optional - if it is missing, Bastion will default to what you see above.
scriptUrl
is a link to a source for card scripts - either official ones, or all of them. Bastion will append the ID of the card, then ".lua". This field is optional - if it is missing, functions that require scripts will be disabled and the following fields will be ignored: scriptUrlAnime
, and scriptUrlCustom
.
scriptUrlAnime
is a link to a source for anime card scripts. Bastion will append the ID of the card, then ".lua". This field is optional - if it is missing, Bastion will default to scriptUrl
.
scriptUrlCustom
is a link to a source for custom card scripts. Bastion will append the ID of the card, then ".lua". This field is optional - if it is missing, Bastion will default to scriptUrl
.
scriptUrlBackup
is a link to a source for backup card scripts - if Bastion doesn't find a script at the first source specified, he'll try again here. Bastion will append the ID of the card, then ".lua". This field is optional - if it is missing, Bastion will not try to find backup scripts.
dbs
is an object of arrays of filenames for card databases Bastion will read, to be found in a folder called dbs
. The keys of the object are language codes. If two DBs have an entry with the same ID, for example because of "fix" DBs, the latest occurence in the array will be the final version of the entry that overwrites the others. This field is optional - if it is missing, Bastion will default to what you see above.
dbMemory
is the size allocated in memory for Bastion to load card database, in bytes. If you get the error "Cannot adjust memory arrays" in the middle of loading databases, you need to increase this. This field is optional - if it is missing, Bastion will default to what you see above.
triviaTimeLimit
is the time a player has to guess the answer in the trivia game, in milliseconds. This field is optional - if it is missing, Bastion will default to what you see above.
triviaHintTime
is the time at which Bastion will provide a hint for the player in the trivia game, in milliseconds. If it is greater than triviaTimeLimit
, the hint will never display, which may be behaviour you desire. This field is optional - if it is missing, Bastion will default to what you see above.
triviaMaxRounds
is the maximum number of rounds a player can set the trivia game to run for, to prevent someone from forcing it to run for an arbitrarily long time. This field is optional - if it is missing, Bastion will default to what you see above.
triviaLocks
is an object with server IDs as keys and an array of channel IDs as the properties. If a server is in the object, the trivia game can only be player in the channels listed in the array. This field is optional - if it is missing, Bastion will default to what you see above, and you can configure it through Bastion even if you don't run the copy using the .tlock
command.
botOwner
is the Discord user ID of the user you consider to own the bot, likely yourself, for the sake of administrative functions. This field is optional - if it is missing, such functions will be disabled.
scriptFunctions
is the name of the JSON file Bastion will load containing information about the YGOPro API's functions - details on this file below. This field is optional - if it is missing, searching for functions will be disabled.
scriptConstants
is the name of the JSON file Bastion will load containing information about the YGOPro API's constants - details on this file below. This field is optional - if it is missing, searching for constants will be disabled.
scriptParams
is the name of the JSON file Bastion will load containing information about the YGOPro API's parameters - details on this file below. This field is optional - if it is missing, searching for parameters will be disabled.
skillDB
is the name of the JSON file Bastion will load containing information about skills in Duel Links - details on this file below. This field is optional - if it is missing, searching for skills will be disabled.
emoteMode
determines if and how emotes will be used when displaying card data. If it is set to 0, emotes will not be used and Types, Attributes etc. will be displayed with text. If it is set to 1, emotes will be used exclusively, representing such properties with only icons. If it is set to 2, it will display both text and icons. This field is optional - if it is missing, it will default to what you see above.
emotesDB
is the name of the JSON file Bastion will load containing the emotes it will use for its card searches and/or reacting to trivia. This won't be loaded if emoteMode is set to 0. This field is optional - is can be ignored depending on emoteMode
's setting, and if it is expected but missing, displaying emotes will be disabled.
helpMessage
is the message the bot will respond with when mentioned or the .help command is used, ideally providing a link to this readme and/or explaning the commands.
messageMode
determines how Bastion will send Messages. If it is set to 0, it will send messages in regular text format. If it is set to 1, it will send messages enclosed in quotes. If it is set to 2, it will send embedded messages. If it is set to 3, it will send messages enclosed in quotes which are also embedded. This field is optional - if it is missing, it will default to what you see above.
embedColor
is the default color of the bar of your embedded messages. This field is optional - is can be ignored depending on messageMode
's setting, and if it is expected but missing, the default color will be used. This is a decimal value converted from a hex color value.
embedColorDB
is the name of the JSON file Bastion will load containing the color codes of your embedded messages. Currently, it only supports different colors depending on the card type of a searched card. This field is optional - if it is missing, all embedded messages will have the same color.
By default, the shortcut file is called shortcuts.json
, and is expected to be found in a subfolder of the local directory called config
, i.e. config/shortcuts.json
. The script expects shortcut.json
to contain a JSON array of arrays, with contents like the following:
[
[
"A0",
"AbZ.",
"AbZ",
"Elemental HERO Absolute Zero"
],
[
"AGGD",
"Ancient Gear Gadjiltron Dragon"
]
]
The final entry in each array should be the full name of a card, for which all other entries are a shortened form of. Bastion splits queries up by spaces when checking for shortcuts, so shortcuts with a space will never be matched.
By default, the setcode file is called setcodes.json
, and is expected to be found in a subfolder of the local directory called config
, i.e. config/setcodes.json
. The script expects setcodes.json
to contain a object, with hexadecimal setcodes as the keys and the names of the corresponding archetypes as the values, like so:
{
"0x1": "Ally of Justice",
"0x2": "Genex"
}
This file can be generated with the setcodes2json.js
file. Simply run it as a node app in the same folder as a YGOPro strings.conf
file, and it will output a setcodes.json
that should be properly formatted.
By default, the emote file is called emotes.json
, and is expected to be found in a subfolder of the local directory called config
, i.e. config/emotes.json
. The script expects emotes.json
to contain a object, with string values as both the keys and the values, with minimal exceptions.
{
"LIGHT": "",
"Aqua": "",
"thumbsup": "",
"thumbsdown": null,
"Equip": ""
}
Keys are what the emotes are used to represent, and the values are the emote to use - either a literal emoji, or the Discord code for a custom emote in a server the bot will be in. You can get this by typing a backslash before the emote in Discord.
Besides all monster types and attributes, and Spell/Trap subtypes, the following emotes are expected:
???
, used when Bastion fails to load a type or attribute.
thumbsup
, a positive reaction used when a correct answer is given in Trivia.
thumbsdown
, a negate reaction used when a wrong answer is given in Trivia. This can be left null to reduce spam/clutter.
NormalST
, representing a Normal Spell/Trap.
Level
, a Level star.
Rank
, a Rank star.
NLevel
, a Negative Level star, for anime Dark Synchros.
Link
, a symbol representing Link Rating.
L.Scale
, the left Pendulum Scale.
R.Scale
, the right Pendulum Scale.
If using a custom emote for thumbsup
or thumbsdown
, leave out the >
on the end.
By default, the banlist file is called lflist.json
, and is expected to be found in a subfolder of the local directory called config
, i.e. config/lflist.json
. The script expects lflist.json
to contain a object, with statuses (e.g. "TCG", "OCG") as the keys, and the values are further objects, with card IDs as keys and how many copies you are allowed in your deck as the value. If a card is not in the list, it is assumed to be unlimited.
{
"TCG": {
"581014": 0,
"2295440": 1
},
"OCG": {
"423585": 2,
"1561110": 1
}
}
This file can be generated with the lflist2json.js
file. Simply run it as a node app in the same folder as a YGOPro lflist.conf
file, and it will output an lflist.json
that should be properly formatted. Note that it assumes the headings of each seperate banlist are in the format of "[date] [name]", i.e. it takes the word after the first space. If your lflist.conf
is formatted differently, you can just go into the JSON and change the name of the key.
By default, the skills file is called skills.json
, and is expected to be found in a subfolder of the local directory called dbs
, i.e. dbs/skills.json
. The script expects skills.json
to contain an array of objects, the format of which is described below.
[
{
"name": "Aroma Strategy",
"desc": "You can look at the card at the very top of your Deck at any time.",
"chars": "Mai Valentine (Level 4)"
},
{
"name": "Baggy Sleeves",
"desc": "If one of your monsters of Level 5 or higher is destroyed in battle, in your next Draw Phase a normal draw gives you 2 cards.",
"chars": "Bandit Keith (Drop)"
}
]
name
is the name of the skill, desc
is the skill's description, and chars
is a list of characters that can obtain the skill, and how they do.
Bastion reads card databases from SQLite databases formatted the same way as those YGOPro uses. Because of this similarity, you can copy databases from YGOPro or edit them with programs like DataEditorX, so it should not be necessary to document the format here. If you do want to learn more about it, you can read MichaelLawrenceDee's tutorial on custom card creation for YGOPro, which covers making Card Databases manually.
A small note - Bastion detects if it needs to display monster stats for a Trap Card by checking for the TRAP_MONSTER type, 0x100, which not all simulators include in their databases - you may need to add this yourself.
The schema for a card database is as follows:
CREATE TABLE IF NOT EXISTS "datas" (
`id` integer,
`ot` integer,
`alias` INTEGER,
`setcode` integer,
`type` integer,
`atk` integer,
`def` integer,
`level` integer,
`race` integer,
`attribute` integer,
`category` integer,
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS "texts" (
`id` integer,
`name` TEXT,
`desc` TEXT,
`str1` TEXT,
`str2` TEXT,
`str3` TEXT,
`str4` TEXT,
`str5` TEXT,
`str6` TEXT,
`str7` TEXT,
`str8` TEXT,
`str9` TEXT,
`str10` TEXT,
`str11` TEXT,
`str12` TEXT,
`str13` TEXT,
`str14` TEXT,
`str15` TEXT,
`str16` TEXT,
PRIMARY KEY(id)
);
Bastion expects 3 files in the dbs
folder containing JSON arrays of objects detailing the functions, constants, and parameters in YGOPro's API. Examples of their format below.
[
{
"sig": "int,int",
"name": "Card.GetOriginalCodeRule(Card c)",
"desc": "Gets the original code of a Card (Card c) (used for wording \"original name\")"
},
{
"sig": "bool",
"name": "Card.IsFusionCode(Card c, int code)",
"desc": "Checks if a Card (Card c) has a specific code (int code) (for Fusion Summons)"
}
]
[
{
"val": "0x01",
"name": "LOCATION_DECK",
"desc": ""
},
{
"val": "0x02",
"name": "LOCATION_HAND",
"desc": ""
}
]
[
{
"type": "string",
"name": "any msg",
"desc": "A string in parantheses (can also include variables: 'Debug.Message(\"string1\"..var1..\"string2\")')"
},
{
"type": "bool",
"name": "cancel",
"desc": "Determines if it's cancelled or not"
}
]
- Add pack opening simulation -- Feature simon has, but could be improved on
- Add OCG/Japanese prices if searching japanese language --Bonus
- Add comparison between different versions of scripts between repos --Bonus
- Add ruling page lookup --Bonus
- Auto CDB update --Bonus
- Grab DBs (and whatever else) from online or local