Dumb April Fools Bot for Touhou Project Discord in 2021
at main 361 lines 12 kB view raw
1import asyncio 2import json 3import random 4import discord 5import os 6import csv 7import collections 8from discord.ext import commands 9 10IMPORT_DATA = "roles.csv" 11OUTPUT_DATA = "data.json" 12BASE_COST = 100000 13COST_GROWTH = 2.50 14PAYOUT_MIN = 50000 15PAYOUT_MAX = 75000 16 17bot = commands.Bot( 18 max_messages=None, 19 command_prefix='!', 20 member_cache_flags=discord.MemberCacheFlags.all(), 21 intents=discord.Intents.all()) 22 23with open(OUTPUT_DATA, "r+") as f: 24 data = json.load(f) 25 26def save_data(data): 27 with open(OUTPUT_DATA, "w") as f: 28 json.dump(data, f) 29 30@bot.event 31async def on_ready(): 32 print("Bot ready!") 33 print(f"Logged in as {bot.user}!") 34 35async def get_confirmation(bot, check): 36 decided = None 37 while decided is None: 38 msg = await bot.wait_for('message', check=check, timeout=30) 39 decided = { 40 'y': True, 41 'yes': True, 42 'n': False, 43 'no': False, 44 }.get(msg.content.lower()) 45 return decided 46 47@bot.listen() 48async def on_message(message): 49 if message.author.bot or message.channel.id == 372835728574382090: 50 return 51 global BASE_COST, PAYOUT_MIN, PAYOUT_MAX, data 52 cnt = message.content 53 if any(cnt.startswith(a) for a in ['!', '~', '%', '\'']): 54 return 55 key = str(message.author.id) 56 payout = random.randint(PAYOUT_MIN, PAYOUT_MAX) 57 if key in data['users']: 58 data['users'][key]['money'] += payout 59 else: 60 data['users'][key] = { 61 'money': payout, 62 'next_roll': BASE_COST, 63 } 64 save_data(data) 65 print(f"Gave ${payout} to {message.author}") 66 67# @bot.command(name="import") 68# async def import_roles(ctx): 69 # """Imports all of the preplanned roles into the server.""" 70 # global data 71 # with open(IMPORT_DATA, 'r') as f: 72 # reader = csv.reader(f) 73 # for row in reader: 74 # print(row) 75 # name = row[0] 76 # weight = int(row[2]) 77 # lore = row[5] 78 # if row[1]: 79 # color = int(row[1][1:], 16) 80 # else: 81 # color = discord.Colour.default() 82 # if 'roles' not in data: 83 # data['roles'] = {} 84 # if any(r['name'] == name for r in data['roles'].values()): 85 # print("Skipping ", name, " already made.") 86 # continue 87 # role = await ctx.guild.create_role( 88 # name=name, 89 # color=color, 90 # permissions=discord.Permissions.none(), 91 # mentionable=False, 92 # hoist=False) 93 94 # data['roles'][role.id] = { 95 # 'id': role.id, 96 # 'name': name, 97 # 'weight': weight, 98 # 'lore': lore 99 # } 100 # save_data(data) 101 # print("Created role ", name) 102 103@bot.command() 104async def gacha(ctx): 105 """Pays money to randomly get one of the roles in the bot.""" 106 global data 107 user = data['users'].get(str(ctx.author.id)) 108 if user is None: 109 await ctx.send(f"Sorry {ctx.author.mention}, I can't give credit! " 110 f"Come back when you are a little, mmmmmmm, RICHER! " 111 f" (Wallet: 0, Roll Cost: **${BASE_COST})**") 112 return 113 elif user['money'] < user['next_roll']: 114 await ctx.send(f"Sorry {ctx.author.mention}, I can't give credit! " 115 f"Come back when you are a little, mmmmmmm, RICHER! " 116 f" (Wallet: {user['money']}, Roll Cost: **${user['next_roll']})**") 117 return 118 user['money'] -= user['next_roll'] 119 total_weight = sum(r['weight'] for r in data['roles'].values()) 120 target_weight = random.randint(0, total_weight) 121 role = None 122 for gacha_role in data['roles'].values(): 123 target_weight -= gacha_role['weight'] 124 if target_weight < 0: 125 role = ctx.guild.get_role(int(gacha_role['id'])) 126 break 127 if role in ctx.author.roles: 128 await ctx.send(f"You rolled {role.mention}, but you already have it!" 129 f"Your next gacha roll will cost " 130 f"**${user['next_roll']}**") 131 else: 132 next_cost = int(COST_GROWTH * user['next_roll']) 133 user['next_roll'] = next_cost 134 suffix = f"Your next gacha roll will cost: {next_cost}" 135 await ctx.author.add_roles(role) 136 await ctx.send(f"You rolled {role.mention}! " + suffix) 137 save_data(data) 138 139@bot.command() 140async def goomble(ctx, amount: int, multiplier: float): 141 """Stake your money on a life or death gamble! 142 143 Examples: 144 ~goomble 20000 5.0 => Bets 20,000 for a payout of -100,000 to 100,000 145 ~goomble 50000 1.0 => Bets 50,000 for a payout of -50,000 to 50,000 146 147 There is no limit to your multiplier. 148 149 YOU CAN GO INTO DEBT USING THIS. BEWARE. 150 ZAWA. ZAWA. ZAWA. ZAWA. ZAWA. 151 """ 152 global data 153 if amount < 0: 154 await ctx.send(f"{ctx.author.mention}, cannot bet negative money!") 155 return 156 user = data['users'].get(str(ctx.author.id)) 157 if user is None or user['money'] < 0: 158 await ctx.send(f"{ctx.author.mention}, you have no money!") 159 return 160 elif user['money'] < amount: 161 await ctx.send(f"{ctx.author.mention}, you don't have ${amount} to bet!") 162 return 163 elif multiplier < 5: 164 await ctx.send(f"{ctx.author.mention}, YOU WEAK WILLED FOOL. GAMBLE MORE!" 165 f"(Minimum Mulitplier 5x)") 166 return 167 168 base_range = random.random() 169 direction = random.choice([-1.0, 1.0]) 170 delta = int(amount * direction * base_range * multiplier) 171 user['money'] = int(user['money'] + delta) 172 save_data(data) 173 await ctx.send(f"{ctx.author.mention}, you gambled {amount} and " 174 f"earned {delta}. You now have **${user['money']}**.") 175 176@bot.command() 177async def allin(ctx): 178 """Stake ALL money on a life or death gamble with a 10,000x multiplier! 179 180 YOU **WILL** GO INTO DEBT USING THIS. BEWARE. 181 ZAWA. ZAWA. ZAWA. ZAWA. ZAWA. 182 """ 183 global data 184 user = data['users'].get(str(ctx.author.id)) 185 if user is None or user['money'] < 0: 186 await ctx.send(f"{ctx.author.mention}, you have no money!") 187 return 188 await goomble(ctx, user['money'], 10000) 189 190@bot.command() 191async def shion(ctx): 192 """Burn all of your money.""" 193 global data 194 user = data['users'].get(str(ctx.author.id)) 195 if user is None: 196 await ctx.send("Sorry who are you?") 197 return 198 if user['money'] < 0: 199 await ctx.send("Shion doesn't want your debt!") 200 return 201 user['money'] = 0 202 save_data(data) 203 await ctx.send("Shion hungrily devours your wallet. You now have $0.") 204 205@bot.command(hidden=True) 206async def gachi(ctx): 207 await ctx.send("Fuck you. You probably meant !gacha.") 208 209@bot.command(hidden=True) 210async def fumo(ctx): 211 """Fumo.""" 212 global data 213 user = data['users'].get(str(ctx.author.id)) 214 if user is None: 215 await ctx.send("Sorry who are you?") 216 return 217 await ctx.send(f"You could buy {user['money'] / 40} fumos with your money.") 218 219@bot.command() 220async def wallet(ctx): 221 """Shows how much money you have.""" 222 try: 223 key = str(ctx.author.id) 224 await ctx.send(f"You have ${data['users'][key]['money']}") 225 except: 226 await ctx.send(f"You have nothing. You are poor.") 227 228@bot.command() 229async def give(ctx, member: discord.Member, offer: discord.Role): 230 """Gives one role to another user.""" 231 if offer not in ctx.author.roles: 232 await ctx.send(f"**{ctx.author.mention}** does not have {offer.mention}") 233 return 234 if str(offer.id) not in data['roles']: 235 await ctx.send(f"**{offer}** is not a gacha role.") 236 return 237 238 await ctx.send(f"{member.mention}, **{ctx.author}** would like to give you" 239 f"{offer.mention}. Do you accept? (y/yes/n/no)") 240 241 def check(msg): 242 return msg.channel == ctx.channel and msg.author == member 243 try: 244 decision = await get_confirmation(ctx.bot, check) 245 except asyncio.TimeoutError: 246 await ctx.send(f"{ctx.author.mention}: Exchange cancelled.") 247 return 248 249 if decision: 250 await asyncio.gather(*[ 251 ctx.author.remove_roles(offer), 252 member.add_roles(offer), 253 ]) 254 await ctx.send(":handshake: Exchange complete!") 255 else: 256 await ctx.send(":x: Exchange refused!") 257 258@bot.command() 259async def charity(ctx, member: discord.Member, amount: int): 260 """Gives another user money.""" 261 if amount < 0: 262 await ctx.send(f"{ctx.author.mention}, DEBIT IS NOT CHARITY!") 263 return 264 global data, BASE_COST 265 src = data['users'].get(str(ctx.author.id)) 266 dst = data['users'].get(str(member.id)) 267 268 if src is None or src['money'] < amount: 269 await ctx.send(f"{ctx.author.mention}, you don't have **${amount}** to give!") 270 return 271 272 await ctx.send(f"{member.mention}, **{ctx.author}** would like to give you" 273 f"${amount}. Do you accept? (y/yes/n/no)") 274 275 def check(msg): 276 return msg.channel == ctx.channel and msg.author == member 277 try: 278 decision = await get_confirmation(ctx.bot, check) 279 except asyncio.TimeoutError: 280 await ctx.send(f"{ctx.author.mention}: Charity cancelled.") 281 return 282 283 src['money'] -= amount 284 if dst is not None: 285 dst['money'] += amount 286 else: 287 data['users'][str(member.id)] = { 288 'money': amount, 289 'next_roll': BASE_COST, 290 } 291 save_data(data) 292 await ctx.send(":handshake: Exchange complete!") 293 294@bot.command() 295async def sacrifice(ctx, role: discord.Role): 296 """Sacrifices roles to the gods.""" 297 global data 298 if str(role.id) not in data['roles']: 299 await ctx.send(f"**{role}** is not a gacha role.") 300 return 301 await ctx.author.remove_roles(role) 302 await ctx.send(f"{ctx.author.mention}: Kanako ate your {role}.") 303 304@bot.command() 305async def lore(ctx, role: discord.Role): 306 """Shows the Touhou Discord History behind a role.""" 307 global data 308 role_data = data['roles'].get(str(role.id)) 309 if role_data is not None: 310 await ctx.send(f"{role.name}: {role_data['lore']}") 311 else: 312 await ctx.send("Lmao what lore?") 313 314@bot.command() 315async def trade(ctx, member: discord.Member, 316 offer: discord.Role, 317 exchange: discord.Role): 318 """Trades one role for another with another user.""" 319 global data 320 if offer not in ctx.author.roles: 321 await ctx.send(f"**{member}** does not have {offer.mention}") 322 return 323 if offer not in ctx.author.roles: 324 await ctx.send(f"**{member}** does not have {offer.mention}") 325 return 326 if exchange not in member.roles: 327 await ctx.send(f"**{member}** does not have {exchange.mention}") 328 return 329 if str(offer.id) not in data['roles']: 330 await ctx.send(f"**{offer}** is not a gacha role.") 331 return 332 if str(exchange.id) not in data['roles']: 333 await ctx.send(f"**{exchange}** is not a gacha role.") 334 return 335 336 await ctx.send(f"{member.mention}, **{ctx.author}** would like to trade" 337 f"{offer.mention} for {exchange.mention}. Do you accept?" 338 f" (y/yes/n/no)") 339 340 def check(msg): 341 return msg.channel == ctx.channel and msg.author == member 342 try: 343 decision = await get_confirmation(ctx.bot, check) 344 except asyncio.TimeoutError: 345 await ctx.send(f"{ctx.author.mention}: Exchange cancelled.") 346 return 347 348 if decision: 349 await asyncio.gather(*[ 350 ctx.author.add_roles(exchange), 351 ctx.author.remove_roles(offer), 352 member.add_roles(offer), 353 member.remove_roles(exchange) 354 ]) 355 await ctx.send(":handshake: Exchange complete!") 356 else: 357 await ctx.send(":x: Exchange refused!") 358 359 360 361bot.run(os.environ["DISCORD_TOKEN"])