1
Fork 0
mirror of https://github.com/wlinator/luminara.git synced 2024-10-02 18:23:12 +00:00

Merge pull request #38 from wlinator/yaml-switch

yaml settings & customizability update
This commit is contained in:
wlinator 2024-08-27 07:03:31 -04:00 committed by GitHub
commit 866cbe6f0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 262 additions and 284 deletions

View file

@ -6,7 +6,6 @@ from discord.ext import commands
from loguru import logger
import Client
import config.parser
import services.config_service
import services.help_service
from db.database import run_migrations
@ -91,13 +90,6 @@ if __name__ == "__main__":
# Run database migrations
run_migrations()
# cache all JSON
[
config.parser.JsonCache.read_json(file[:-5])
for file in os.listdir("config/JSON")
if file.endswith(".json")
]
# load command and listener cogs
load_modules()

View file

@ -1,30 +0,0 @@
{
"logo": {
"opaque": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_logo.png",
"transparent": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_logo_transparent.png?_=1"
},
"icons": {
"boost": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_boost.png",
"check": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_check.png?_=1",
"cross": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_cross.png?_=2",
"exclaim": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_exclaim.png?_=3",
"hammer": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_hammer.png?_=1",
"money_bag": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_money_bag.png?_=1",
"money_coins": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_money_coins.png?_=1",
"question": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_question.png?_=2",
"streak": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_streak.png?_=2",
"streak_bronze": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_streak_bronze.png?_=1",
"streak_gold": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_streak_gold.png?_=1",
"streak_silver": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_streak_silver.png?_=1",
"warning": "https://git.wlinator.org/Luminara/Art/raw/branch/main/lumi_warning.png?_=1"
},
"juicybblue": {
"flowers": "https://i.imgur.com/79XfsbS.png",
"teapot": "https://i.imgur.com/wFsgSnr.png",
"muffin": "https://i.imgur.com/hSauh7K.png"
},
"other": {
"cloud": "https://i.imgur.com/rc68c43.png",
"trophy": "https://i.imgur.com/dvIIr2G.png"
}
}

View file

@ -1,87 +0,0 @@
{
"emotes_guild_id": 1038051105642401812,
"repository_url": "https://git.wlinator.org/Luminara/Lumi",
"guild_specific": {
"guild_id": 719227135151046699,
"intro_channel_id": 973619250507972618,
"question_mapping": {
"(Nick)name": "Let's start with your nickname. How would you like to be identified in the server?",
"Age": "How old are you?",
"Region": "Where do you live?",
"Languages": "Which languages do you speak?",
"Pronouns": "What are your preferred pronouns?",
"Sexuality": "What's your sexuality?",
"Relationship status": "What's your current relationship status?",
"Likes & interests": "Likes & interests",
"Dislikes": "Dislikes",
"EXTRAS": "EXTRAS: job status, zodiac sign, hobbies, etc. Tell us about yourself!"
}
},
"daily_reward": 500,
"blackjack": {
"emotes": {
"hit": "<:hit:1119262723285467156>",
"stand": "<:stand:1118923298298929154>"
},
"reward_multiplier": 1.4,
"deck_suits": [
"♠",
"♡",
"♢",
"♣"
],
"deck_ranks": [
"A",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"J",
"Q",
"K"
]
},
"slots": {
"emotes": {
"slots_animated_id": 1119262805309259776,
"slots_0_id": 1119262803816095825,
"slots_1_id": 1119262801261760592,
"slots_2_id": 1119262800049614939,
"slots_3_id": 1119262796497039510,
"slots_4_id": 1119262794676715681,
"slots_5_id": 1119262792386621555,
"slots_6_id": 1119262791061229669,
"S_Wide": 1119286730302955651,
"L_Wide": 1119286763802857533,
"O_Wide": 1119286787169329203,
"T_Wide": 1119286804634406942,
"CBorderBLeft": 1119286973572595712,
"CBorderBRight": 1119286918459445408,
"CBorderTLeft": 1119287006464331806,
"CBorderTRight": 1119286865284051035,
"HBorderB": 1119286936155213835,
"HBorderT": 1119287027662344322,
"VBorder": 1119286889854279680,
"WSmall": 1119288536282173490,
"ISmall": 1119288552673517608,
"NSmall": 1119288579382857830,
"LCentered": 1119287296127156325,
"OCentered": 1119287563245584394,
"SCentered": 1119287327588634647,
"ECentered": 1119287343833165945,
"Blank": 1119287267001905283,
"lost": 1119288454212243607
},
"reward_multipliers": {
"pair": 1.5,
"three_of_a_kind": 4,
"three_diamonds": 6,
"jackpot": 15
}
}
}

View file

@ -1,14 +0,0 @@
import json
class JsonCache:
_cache = {}
@staticmethod
def read_json(path):
"""Read and cache the JSON data if not already cached."""
if path not in JsonCache._cache:
with open(f"config/JSON/{path}.json") as file:
JsonCache._cache[path] = json.load(file)
return JsonCache._cache[path]

View file

@ -1,102 +1,120 @@
import os
from typing import Optional, Set
from typing import Optional, Set, List, Dict
import yaml
import json
from functools import lru_cache
from config.parser import JsonCache
class _parser:
"""Internal parser class. Not intended for direct use outside this module."""
@lru_cache(maxsize=1024)
def read_yaml(self, path):
return self._read_file(f"settings/{path}.yaml", yaml.safe_load)
@lru_cache(maxsize=1024)
def read_json(self, path):
return self._read_file(f"settings/{path}.json", json.load)
def _read_file(self, file_path, load_func):
with open(file_path) as file:
return load_func(file)
class Constants:
# JSON raw
ART = JsonCache.read_json("art")
RESOURCES = JsonCache.read_json("resources")
LEVEL_MESSAGES = JsonCache.read_json("levels")
_p = _parser()
_settings = _p.read_yaml("settings")
# metadata
TITLE = "Luminara"
AUTHOR = "wlinator"
LICENSE = "GNU General Public License v3.0"
VERSION = "2.8.12" # "Refactor Blackjack" update
# bot credentials
TOKEN: Optional[str] = os.environ.get("TOKEN", None)
INSTANCE: Optional[str] = os.environ.get("INSTANCE", None)
# bot credentials (.env file)
TOKEN: Optional[str] = os.environ.get("TOKEN")
INSTANCE: Optional[str] = os.environ.get("INSTANCE")
XP_GAIN_PER_MESSAGE: int = int(os.environ.get("XP_GAIN_PER_MESSAGE", 1))
XP_GAIN_COOLDOWN: int = int(os.environ.get("XP_GAIN_COOLDOWN", 8))
DBX_TOKEN: Optional[str] = os.environ.get("DBX_OAUTH2_REFRESH_TOKEN")
DBX_APP_KEY: Optional[str] = os.environ.get("DBX_APP_KEY")
DBX_APP_SECRET: Optional[str] = os.environ.get("DBX_APP_SECRET")
MARIADB_USER: Optional[str] = os.environ.get("MARIADB_USER")
MARIADB_PASSWORD: Optional[str] = os.environ.get("MARIADB_PASSWORD")
MARIADB_ROOT_PASSWORD: Optional[str] = os.environ.get("MARIADB_ROOT_PASSWORD")
MARIADB_DATABASE: Optional[str] = os.environ.get("MARIADB_DATABASE")
OWNER_IDS: Optional[Set[int]] = (
{int(id.strip()) for id in os.environ.get("OWNER_IDS", "").split(",") if id}
if os.environ.get("OWNER_IDS")
if "OWNER_IDS" in os.environ
else None
)
XP_GAIN_PER_MESSAGE: int = int(os.environ.get("XP_GAIN_PER_MESSAGE", 1))
XP_GAIN_COOLDOWN: int = int(os.environ.get("XP_GAIN_COOLDOWN", 8))
# metadata
TITLE: str = _settings["info"]["title"]
AUTHOR: str = _settings["info"]["author"]
LICENSE: str = _settings["info"]["license"]
VERSION: str = _settings["info"]["version"]
REPO_URL: str = _settings["info"]["repository_url"]
DBX_TOKEN: Optional[str] = os.environ.get("DBX_OAUTH2_REFRESH_TOKEN", None)
DBX_APP_KEY: Optional[str] = os.environ.get("DBX_APP_KEY", None)
DBX_APP_SECRET: Optional[str] = os.environ.get("DBX_APP_SECRET", None)
MARIADB_USER: Optional[str] = os.environ.get("MARIADB_USER", None)
MARIADB_PASSWORD: Optional[str] = os.environ.get("MARIADB_PASSWORD", None)
MARIADB_ROOT_PASSWORD: Optional[str] = os.environ.get("MARIADB_ROOT_PASSWORD", None)
MARIADB_DATABASE: Optional[str] = os.environ.get("MARIADB_DATABASE", None)
# config
ALLOWED_IMAGE_EXTENSIONS = (".jpg", ".png")
# emotes
EMOTES_GUILD_ID = 1038051105642401812
# color scheme
COLOR_DEFAULT = 0xFF8C00
COLOR_WARNING = 0xFF7600
COLOR_ERROR = 0xFF4500
# strings
STRINGS = JsonCache.read_json("strings")
# repository
REPO_URL = "https://git.wlinator.org/Luminara/Lumi"
INVITE_LINK = "https://discord.com/oauth2/authorize?client_id=1038050427272429588&permissions=8&scope=bot"
# KRC
KRC_GUILD_ID: int = 719227135151046699
KRC_INTRO_CHANNEL_ID: int = 973619250507972618
KRC_QUESTION_MAPPING: dict[str, str] = RESOURCES["guild_specific"][
"question_mapping"
# images
ALLOWED_IMAGE_EXTENSIONS: List[str] = _settings["images"][
"allowed_image_extensions"
]
BIRTHDAY_GIF_URL: str = _settings["images"]["birthday_gif_url"]
# logo
LUMI_LOGO_TRANSPARENT = ART["logo"]["transparent"]
LUMI_LOGO_OPAQUE = ART["logo"]["opaque"]
# icons art
BOOST_ICON = ART["icons"]["boost"]
CHECK_ICON = ART["icons"]["check"]
CROSS_ICON = ART["icons"]["cross"]
EXCLAIM_ICON = ART["icons"]["exclaim"]
HAMMER_ICON = ART["icons"]["hammer"]
MONEY_BAG_ICON = ART["icons"]["money_bag"]
MONEY_COINS_ICON = ART["icons"]["money_coins"]
QUESTION_ICON = ART["icons"]["question"]
STREAK_ICON = ART["icons"]["streak"]
WARNING_ICON = ART["icons"]["warning"]
# art by JuicyBblue
FLOWERS_ART = ART["juicybblue"]["flowers"]
TEAPOT_ART = ART["juicybblue"]["teapot"]
MUFFIN_ART = ART["juicybblue"]["muffin"]
# other art
CLOUD_ART = ART["other"]["cloud"]
TROPHY_ART = ART["other"]["trophy"]
# birthdays
BIRTHDAY_MESSAGES = JsonCache.read_json("birthday")["birthday_messages"]
BIRTHDAY_MONTHS = JsonCache.read_json("birthday")["months"]
BIRTHDAY_GIF_URL = "https://media1.tenor.com/m/NXvU9jbBUGMAAAAC/fireworks.gif"
# colors
COLOR_DEFAULT: int = _settings["colors"]["color_default"]
COLOR_WARNING: int = _settings["colors"]["color_warning"]
COLOR_ERROR: int = _settings["colors"]["color_error"]
# economy
DAILY_REWARD = RESOURCES["daily_reward"]
SLOTS = RESOURCES["slots"]
BLACKJACK = RESOURCES["blackjack"]
DAILY_REWARD: int = _settings["economy"]["daily_reward"]
BLACKJACK_MULTIPLIER: float = _settings["economy"]["blackjack_multiplier"]
BLACKJACK_HIT_EMOJI: str = _settings["economy"]["blackjack_hit_emoji"]
BLACKJACK_STAND_EMOJI: str = _settings["economy"]["blackjack_stand_emoji"]
SLOTS_MULTIPLIERS: Dict[str, float] = _settings["economy"]["slots_multipliers"]
# art from git repository
_fetch_url: str = _settings["art"]["fetch_url"]
LUMI_LOGO_OPAQUE: str = _fetch_url + _settings["art"]["logo"]["opaque"]
LUMI_LOGO_TRANSPARENT: str = _fetch_url + _settings["art"]["logo"]["transparent"]
BOOST_ICON: str = _fetch_url + _settings["art"]["icons"]["boost"]
CHECK_ICON: str = _fetch_url + _settings["art"]["icons"]["check"]
CROSS_ICON: str = _fetch_url + _settings["art"]["icons"]["cross"]
EXCLAIM_ICON: str = _fetch_url + _settings["art"]["icons"]["exclaim"]
HAMMER_ICON: str = _fetch_url + _settings["art"]["icons"]["hammer"]
MONEY_BAG_ICON: str = _fetch_url + _settings["art"]["icons"]["money_bag"]
MONEY_COINS_ICON: str = _fetch_url + _settings["art"]["icons"]["money_coins"]
QUESTION_ICON: str = _fetch_url + _settings["art"]["icons"]["question"]
STREAK_ICON: str = _fetch_url + _settings["art"]["icons"]["streak"]
STREAK_BRONZE_ICON: str = _fetch_url + _settings["art"]["icons"]["streak_bronze"]
STREAK_GOLD_ICON: str = _fetch_url + _settings["art"]["icons"]["streak_gold"]
STREAK_SILVER_ICON: str = _fetch_url + _settings["art"]["icons"]["streak_silver"]
WARNING_ICON: str = _fetch_url + _settings["art"]["icons"]["warning"]
# art from imgur
FLOWERS_ART: str = _settings["art"]["juicybblue"]["flowers"]
TEAPOT_ART: str = _settings["art"]["juicybblue"]["teapot"]
MUFFIN_ART: str = _settings["art"]["juicybblue"]["muffin"]
CLOUD_ART: str = _settings["art"]["other"]["cloud"]
TROPHY_ART: str = _settings["art"]["other"]["trophy"]
# emotes
EMOTES_SERVER_ID: int = _settings["emotes"]["guild_id"]
EMOTE_IDS: Dict[str, int] = _settings["emotes"]["emote_ids"]
# introductions (currently only usable in ONE guild)
INTRODUCTIONS_GUILD_ID: int = _settings["introductions"]["intro_guild_id"]
INTRODUCTIONS_CHANNEL_ID: int = _settings["introductions"]["intro_channel_id"]
INTRODUCTIONS_QUESTION_MAPPING: Dict[str, str] = _settings["introductions"][
"intro_question_mapping"
]
# Response strings
# TODO: Implement switching between languages
STRINGS = _p.read_json("responses/strings.en-US")
LEVEL_MESSAGES = _p.read_json("responses/levels.en-US")
# birthday messages
_bday = _p.read_json("responses/bdays.en-US")
BIRTHDAY_MESSAGES = _bday["birthday_messages"]
BIRTHDAY_MONTHS = _bday["months"]
CONST = Constants()

View file

@ -2,49 +2,6 @@ import discord
from discord.ui import View
class BlackJackButtons(View):
def __init__(self, ctx):
super().__init__(timeout=180)
self.ctx = ctx
self.clickedHit = False
self.clickedStand = False
self.clickedDoubleDown = False
async def on_timeout(self):
for child in self.children:
child.disabled = True
await self.message.edit(view=None)
@discord.ui.button(
label="hit",
style=discord.ButtonStyle.gray,
emoji="<:hit:1119262723285467156> ",
)
async def hit_button_callback(self, button, interaction):
self.clickedHit = True
await interaction.response.defer()
self.stop()
@discord.ui.button(
label="stand",
style=discord.ButtonStyle.gray,
emoji="<:stand:1118923298298929154>",
)
async def stand_button_callback(self, button, interaction):
self.clickedStand = True
await interaction.response.defer()
self.stop()
async def interaction_check(self, interaction) -> bool:
if interaction.user == self.ctx.author:
return True
await interaction.response.send_message(
"You can't use these buttons, they're someone else's!",
ephemeral=True,
)
return False
class ExchangeConfirmation(View):
def __init__(self, ctx):
super().__init__(timeout=180)

View file

@ -1,11 +1,12 @@
import random
from typing import List, Tuple
from loguru import logger
import discord
from discord.ui import View
import pytz
from discord.ext import commands
from lib import interaction
from lib.constants import CONST
from lib.exceptions.LumiExceptions import LumiException
from services.currency_service import Currency
@ -34,6 +35,7 @@ async def cmd(ctx: commands.Context, bet: int) -> None:
try:
await play_blackjack(ctx, currency, bet)
except Exception as e:
logger.exception(f"Error in blackjack game: {e}")
raise LumiException(CONST.STRINGS["error_blackjack_game_error"]) from e
finally:
del ACTIVE_BLACKJACK_GAMES[ctx.author.id]
@ -42,11 +44,11 @@ async def cmd(ctx: commands.Context, bet: int) -> None:
async def play_blackjack(ctx: commands.Context, currency: Currency, bet: int) -> None:
deck = get_new_deck()
player_hand, dealer_hand = initial_deal(deck)
multiplier = float(CONST.BLACKJACK["reward_multiplier"])
multiplier = CONST.BLACKJACK_MULTIPLIER
player_value = calculate_hand_value(player_hand)
status = 5 if player_value == 21 else 0
view = interaction.BlackJackButtons(ctx)
view = BlackJackButtons(ctx)
playing_embed = False
while status == 0:
@ -85,7 +87,7 @@ async def play_blackjack(ctx: commands.Context, currency: Currency, bet: int) ->
currency.push()
raise LumiException(CONST.STRINGS["error_out_of_time_economy"])
view = interaction.BlackJackButtons(ctx)
view = BlackJackButtons(ctx)
await handle_game_end(
ctx,
@ -255,8 +257,8 @@ def create_end_game_embed(
def get_new_deck() -> List[Card]:
deck = [
rank + suit
for suit in CONST.BLACKJACK["deck_suits"]
for rank in CONST.BLACKJACK["deck_ranks"]
for suit in ["", "", "", ""]
for rank in ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
]
random.shuffle(deck)
return deck
@ -277,3 +279,46 @@ def calculate_hand_value(hand: Hand) -> int:
value -= 10
aces -= 1
return value
class BlackJackButtons(View):
def __init__(self, ctx):
super().__init__(timeout=180)
self.ctx = ctx
self.clickedHit = False
self.clickedStand = False
self.clickedDoubleDown = False
async def on_timeout(self):
for child in self.children:
child.disabled = True
await self.message.edit(view=None)
@discord.ui.button(
label=CONST.STRINGS["blackjack_hit"],
style=discord.ButtonStyle.gray,
emoji=CONST.BLACKJACK_HIT_EMOJI,
)
async def hit_button_callback(self, button, interaction):
self.clickedHit = True
await interaction.response.defer()
self.stop()
@discord.ui.button(
label=CONST.STRINGS["blackjack_stand"],
style=discord.ButtonStyle.gray,
emoji=CONST.BLACKJACK_STAND_EMOJI,
)
async def stand_button_callback(self, button, interaction):
self.clickedStand = True
await interaction.response.defer()
self.stop()
async def interaction_check(self, interaction) -> bool:
if interaction.user == self.ctx.author:
return True
await interaction.response.send_message(
CONST.STRINGS["error_cant_use_buttons"],
ephemeral=True,
)
return False

View file

@ -15,23 +15,14 @@ est = pytz.timezone("US/Eastern")
async def cmd(self, ctx, bet):
# Currency handler
ctx_currency = Currency(ctx.author.id)
# check if the user has enough cash
player_balance = ctx_currency.balance
if bet > player_balance:
raise commands.BadArgument("you don't have enough cash.")
elif bet <= 0:
raise commands.BadArgument("the bet you entered is invalid.")
# # check if the bet exceeds the bet limit
# bet_limit = int(resources["bet_limit"])
# if abs(bet) > bet_limit:
# message = strings["bet_limit"].format(ctx.author.name, Currency.format_human(bet_limit))
# return await ctx.respond(content=message)
# calculate the results before the command is shown
results = [random.randint(0, 6) for _ in range(3)]
calculated_results = calculate_slots_results(bet, results)
@ -84,14 +75,14 @@ async def cmd(self, ctx, bet):
def get_emotes(client):
decoration = CONST.SLOTS["emotes"]
return {name: client.get_emoji(emoji_id) for name, emoji_id in decoration.items()}
emotes = CONST.EMOTE_IDS
return {name: client.get_emoji(emoji_id) for name, emoji_id in emotes.items()}
def calculate_slots_results(bet, results):
result_type = None
multiplier = None
rewards = CONST.SLOTS["reward_multipliers"]
rewards = CONST.SLOTS_MULTIPLIERS
# count occurrences of each item in the list
counts = Counter(results)

View file

@ -73,4 +73,4 @@
"🎊 It's a day to be spoiled and celebrated, **{0}**! Wishing you the happiest of birthdays! 🎁",
"🎂 As you turn another year older, know that you are loved and cherished, **{0}**! Happy Birthday! 🎉"
]
}
}

View file

@ -49,6 +49,8 @@
"blackjack_won_21": "You won with a score of 21!",
"blackjack_won_natural": "You won with a natural hand!",
"blackjack_won_payout": "You won **${0}**.",
"blackjack_hit": "hit",
"blackjack_stand": "stand",
"boost_default_description": "Thanks for boosting, **{0}**!!",
"boost_default_title": "New Booster",
"case_case_field": "Case:",
@ -289,5 +291,6 @@
"give_error_bot": "you can't give money to a bot.",
"give_error_invalid_amount": "invalid amount.",
"give_error_insufficient_funds": "you don't have enough cash.",
"give_success": "**{0}** gave **${1}** to {2}."
"give_success": "**{0}** gave **${1}** to {2}.",
"error_cant_use_buttons": "You can't use these buttons, they're someone else's!"
}

103
settings/settings.yaml Normal file
View file

@ -0,0 +1,103 @@
---
info:
title: Luminara
author: wlinator
license: GNU General Public License v3.0
version: "2.9.0" # "Settings & Customizability" update
repository_url: https://git.wlinator.org/Luminara/Lumi
images:
allowed_image_extensions:
- .jpg
- .png
birthday_gif_url: https://media1.tenor.com/m/NXvU9jbBUGMAAAAC/fireworks.gif
colors:
color_default: 0xFF8C00
color_warning: 0xFF7600
color_error: 0xFF4500
economy:
daily_reward: 500
blackjack_multiplier: 1.4
blackjack_hit_emoji: <:hit:1119262723285467156>
blackjack_stand_emoji: <:stand:1118923298298929154>
slots_multipliers:
pair: 1.5
three_of_a_kind: 4
three_diamonds: 6
jackpot: 15
art:
fetch_url: https://git.wlinator.org/Luminara/Art/raw/branch/main/
logo:
opaque: lumi_logo.png
transparent: lumi_logo_transparent.png
icons:
boost: lumi_boost.png
check: lumi_check.png
cross: lumi_cross.png
exclaim: lumi_exclaim.png
hammer: lumi_hammer.png
money_bag: lumi_money_bag.png
money_coins: lumi_money_coins.png
question: lumi_question.png
streak: lumi_streak.png
streak_bronze: lumi_streak_bronze.png
streak_gold: lumi_streak_gold.png
streak_silver: lumi_streak_silver.png
warning: lumi_warning.png
juicybblue:
flowers: https://i.imgur.com/79XfsbS.png
teapot: https://i.imgur.com/wFsgSnr.png
muffin: https://i.imgur.com/hSauh7K.png
other:
cloud: https://i.imgur.com/rc68c43.png
trophy: https://i.imgur.com/dvIIr2G.png
emotes:
guild_id: 1038051105642401812
emote_ids:
slots_animated_id: 1119262805309259776
slots_0_id: 1119262803816095825
slots_1_id: 1119262801261760592
slots_2_id: 1119262800049614939
slots_3_id: 1119262796497039510
slots_4_id: 1119262794676715681
slots_5_id: 1119262792386621555
slots_6_id: 1119262791061229669
S_Wide: 1119286730302955651
L_Wide: 1119286763802857533
O_Wide: 1119286787169329203
T_Wide: 1119286804634406942
CBorderBLeft: 1119286973572595712
CBorderBRight: 1119286918459445408
CBorderTLeft: 1119287006464331806
CBorderTRight: 1119286865284051035
HBorderB: 1119286936155213835
HBorderT: 1119287027662344322
VBorder: 1119286889854279680
WSmall: 1119288536282173490
ISmall: 1119288552673517608
NSmall: 1119288579382857830
LCentered: 1119287296127156325
OCentered: 1119287563245584394
SCentered: 1119287327588634647
ECentered: 1119287343833165945
Blank: 1119287267001905283
lost: 1119288454212243607
introductions:
intro_guild_id: 719227135151046700
intro_channel_id: 973619250507972600
intro_question_mapping:
Nickname: How would you like to be identified in the server?
Age: How old are you?
Region: Where do you live?
Languages: Which languages do you speak?
Pronouns: What are your preferred pronouns?
Sexuality: What's your sexuality?
Relationship status: What's your current relationship status?
Likes & interests: Likes & interests
Dislikes: Dislikes
EXTRAS: "EXTRAS: job status, zodiac sign, hobbies, etc. Tell us about yourself!"