async def on_pick(self, ctx, member: discord.Member): if not self.model.ChkIsReg(ctx): return choosingId = ctx.message.author.id choosingPlayer = ctx.message.author.name pickedId = member.id pickedPlayer = member.name game = await self.can_pick(ctx, choosingId, choosingPlayer, pickedId) if not game: return if game.playerTurn.id != choosingId: await ctx.send(CodeSB(f'Not your turn to pick')) return None if pickedId not in game.PoolIds: await ctx.send(CodeSB(f"{pickedPlayer} not in player pool")) return if game.state == State.IN_GAME: await ctx.send(CodeSB(f'Game already running')) return None await self.model.PickPlayer(ctx, game, choosingPlayer, pickedId, pickedPlayer)
async def RemPlayerQueue(self, ctx, playerName, playerId, region: Region): if self.queues.remove_all_of(region.region, playerId): embed = discord.Embed(colour=discord.Colour.blue(), description=self.QueueStatus()) await ctx.channel.send(content=CodeSB( f'{playerName} removed from: {", ".join(region.ToList())}'), embed=embed) else: await ctx.send(CodeSB(f'{playerName} not queued on any region'))
async def can_pick(self, ctx, choosingId, choosingPlayer, pickedId): if not (self.model.ChkIsRegId(choosingId) and self.model.ChkIsRegId(pickedId)): return None region = self.model.RegFromPlayer(choosingId) if region == None: await ctx.send(CodeSB(f'Must be a captain in order to pick')) return None if choosingId == pickedId: await ctx.send(CodeSB(f'Cannot pick self')) return None return self.model.games[region]
async def StartGame(self, ctx, game): zerg = [(self.IdToUser(id), id) for id in game.zerg.Ids] terran = [(self.IdToUser(id), id) for id in game.terran.Ids] zergNames = ", ".join( map(lambda memtup: Model.UserToName(memtup[0], memtup[1]), zerg)) terranNames = ", ".join( map(lambda memtup: Model.UserToName(memtup[0], memtup[1]), terran)) zergMentions = " ".join( map(lambda memtup: Model.UserToMention(memtup[0], memtup[1]), zerg)) terranMentions = " ".join( map(lambda memtup: Model.UserToMention(memtup[0], memtup[1]), terran)) description = f''' One captain start a prepicked lobby and arrange teams and report back the result of the game with < !rw/!rl/!rt > <Zerg> {zergNames} <Terran> {terranNames} ''' embed = discord.Embed(description=CodeB(description, 'md'), colour=discord.Colour.blue()) await ctx.channel.send( content=CodeSB(f"Game Starting on {game.region}") + f' {zergMentions} {terranMentions}', embed=embed) await self.CreateVoice(game)
async def on_set_stats(self, ctx, member: discord.Member, region: Region, race: Race, wins: int, loses: int, ties: int): playerName = member.name regions = region.ToList() races = race.ToList() for reg in regions: usPlayer = self.model.playerDB.Find(member.id, reg) if usPlayer == None: await ctx.send(f'Player {playerName} not registered') return if not usPlayer.lastPlayed: usPlayer.SetPlayed() for r in races: usPlayer.wins[r] = wins usPlayer.loses[r] = loses usPlayer.ties[r] = ties self.model.playerDB.UpdateStats(usPlayer) await ctx.send( CodeSB( f"Updated {playerName}'s wins={usPlayer.wins[races[0]]}, loses={usPlayer.loses[races[0]]}, ties={usPlayer.ties[races[0]]} for {', '.join(races)} on {', '.join(regions)}" ))
async def on_queue_flush(self, ctx, region: Region = Region(Region.ALL)): self.model.queues.clear(region.region) embed = discord.Embed(colour=discord.Colour.blue(), description=self.model.QueueStatus()) await ctx.channel.send( content=CodeSB(f'Queues cleared on: {", ".join(region.ToList())}'), embed=embed)
async def on_queue_bot(self, ctx, region: Region, count: int): await self.model.CreateStubs(ctx, region, count) embed = discord.Embed(colour=discord.Colour.blue(), description=self.model.QueueStatus()) await ctx.channel.send( content=CodeSB(f'Queued {count} bots on {region.region}'), embed=embed)
async def ValidateReg(self, ctx, region): if not Region.Valid(region): await ctx.send( CodeSB( f'Invalid region, expected: {"/".join(Region.VALID_REGIONS)}' )) return False return True
async def ReportMatchResult(self, ctx, res, playerId): region = self.RegFromPlayer(playerId) if region == None: await ctx.send( CodeSB(f'Must be a captain in order to report match result')) return game = self.games[region] if game == None or game.state != State.IN_GAME: await ctx.send(CodeSB(f'Cannot report result of non-running game')) return oldZElo = [(self.IdToName(player.id), int(player.zelo)) for player in game.zerg.players] oldTElo = [(self.IdToName(player.id), int(player.telo)) for player in game.terran.players] game.MatchResult(playerId, res) for player in itertools.chain(game.zerg.players, game.terran.players): self.playerDB.UpdatePlayer(player) newZElo = [(self.IdToName(player.id), int(player.zelo)) for player in game.zerg.players] newTElo = [(self.IdToName(player.id), int(player.telo)) for player in game.terran.players] embed = discord.Embed( description=f"Victor: {game.GetVictor(playerId, res)}", colour=discord.Colour.blue()) nameMax = max(len(name) for name, _ in oldZElo) strZUpdElos = '\n'.join([ f'{oldElo[0].ljust(nameMax)}: {oldElo[1]} -> {newElo[1]}' for oldElo, newElo in zip(oldZElo, newZElo) ]) strTUpdElos = '\n'.join([ f'{oldElo[0].ljust(nameMax)}: {oldElo[1]} -> {newElo[1]}' for oldElo, newElo in zip(oldTElo, newTElo) ]) embed.add_field(name="Updated Z elo's: ", value=strZUpdElos) embed.add_field(name="Updated T elo's: ", value=strTUpdElos) await ctx.channel.send( content=CodeSB(f"Match Concluded on {game.region}"), embed=embed) await self.EndMatch(ctx, game)
async def RemPlayerSub(self, ctx, playerName, playerId, region: Region): regions = region.ToList() for reg in regions: self.subs[reg].discard(playerId) await ctx.send( CodeSB( f'{playerName} no longer avaiable to sub on {", ".join(regions)}' ))
async def on_register(self, ctx): playerId = ctx.message.author.id playerName = ctx.message.author.name registeredRegs = [] for reg in Region.REGIONS: res = self.model.playerDB.IsRegistered(playerId, reg) if not res: self.model.playerDB.Register(Player(playerId, reg)) registeredRegs.append(reg) if len(registeredRegs) == 0: await ctx.send(CodeSB(f'{playerName} already registered')) return else: await ctx.send( CodeSB( f'{playerName} successfully registered on {", ".join(registeredRegs)}' ))
async def on_cancel_match(self, ctx): if not self.model.ChkIsReg(ctx): return invokingId = ctx.message.author.id invokingPlayer = ctx.message.author.name region = self.model.RegFromPlayer(invokingId) if region == None: await ctx.send(CodeSB(f'Must be a captain in order to cancel')) return game = self.model.games[region] otherCaptId = game.terranCapt.id if game.zergCapt.id == invokingId else game.zergCapt.id otherCaptMent = self.model.IdToMention(otherCaptId) REQUEST_TIMEOUT = 60 await ctx.send( CodeSB(f'{invokingPlayer} attempting to cancel game on {region}.') + f'{otherCaptMent} `respond with y/n`') def check(msg): response = msg.content.lower() return msg.author.id == otherCaptId and response in ['y', 'n'] try: msg = await self.model.bot.wait_for("message", check=check, timeout=REQUEST_TIMEOUT) except asyncio.TimeoutError: await ctx.send(CodeSB(f"Cancelation request on {region} timed out") ) else: if msg.content == 'y': await self.model.EndMatch(ctx, game) await ctx.send( CodeSB(f"Cancelation on {region} was successfull")) else: await ctx.send( CodeSB(f"Cancelation on {region} was not successfull"))
async def AddPlayerSub(self, ctx, playerName, playerId, region: Region): regions = region.ToList() if any((self.games[reg] and (playerId in self.games[reg].AllPlayers) for reg in regions)): await ctx.send(CodeSB(f'Cannot sub when in game or in player pool') ) return subbedRegs = [] for reg in regions: if self.games[reg]: self.subs[reg].add(playerId) subbedRegs.append(reg) if len(subbedRegs) == 0: await ctx.send(CodeSB(f'No game found to sub/already in a pool')) else: await ctx.send( CodeSB( f'{playerName} now avaiable to sub on {", ".join(subbedRegs)}' ))
async def on_qracepref(self, ctx, region: Region = Region(Region.ALL)): if not self.model.ChkIsReg(ctx): return playerId = ctx.message.author.id playerName = ctx.message.author.name regions = region.ToList() racePrefs = dict() for reg in regions: usPlayer = self.model.playerDB.Find(playerId, reg) if usPlayer == None: await ctx.send(CodeSB(f'Player {playerName} not registered')) racePrefs[reg] = usPlayer.racePref racePrefStr = [ f'{reg}: {pref.race}' for reg, pref in racePrefs.items() ] await ctx.send( CodeSB(f"{playerName}'s race preference: {', '.join(racePrefStr)}") )
async def on_set_elo(self, ctx, member: discord.Member, region: Region, race: Race, elo: float): playerName = member.name regions = region.ToList() races = race.ToList() for reg in regions: usPlayer = self.model.playerDB.Find(member.id, reg) if usPlayer == None: await ctx.send(CodeSB(f'Player {playerName} not registered')) return if not usPlayer.lastPlayed: usPlayer.SetPlayed() for r in races: usPlayer.elo[r] = elo self.model.playerDB.UpdateStats(usPlayer) await ctx.send( CodeSB( f"Updated {playerName}'s elo to {usPlayer.elo[races[0]]} for {', '.join(races)} on {', '.join(regions)}" ))
async def on_set_racepref(self, ctx, racePref: Race, region: Region = Region(Region.ALL)): if not self.model.ChkIsReg(ctx): return playerId = ctx.message.author.id playerName = ctx.message.author.name regions = region.ToList() for reg in regions: usPlayer = self.model.playerDB.Find(playerId, reg) if usPlayer == None: await ctx.send(CodeSB(f'Player {playerName} not registered')) usPlayer.racePref = racePref self.model.playerDB.UpdateStats(usPlayer) await ctx.send( CodeSB( f"{playerName}'s race preference updated to {racePref.race} on {', '.join(regions)}" ))
async def pick_timeout(self): remQueues = dict() for reg, queue in self.queues: for id, timeQueued in queue.copy().items(): timeDelta = (datetime.now() - timeQueued).total_seconds() / 60.0 if timeDelta > Model.QUEUE_TIMEOUT: self.queues.remove(reg, id) playerName = self.IdToName(id) remQueues.setdefault(playerName, []) remQueues[playerName].append(reg) if len(remQueues) != 0: description = "" for playerName, regSet in remQueues.items(): description += f"-{playerName} timed out and removed from {', '.join(regSet)}\n" #description += f"\n\n{self.QueueStatus()}" embed = discord.Embed(colour=discord.Colour.blue(), description=CodeB(description, "diff")) await self.privChannel.send(content=CodeSB(self.QueueStatus()), embed=embed)
async def ShowTeamPickInfo(self, ctx, game, pingCapts=False): playerPool = ', '.join( f'{self.IdToName(player.id)}({player.racePref.race})' for player in list(game.PoolPlayers)) zCapt = self.IdToMention( game.zergCapt.id ) if pingCapts else f"`{self.IdToName(game.zergCapt.id)}`" tCapt = self.IdToMention( game.terranCapt.id ) if pingCapts else f"`{self.IdToName(game.terranCapt.id)}`" embed = discord.Embed(colour=discord.Colour.blue()) embed.add_field(name=f"{self.IdToName(game.playerTurn.id)}'s pick", value=CodeB(f'<Pool> {playerPool}', 'md')) zerg = self.IdsToNames(game.zerg.Ids) terran = self.IdsToNames(game.terran.Ids) embed.add_field(name="Teams", value=CodeB(f"<Zerg> {zerg}\n<Terran> {terran}", 'md')) await ctx.channel.send( content=CodeSB(f'Picking teams on {game.region}') + f' - Captains - <Zerg> {zCapt} | <Terran> {tCapt}', embed=embed)
async def AddPlayerQueue(self, ctx, playerName, playerId, region: Region, showStatus=True): regions = region.ToList() regionsAddedTo = [] for reg in regions: if playerId not in self.queues[reg]: if not any((self.games[newReg] != None and self.games[newReg].IsPlaying(playerId) \ for newReg in Region.REGIONS)): self.queues.add(reg, playerId) regionsAddedTo.append(reg) if self.queues.is_full(reg): if self.games[reg]: # await ctx.send(CodeSB(f'Game on {reg} already running... waiting until it ends')) return for remReg in [r for r in regions if r != reg]: if playerId in self.queues[remReg]: self.queues.remove(remReg, playerId) if showStatus: await self.ShowAddQueueStatus( ctx, playerName, [reg]) await self.StartTeamPick(ctx, reg) return if len(regionsAddedTo) == 0: await ctx.send( CodeSB(f'{playerName} already added to {", ".join(regions)}')) return if showStatus: await self.ShowAddQueueStatus(ctx, playerName, regionsAddedTo)
async def on_sub(self, ctx, memSub: discord.Member, memSubWith: discord.Member): if not (self.model.ChkIsRegId(memSub.id) and self.model.ChkIsRegId(memSubWith.id)): await ctx.send(f'`All subbed players must be registered`') choosingId = ctx.message.author.id choosingPlayer = ctx.message.author.name game = await self.can_pick(ctx, choosingId, choosingPlayer, memSubWith.id) if not game: return if any(self.model.games[reg] and self.model.games[reg].IsPlaying(memSubWith.id) for reg in Region.REGIONS): await ctx.send(f"`{memSubWith.name} already in game/player pool`") return if memSubWith.id not in self.model.subs[game.region]: await ctx.send( CodeSB( f"{memSubWith.name} has not agreed to sub (they can allow themself sub via !sub <region>" )) return #must validate memSubWith.id not in another game already but should already be handled with above check pSubWith = self.model.playerDB.Find(memSubWith.id, game.region) game.Sub(memSub.id, pSubWith) await ctx.send( f'`{memSub.name} subbed with {memSubWith.name} on {game.region}`') if game.state != State.IN_GAME: await self.model.PickPlayer(ctx, game, choosingPlayer, memSubWith.id, memSubWith.name)
async def on_force_end(self, ctx, region: Region = Region(Region.ALL)): for reg in region.ToList(): if self.model.games[reg]: await self.model.EndMatch(ctx, self.model.games[reg]) await ctx.send(CodeSB(f"Match Concluded on {reg}"))
async def ShowAddQueueStatus(self, ctx, playerName, regionsAddedTo): embed = discord.Embed(description=self.QueueStatus(), colour=discord.Colour.blue()) await ctx.channel.send(content=CodeSB( f'{playerName} added to: {", ".join(regionsAddedTo)}'), embed=embed)