initial commit
This commit is contained in:
commit
7b25cd51ed
8 changed files with 552 additions and 0 deletions
20
build/OhFortuna/Dockerfile
Normal file
20
build/OhFortuna/Dockerfile
Normal file
|
@ -0,0 +1,20 @@
|
|||
FROM python:3
|
||||
|
||||
ENV HOME_DIR="/OhFortuna"
|
||||
ENV BOT_DATA_DIR="${HOME_DIR}/data"
|
||||
ENV PATH="${HOME_DIR}/.local/bin:${PATH}"
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK="1"
|
||||
|
||||
RUN addgroup --gid '1000' 'abc'; \
|
||||
adduser --system --disabled-password --uid '1000' --home "$HOME_DIR" --gid '1000' 'abc'; \
|
||||
chmod 750 "$HOME_DIR"
|
||||
|
||||
COPY --chown=abc:abc ./src "$HOME_DIR"
|
||||
USER abc
|
||||
|
||||
WORKDIR "$HOME_DIR"
|
||||
RUN chmod u+x "${HOME_DIR}/bot.py"; \
|
||||
mkdir "$BOT_DATA_DIR"; \
|
||||
pip install --user discord
|
||||
|
||||
CMD "${HOME_DIR}"/bot.py
|
7
build/OhFortuna/src/Readme.txt
Normal file
7
build/OhFortuna/src/Readme.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
This bot is written in Python 3.8, for seamless experience, please install Python version 3.8 or above.
|
||||
|
||||
External Library used:
|
||||
- discord.py
|
||||
- python-dotenv
|
||||
|
||||
Please install the libraries stated above for the bot to work.
|
339
build/OhFortuna/src/bot.py
Normal file
339
build/OhFortuna/src/bot.py
Normal file
|
@ -0,0 +1,339 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
from os.path import isfile
|
||||
from random import randrange
|
||||
import re
|
||||
import math
|
||||
import json
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
if 'BOT_TOKEN' in os.environ:
|
||||
TOKEN = os.environ['BOT_TOKEN']
|
||||
else:
|
||||
with open('tokenfile', 'r') as tokenfd:
|
||||
TOKEN = tokenfd.read().strip().strip('\n')
|
||||
|
||||
BOT_DATA_DIR = os.getenv('BOT_DATA_DIR', '')
|
||||
|
||||
|
||||
#print(TOKEN)
|
||||
#
|
||||
#import sys
|
||||
#sys.exit(1)
|
||||
|
||||
# Setup Bot
|
||||
bot = commands.Bot(command_prefix='!')
|
||||
|
||||
# Bot Initialization
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
print("\n{name} is online\n".format(name=bot.user.name))
|
||||
|
||||
|
||||
|
||||
# ──────────────────────
|
||||
# Start of Code
|
||||
# ──────────────────────
|
||||
|
||||
# === Functions ===
|
||||
|
||||
def dice(value):
|
||||
value = value.split("d")
|
||||
amount, face = int(value[0]), int(value[1])
|
||||
rolled = []
|
||||
for i in range(0,amount):
|
||||
rolled.append(randrange(face)+1)
|
||||
return rolled
|
||||
|
||||
def find(value, data):
|
||||
i = 0
|
||||
for x in data:
|
||||
if value in x:
|
||||
return i
|
||||
i+=1
|
||||
return "False"
|
||||
|
||||
def fetch_var(ctx, var):
|
||||
emsg = False
|
||||
user = ctx.message.author.id
|
||||
path = os.path.join(BOT_DATA_DIR, "{0}.txt".format(user))
|
||||
if isfile(path) == True:
|
||||
with open(path, "r") as file:
|
||||
data = json.load(file)
|
||||
if var in data:
|
||||
key = str(data[var])
|
||||
else:
|
||||
emsg = "`{0}` does not exist in user database".format(var)
|
||||
key = False
|
||||
else:
|
||||
emsg = "Database does not exist. Please start with `!uvar`"
|
||||
key = False
|
||||
return key, emsg
|
||||
|
||||
def check_doublet(roll):
|
||||
a, b = roll[0], roll[1]
|
||||
if a == b:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# === Error Handler ===
|
||||
|
||||
# Ignore Command Not Found Error in Console
|
||||
@bot.event
|
||||
async def on_command_error(ctx, error):
|
||||
if isinstance(error, commands.CommandNotFound):
|
||||
return
|
||||
raise error
|
||||
|
||||
# === Commands ===
|
||||
@bot.command(name="uvar", aliases=["gvar"], brief="Create/Change/Remove variable", description="You may use this command to create/change/remove either user or global variable\nUse !uvar for user's database; !gvar for global database", usage="[change/remove] <Variable> <Value>")
|
||||
async def uvar(ctx, *args):
|
||||
if ctx.invoked_with == "gvar":
|
||||
command = "gvar"
|
||||
path = os.path.join(BOT_DATA_DIR, "Global.txt")
|
||||
else:
|
||||
command = "uvar"
|
||||
path = os.path.join(BOT_DATA_DIR, '{}.txt'.format(ctx.message.author.id))
|
||||
if len(args) == 2:
|
||||
if args[0] != "delete":
|
||||
name, value = args[0], args[1]
|
||||
if value.isnumeric():
|
||||
value = int(value)
|
||||
if isfile(path) != True:
|
||||
data = {name: value}
|
||||
with open(path, 'w') as file:
|
||||
file.write(json.dumps(data))
|
||||
await ctx.reply("Create the variable: `{0}` with value: {1}".format(name, value))
|
||||
else:
|
||||
with open(path, 'r') as file:
|
||||
data = json.load(file)
|
||||
if (name in data):
|
||||
await ctx.reply("This name already exist")
|
||||
else:
|
||||
data[name] = value
|
||||
with open(path, 'w') as file:
|
||||
file.write(json.dumps(data))
|
||||
await ctx.reply("Create the variable: `{0}` with value: {1}".format(name, value))
|
||||
else:
|
||||
await ctx.reply("Please enter a valid value\nFor more info, please use `!help {}`".format(command))
|
||||
else:
|
||||
name = args[1]
|
||||
if isfile(path):
|
||||
with open(path, 'r') as file:
|
||||
data = json.load(file)
|
||||
if name in data.keys():
|
||||
data.pop(name)
|
||||
with open(path, 'w') as file:
|
||||
file.write(json.dumps(data))
|
||||
await ctx.reply("Variable: `{0}` is deleted".format(name))
|
||||
else:
|
||||
await ctx.reply("That variable does not exist")
|
||||
else:
|
||||
await ctx.reply("Database does not exist, please start by entering `!{}`".format(command))
|
||||
|
||||
elif len(args) == 3:
|
||||
action, name, value = args[0].lower(), args[1], args[2]
|
||||
if action == "change":
|
||||
if value.isnumeric():
|
||||
value = int(value)
|
||||
if isfile(path):
|
||||
with open(path, 'r') as file:
|
||||
data = json.load(file)
|
||||
if name in data:
|
||||
data[name] = value
|
||||
with open(path, 'w') as file:
|
||||
file.write(json.dumps(data))
|
||||
await ctx.reply("Changed the variable: `{0}` value to: {1}".format(name, value))
|
||||
else:
|
||||
await ctx.reply("This variable does not exist, please add with `!{}`".format(command))
|
||||
else:
|
||||
await ctx.reply("User data does not exist, please use `!{}` to make new value".format(command))
|
||||
else:
|
||||
await ctx.reply("Please enter a valid value\nFor more info, please use `!help {}`".format(command))
|
||||
else:
|
||||
await ctx.reply("This action does not exist\nFor more info, please use `!help {}`".format(command))
|
||||
else:
|
||||
await ctx.reply("Please insert the variable and value\nFor more info, please use `!help {}`".format(command))
|
||||
|
||||
@bot.command(name="ulist", aliases=["glist"], brief="Check list of variables", description="Use this command to check the variables in user/global database")
|
||||
async def ulist(ctx):
|
||||
if ctx.invoked_with == "glist":
|
||||
path = os.path.join(BOT_DATA_DIR, "Global.txt")
|
||||
else:
|
||||
path = os.path.join(BOT_DATA_DIR, '{}.txt'.format(ctx.message.author.id))
|
||||
if isfile(path):
|
||||
with open(path, 'r') as file:
|
||||
data = json.load(file)
|
||||
var = []
|
||||
if ctx.invoked_with == "glist":
|
||||
var.append("**Global Variables**")
|
||||
else:
|
||||
var.append("**{0}'s Variables**".format(ctx.message.author.display_name))
|
||||
for i in data:
|
||||
line = "{0} `{1}`".format(i, data[i])
|
||||
var.append(line)
|
||||
await ctx.reply("\n".join(var))
|
||||
else:
|
||||
await ctx.reply("There is no variable list yet")
|
||||
|
||||
@bot.command(name="uclear", aliases=["gclear"], brief="Clear variables from database")
|
||||
async def uclear(ctx):
|
||||
if ctx.invoked_with == "gclear":
|
||||
name = "global"
|
||||
path = os.path.join(BOT_DATA_DIR, "Global.txt")
|
||||
else:
|
||||
name = "user"
|
||||
path = os.path.join(BOT_DATA_DIR, '{}.txt'.format(ctx.message.author.id))
|
||||
if isfile(path):
|
||||
os.remove(path)
|
||||
await ctx.reply("Cleared the {0} data".format(name))
|
||||
else:
|
||||
await ctx.reply("The {0} data is already empty".format(name))
|
||||
|
||||
@bot.command(name="roll", brief="Discretionary dice rolls", description="Use this to roll dice of any types and with simple math\nFor example: !roll 3d10+1\nRefers to 3 Dice with 10 Sides, adds 1",usage="<Value> [%Alias]")
|
||||
async def roll(ctx, value: str = False, name: str = False):
|
||||
if value != False:
|
||||
try:
|
||||
line = []
|
||||
if not name:
|
||||
name = ctx.message.author.display_name
|
||||
line.append("**{0}'s Roll**".format(name.strip("%")))
|
||||
vlist = re.split('([+-/*//])', value)
|
||||
x = 0
|
||||
for i in vlist:
|
||||
if "d" in i:
|
||||
i = dice(i)
|
||||
vlist[x] = i
|
||||
x+=1
|
||||
x = 0
|
||||
roll = 1
|
||||
for i in vlist:
|
||||
if type(i) == list:
|
||||
line.append("Roll {0}: `{1}`".format(roll, ", ".join(list(map(str, i)))))
|
||||
roll+=1
|
||||
vlist[x] = sum(i)
|
||||
x+=1
|
||||
vlist = ' '.join(list(map(str, vlist)))
|
||||
total = eval(vlist)
|
||||
line.append("\nTotal: {0} = **{1}**".format(vlist, total))
|
||||
await ctx.reply("\n".join(line))
|
||||
except:
|
||||
await ctx.reply("Invalid roll value\nFor more info, please use `!help roll`")
|
||||
else:
|
||||
await ctx.reply("Please indicate the roll variable\nFor more info, please use `!help roll`")
|
||||
|
||||
@bot.command(name="r",aliases=["r+","r++","r-","i"], brief="Standard/Initiative roll", description="You may use this command to roll either standard or initiative dice roll\nFor example: !r 3+VAR-VAR2 %Snowy #10\n\n*!i does not support target", usage="[Var/Number] [%Alias] [#Target]")
|
||||
async def roll(ctx, *, value: str = False):
|
||||
try:
|
||||
command = ctx.invoked_with
|
||||
line = False
|
||||
no_error = True
|
||||
name = ctx.message.author.display_name
|
||||
cname = "False"
|
||||
target = "False"
|
||||
if command == "r":
|
||||
roll = dice("2d10")
|
||||
line = "{0},{1}".format(roll[0], roll[1])
|
||||
elif command == "r+":
|
||||
roll = sorted(dice("3d10"), reverse=True)
|
||||
line = "{0},{1},~~{2}~~".format(roll[0], roll[1], roll[2])
|
||||
roll.pop(2)
|
||||
elif command == "r++":
|
||||
roll = sorted(dice("4d10"), reverse=True)
|
||||
line = "{0},{1},~~{2}~~,~~{3}~~".format(roll[0], roll[1], roll[2], roll[3])
|
||||
roll.pop(3)
|
||||
roll.pop(2)
|
||||
elif command == "r-":
|
||||
roll = sorted(dice("3d10"))
|
||||
line = "{0},{1},~~{2}~~".format(roll[0], roll[1], roll[2])
|
||||
roll.pop(2)
|
||||
elif command == "i":
|
||||
roll = dice("1d10")
|
||||
line = "{0}".format(roll[0])
|
||||
if value:
|
||||
value = re.split('([+-/*// ])', value)
|
||||
value = [x for x in value if x.strip()]
|
||||
cname = find("%", value)
|
||||
if cname != "False":
|
||||
cname = value.pop(cname)
|
||||
name = cname.strip("%")
|
||||
target = find("#", value)
|
||||
if target != "False":
|
||||
target = value.pop(target)
|
||||
target = int(target.strip("#"))
|
||||
if command == "i":
|
||||
no_error = False
|
||||
await ctx.reply("Initiative (`!i`) does not accept target value")
|
||||
x = 0
|
||||
for i in value:
|
||||
if no_error:
|
||||
if i.isnumeric():
|
||||
pass
|
||||
elif (i == "+") | (i == "-") | (i == "*") | (i == "/"):
|
||||
pass
|
||||
else:
|
||||
var, emsg = fetch_var(ctx, i)
|
||||
if var:
|
||||
value[x] = var
|
||||
else:
|
||||
await ctx.reply(emsg)
|
||||
no_error = False
|
||||
break
|
||||
x+=1
|
||||
else:
|
||||
break
|
||||
if no_error:
|
||||
total = 0
|
||||
if value:
|
||||
total = eval(' '.join(list(map(str, value))))
|
||||
total += sum(roll)
|
||||
if target != "False":
|
||||
if check_doublet(roll) & (total < target):
|
||||
output = "Dramatic Failure"
|
||||
elif check_doublet(roll) & (total > target):
|
||||
staging = math.floor((total-target)/2)+1
|
||||
output = "Exceptional Success, {0} staging(s)".format(staging)
|
||||
elif total < target:
|
||||
output = "Failure"
|
||||
elif total == target:
|
||||
output = "Tough Luck, 1 staging"
|
||||
elif total > target:
|
||||
staging = math.floor((total-target)/3)+1
|
||||
output = "Success, {0} staging(s)".format(staging)
|
||||
if value:
|
||||
output = "{0}'s Roll: {1} ({2}[+{3}]={4} vs. {5})".format(name, output, line, "".join(value), total, target)
|
||||
else:
|
||||
output = "{0}'s Roll: {1} ({2}={3} vs. {4})".format(name, output, line, total, target)
|
||||
await ctx.reply(output)
|
||||
else:
|
||||
if value:
|
||||
output = "{0}[+{1}]".format(line, "".join(value))
|
||||
else:
|
||||
output = "{0}".format(line)
|
||||
|
||||
if command == "i":
|
||||
output = "{0}'s roll: Initiative {1} ({2})".format(name, total, output)
|
||||
elif check_doublet(roll):
|
||||
output = "{0}'s roll: a Doublet {1} ({2})".format(name, total, output)
|
||||
else:
|
||||
output = "{0}'s roll: {1} ({2})".format(name, total, output)
|
||||
await ctx.reply(output)
|
||||
else:
|
||||
total = sum(roll)
|
||||
if command == "i":
|
||||
output = "{0}'s roll: Initiative {1} ({2})".format(name, total, line)
|
||||
elif check_doublet(roll):
|
||||
output = "{0}'s roll: Doublet {1} ({2})".format(name, total, line)
|
||||
else:
|
||||
output = "{0}'s roll: {1} ({2})".format(name, total, line)
|
||||
await ctx.reply(output)
|
||||
except:
|
||||
await ctx.reply("Invalid arguement, please use `!help r/i to learn more`")
|
||||
|
||||
|
||||
|
||||
bot.run(TOKEN)
|
1
build/OhFortuna/src/requirements.txt
Normal file
1
build/OhFortuna/src/requirements.txt
Normal file
|
@ -0,0 +1 @@
|
|||
discord
|
1
build/OhFortuna/src/tokenfile
Normal file
1
build/OhFortuna/src/tokenfile
Normal file
|
@ -0,0 +1 @@
|
|||
DemoToken123
|
Loading…
Add table
Add a link
Reference in a new issue