from objects.rance import automate import random as ra import asyncio import discord excluded=False commands={'rance':[], 'rancequit':[], 'rancehack':[], 'rancerank':[], 'azul':[]} rancegames={} async def rance(args, channel, message): if channel.id in rancegames and not type(rancegames[channel.id])==tuple: await channel.send("Game already in progress, just watch or pick another channel") return p1=message.author if len(args)==1: try: num=int(args[0]) except ValueError: num=None if num is not None and 0") await p2.send(f"Game's ready in <#{channel.id}>") await playrance(channel) async def rancesetup(p1,p2,channel,num): # All checks finally out of the way zzzz rancegames[channel.id]=seed=ra.random() await channel.send("ゲーム・スタート!") # Fire off the first set of listeners; the player names. try: names=await getnp("Please enter player name.",[p1,p2],[[],[]],[]) except (discord.Forbidden,discord.HTTPException) as ex: await channel.send("Couldn't DM one of the players (can't tell who yet), maybe their DM settings are wrong; perhaps try DMing me first.") rancegames.pop(channel.id) return if not rancestatus(channel.id,seed): return berd=automate.blindstart(num,*names) classlist=next(berd) # https://stackoverflow.com/a/44780467 nl='\n' longth=lambda x:len(x.split(' '))==num or "Wrong number of units provided" def incls(x): out=[] for n in x.split(' '): if n not in automate.classlist: out.append(n) if out: return f"Invalid class names: {', '.join(out)}. Please note they're case sensitive." return True classes=await getnp(f"What classes would you like for your **{num}** units? (Space separated)\nList of melee classes (work best in front row):\n{nl.join(classlist[0])}\n\nRanged (work best in back row):\n{nl.join(classlist[1])}",[p1,p2],[[],[]],[longth,incls]) if not rancestatus(channel.id,seed): return units=berd.send(tuple([m.lower() for m in n.split(' ')] for n in classes)) def isint(x): try: int(x); return True except ValueError: return f"'{x}' isn't a valid integer" rerolls=await getnp("Your units:\n{0}\n Please pick a number (from 1 to {1}) to reroll; you can discard the reroll, don't worry",[p1,p2],[['\n'.join(units[0]),num],['\n'.join(units[1]),num]],[isint,lambda x:int(x) in range(1,num+1) or f"{x} isn't a valid unit number"]) rerolls=tuple(int(n)-1 for n in rerolls) if not rancestatus(channel.id,seed): return news=berd.send(rerolls) boolaliases={'new':True,'old':False, 'yes':True,'no':False, 'true':True,'false':False, '1':True,'0':False, 'y':True,'n':False} confirms=await getnp("Old unit: {0}\nNew unit: {1}\nWhich would you like to keep (old/new)?",[p1,p2],[[units[0][rerolls[0]],news[0]],[units[1][rerolls[1]],news[1]]],[lambda x:x in boolaliases or "Please specify either `old` or `new`"]) if not rancestatus(channel.id,seed): return _=berd.send(tuple(boolaliases[n.lower()] for n in confirms)) def checknames(x): if x in ('-','`-`'): return True try: a={int(n.split(':')[0]):n.split(':')[1] for n in x.split(' ')} except: return 'The format was weird in some way, please try again.' if min(list(a))<1 or max(list(a))>num+1: return f"Numbers should be between 1 and {num} inclusive." return True unames=await getnp('You may provide names for your units, if you wish. Please provide them as num:name pairs, eg. `2:Ran 3:Rin`\nUnnamed units will be assigned a number as their name. Say `-` if you don\'t want to name any units.',[p1,p2],[[],[]],[checknames]) if not rancestatus(channel.id,seed): return def isints(x): for n in x.split(' '): try: int(n) except ValueError: return f"'{n}' isn't a valid integer" if int(n) not in range(1,7): return f"{n} isn't a valid position" return True units=berd.send(({int(n.split(':')[0])-1:n.split(':')[1] for n in unames[0].split(' ')} if unames[0]!='-' else {},{int(n.split(':')[0])-1:n.split(':')[1] for n in unames[1].split(' ')} if unames[1]!='-' else {})) positions=await getnp("Final unit list:\n{0}\nPlease enter the positions for these units (1-3 back row (ranged units should go here), 4-6 front row (melee units should go here), space separated, positions should be unique!)",[p1,p2],[['\n'.join(units[0])],['\n'.join(units[1])]],[lambda x:len(x.split(' '))==num or f"You should provide {num} position numbers", isints, lambda x:len(set(x.split(' ')))==len(x.split(' ')) or "Position numbers must be unique"]) if not rancestatus(channel.id,seed): return _=berd.send(([int(n)-1 for n in positions[0].split(' ')],[int(n)-1 for n in positions[1].split(' ')])) try: berd.send((p1.id,p2.id)) except StopIteration as ex: board=ex.value # We have a board! rancegames[channel.id]=board await p1.send(f"Game's ready in <#{channel.id}>") await p2.send(f"Game's ready in <#{channel.id}>") async def playrance(channel,board=None): nl='\n' if board is None: board=rancegames[channel.id] controller=board.controller() await channel.send("If a unit wasn't named, its unit code became its name.\nファイト!") # No auto quit yet. while True: if not rancestatus(channel.id,board): return # We can discard this during charged actions but if we don't get it shit goes wrong. try: active=next(controller) except StopIteration as ex: end=ex; break if active is None: # Charged action is happening. Don't wait for action or anything. action=None else: await channel.send(f'```{board}```') await channel.send(f"Available actions for {active[0][0]}'s unit {active[1]}:\n{nl.join([', '.join(n) for n in active[2]])}") msg=await client.wait_for('message',check=lambda x:x.author.id==active[0][1] and x.channel.id==channel.id and x.content.split(' ')[0] in [n[0] for n in active[2]]) action=msg.content.split(' ') try: res=controller.send(action); await channel.send(res) except Exception as ex: await channel.send(str(ex)+'\nThis might have broken the game state; please confirm and quit if so') await channel.send(f'```{board}```') await channel.send(end) rancegames.pop(channel.id) async def getnp(question,players,formats,conditions): # Each condition is a function that will return a string if the content failed validation. # That string should be fired back to the user, for them to retry. # The conditions should accept a string. solos=[get1p(question,players[i],formats[i],conditions) for i in range(len(players))] return [n.content.replace(' ',' ') for n in await asyncio.gather(*solos)] async def get1p(question,player,forma,conditions): # Probably easier to do it like this. await player.send(question.format(*forma)) valid=False while not valid: msg=await client.wait_for('message',check=lambda x:x.author.id==player.id and x.channel==x.author.dm_channel) content=msg.content.replace(' ',' ') valid=True for con in conditions: res=con(content) if res!=True: valid=False; await player.send(f"Please try again:\n{res}"); break return msg async def rancequit(args, channel, message): # Get noobed try: del rancegames[channel.id]; rancegames.pop(channel.id) except KeyError: pass # I might make this use the playrance function later. async def rancehack(args, channel, message): rancegames[channel.id]=board=automate.Board('a','b','','',{0:automate.unit.BattleUnit('tactician',1,9,3,9,400,4,{},'Ram'),2:automate.unit.BattleUnit('tactician',1,9,3,3,400,4,{},'Rem')},{4:automate.unit.BattleUnit('tactician',1,9,3,3,400,4,{},'Rom'), 2:automate.unit.BattleUnit('tactician',1,9,3,3,400,4,{},'Rim')}) board.turn=2 controller=board.controller() nl='\n' while True: if not rancestatus(channel.id,board): return # We can discard this during charged actions but if we don't get it shit goes wrong. try: active=next(controller) except StopIteration as ex: end=ex; break if active is None: # Charged action is happening. Don't wait for action or anything. action=None else: await channel.send(f'```{board}```') await channel.send(f"Available actions for {active[0][0]}'s unit {active[1]}:\n{nl.join([', '.join(n) for n in active[2]])}") msg=await client.wait_for('message',check=lambda x:x.author!=client.user and x.channel.id==channel.id and x.content.split(' ')[0] in [n[0] for n in active[2]]) action=msg.content.split(' ') res=controller.send(action); await channel.send(res) #except Exception as ex: await channel.send(str(ex)+'\nThis might have broken the game state; please confirm and quit if so') await channel.send(f'```{board}```') await channel.send(end) rancegames.pop(channel.id) def rancestatus(cid,seed): return cid in rancegames and rancegames[cid]==seed async def azul(args, channel, message): pass