class RaceRoom(command.Module): def get_new_raceinfo(): to_return = RaceInfo() to_return.seed_fixed = False to_return.seeded = True to_return.character = 'Cadence' to_return.descriptor = 'Condor Race' to_return.sudden_death = False to_return.flagplant = False to_return.seed = seedgen.get_new_seed() return to_return def __init__(self, condor_module, condor_match, race_channel): self.channel = race_channel #The channel in which this race is taking place self.is_closed = False #True if room has been closed self.match = condor_match self.events = Events() self.race = None #The current race self.recorded_race = False #Whether the current race has been recorded self.entered_racers = [] #Racers that have typed .here in this channel self.before_races = True self.cancelling_racers = [] #Racers that have typed .cancel self._cm = condor_module self.command_types = [command.DefaultHelp(self), Here(self), Ready(self), Unready(self), Done(self), Undone(self), Cancel(self), #Forfeit(self), #Unforfeit(self), #Comment(self), #Igt(self), Time(self), Contest(self), ForceCancel(self), ForceChangeWinner(self), #ForceClose(self), ForceForfeit(self), #ForceForfeitAll(self), ForceRecordRace(self), ForceNewRace(self), ForceCancelRace(self), ForceRecordMatch(self), #Kick(self), ] @property def infostr(self): return 'Race' @property def client(self): return self._cm.necrobot.client @property def necrobot(self): return self._cm.necrobot @property def condordb(self): return self._cm.condordb #True if the user has admin permissions for this race def is_race_admin(self, member): admin_roles = self._cm.necrobot.admin_roles for role in member.roles: if role in admin_roles: return True return False # Set up the leaderboard etc. Should be called after creation; code not put into __init__ b/c coroutine @asyncio.coroutine def initialize(self, users_to_mention=[]): yield from self.update_leaderboard() asyncio.ensure_future(self.countdown_to_match_start()) # Write text to the raceroom. Return a Message for the text written @asyncio.coroutine def write(self, text): return self.client.send_message(self.channel, text) # Write text to the bot_notifications channel. @asyncio.coroutine def alert_staff(self, text): return self.client.send_message(self._cm.necrobot.notifications_channel, text) # Register a racer as wanting to cancel @asyncio.coroutine def wants_to_cancel(self, member): for racer in self.match.racers: if int(racer.discord_id) == int(member.id) and not racer in self.cancelling_racers: self.cancelling_racers.append(racer) if len(self.cancelling_racers) == 2: yield from self.cancel_race() return True else: return False # Cancel the race @asyncio.coroutine def cancel_race(self): if self.race and not self.race.is_before_race: self.cancelling_racers = [] yield from self.race.cancel() yield from self.record_race(cancelled=True) yield from self.write('The current race was cancelled.') else: self.cancelling_racers = [] race_number = int(self._cm.condordb.largest_recorded_race_number(self.match)) if race_number > 0: self.condordb.cancel_race(self.match, race_number) yield from self.write('The previous race was cancelled.'.format(race_number)) yield from self.update_leaderboard() #Updates the leaderboard @asyncio.coroutine def update_leaderboard(self): if self.race or self.match.time_until_match.total_seconds() < 0: topic = '``` \n' topic += 'Necrodancer World Cup Match (Cadence Seeded)\n' max_name_len = 0 for racer in self.match.racers: max_name_len = max(max_name_len, len(racer.discord_name)) for racer in self.match.racers: wins = self._cm.condordb.number_of_wins(self.match, racer, count_draws=True) topic += ' ' + racer.discord_name + (' ' * (max_name_len - len(racer.discord_name))) + ' --- Wins: {0}\n'.format(str(round(wins,1) if wins % 1 else int(wins))) race_number = self._cm.condordb.number_of_finished_races(self.match) + 1 if race_number > config.RACE_NUMBER_OF_RACES: topic += 'Match complete. \n' else: topic += 'Current race: #{}\n'.format(race_number) if self.race: topic += self.race.leaderboard topic += '\n ```' asyncio.ensure_future(self.client.edit_channel(self.channel, topic=topic)) else: topic_str = '``` \n' minutes_until_match = int( (self.match.time_until_match.total_seconds() + 30) // 60 ) topic_str += 'The race is scheduled to begin in {0} minutes! Please let the bot know you\'re here by typing .here. \n\n'.format(minutes_until_match) waiting_str = '' if self.match.racer_1 not in self.entered_racers: waiting_str += self.match.racer_1.twitch_name + ', ' if self.match.racer_2 not in self.entered_racers: waiting_str += self.match.racer_2.twitch_name + ', ' topic_str += 'Still waiting for .here from: {0} \n'.format(waiting_str[:-2]) if waiting_str else 'Both racers are here!\n' topic_str += '```' asyncio.ensure_future(self.client.edit_channel(self.channel, topic=topic_str)) @asyncio.coroutine def alert_racers(self, send_pm=False): member_1 = self._cm.necrobot.find_member_with_id(self.match.racer_1.discord_id) member_2 = self._cm.necrobot.find_member_with_id(self.match.racer_2.discord_id) alert_str = '' if member_1: alert_str += member_1.mention + ', ' if member_2: alert_str += member_2.mention + ', ' minutes_until_match = int( (self.match.time_until_match.total_seconds() + 30) // 60 ) if alert_str: yield from self.write('{0}: The match is scheduled to begin in {1} minutes.'.format(alert_str[:-2], minutes_until_match)) if send_pm: if member_1: yield from self.client.send_message(member_1, '{0}: Your match with {1} is scheduled to begin in {2} minutes.'.format(member_1.mention, self.match.racer_2.escaped_twitch_name, minutes_until_match)) if member_2: yield from self.client.send_message(member_2, '{0}: Your match with {1} is scheduled to begin in {2} minutes.'.format(member_2.mention, self.match.racer_1.escaped_twitch_name, minutes_until_match)) @asyncio.coroutine def countdown_to_match_start(self): time_until_match = self.match.time_until_match asyncio.ensure_future(self.constantly_update_leaderboard()) if time_until_match < datetime.timedelta(seconds=0): if not self.played_all_races: yield from self.write('I believe that I was just restarted; an error may have occurred. I am beginning a new race and attempting to pick up this ' \ 'match where we left off. If this is an error, or if there are unrecorded races, please contact CoNDOR Staff (`.staff`).') yield from self.begin_new_race() else: pm_warning = datetime.timedelta(minutes=30) first_warning = datetime.timedelta(minutes=15) alert_staff_warning = datetime.timedelta(minutes=5) if time_until_match > pm_warning: yield from asyncio.sleep( (time_until_match - pm_warning).total_seconds() ) if not self.race: yield from self.alert_racers(send_pm=True) time_until_match = self.match.time_until_match if time_until_match > first_warning: yield from asyncio.sleep( (time_until_match - first_warning).total_seconds() ) if not self.race: yield from self.alert_racers() time_until_match = self.match.time_until_match if time_until_match > alert_staff_warning: yield from asyncio.sleep( (time_until_match - alert_staff_warning).total_seconds() ) # this is done at the alert_staff_warning, unless this function was called after the alert_staff_warning, in which case do it immediately if not self.race: yield from self.alert_racers() for racer in self.match.racers: if racer not in self.entered_racers: discord_name = '' if racer.discord_name: discord_name = ' (Discord name: {0})'.format(racer.discord_name) minutes_until_race = int( (self.match.time_until_match.total_seconds() + 30) // 60) yield from self.alert_staff('Alert: {0}{1} has not yet shown up for their match, which is scheduled in {2} minutes.'.format(racer.escaped_twitch_name, discord_name, minutes_until_race)) yield from self._cm.post_match_alert(self.match) yield from asyncio.sleep(self.match.time_until_match.total_seconds()) if not self.race: yield from self.begin_new_race() @asyncio.coroutine def constantly_update_leaderboard(self): while self.match.time_until_match.total_seconds() > 0: asyncio.ensure_future(self.update_leaderboard()) yield from asyncio.sleep(30) @asyncio.coroutine def begin_new_race(self): self.cancelling_racers = [] self.before_races = False self.race = Race(self, RaceRoom.get_new_raceinfo(), self._cm.condordb) yield from self.race.initialize() self.recorded_race = False for racer in self.match.racers: racer_as_member = self._cm.necrobot.find_member_with_id(racer.discord_id) if racer_as_member: yield from self.race.enter_racer(racer_as_member) else: yield from self.write('Error: Couldn\'t find the racer {0}. Please contact CoNDOR Staff (`.staff`).'.format(racer.escaped_twitch_name)) yield from self.update_leaderboard() race_number = int(self._cm.condordb.number_of_finished_races(self.match) + 1) race_str = '{}th'.format(race_number) if race_number == int(1): race_str = 'first' elif race_number == int(2): race_str = 'second' elif race_number == int(3): race_str = 'third' yield from self.write('Please input the seed ({1}) and type `.ready` when you are ready for the {0} race. '\ 'When both racers `.ready`, the race will begin.'.format(race_str, self.race.race_info.seed)) # Returns true if all racers are ready @property def all_racers_ready(self): return self.race and self.race.num_not_ready == 0 @property def played_all_races(self): if self.match.is_best_of: return self._cm.condordb.number_of_wins_of_leader(self.match) >= (self.match.number_of_races//2 + 1) else: return self._cm.condordb.number_of_finished_races(self.match) >= self.match.number_of_races @property def race_to_contest(self): if not self.race: return 0 if self.race.is_before_race: return self.race_number - 1 else: return self.race_number # Begins the race if ready. (Writes a message if all racers are ready but an admin is not.) # Returns true on success @asyncio.coroutine def begin_if_ready(self): if self.race and self.all_racers_ready: yield from self.race.begin_race_countdown() return True @asyncio.coroutine def enter_racer(self, member): for racer in self.match.racers: if int(racer.discord_id) == int(member.id): if racer in self.entered_racers: yield from self.write('{0} is already here.'.format(member.mention)) return self.entered_racers.append(racer) yield from self.write('{0} is here for the race.'.format(member.mention)) yield from self.update_leaderboard() return yield from self.write('{0}: I do not recognize you as one of the racers in this match. Contact CoNDOR Staff (`.staff`) if this is in error.'.format(member.mention)) @asyncio.coroutine def record_race(self, cancelled=False): if self.race and self.race.start_time: self.recorded_race = True racer_1_time = -1 racer_2_time = -1 racer_1_finished = False racer_2_finished = False for racer in self.race.racer_list: if int(racer.id) == int(self.match.racer_1.discord_id): if racer.is_finished: racer_1_time = racer.time racer_1_finished = True elif int(racer.id) == int(self.match.racer_2.discord_id): if racer.is_finished: racer_2_time = racer.time racer_2_finished = True winner = 0 if racer_1_finished and not racer_2_finished: winner = 1 elif not racer_1_finished and racer_2_finished: winner = 2 elif racer_1_finished and racer_2_finished: if racer_1_time < racer_2_time: winner = 1 elif racer_2_time < racer_1_time: winner = 2 if abs(racer_1_time - racer_2_time) <= (config.RACE_NOTIFY_IF_TIMES_WITHIN_SEC*100): race_number = self._cm.condordb.number_of_finished_races(self.match) + 1 yield from self.client.send_message(self.necrobot.notifications_channel, 'Race number {0} has finished within {1} seconds in channel {2}. ({3} -- {4}, {5} -- {6})'.format( race_number, config.RACE_NOTIFY_IF_TIMES_WITHIN_SEC, self.channel.mention, self.match.racer_1.escaped_twitch_name, racetime.to_str(racer_1_time), self.match.racer_2.escaped_twitch_name, racetime.to_str(racer_2_time))) self._cm.condordb.record_race(self.match, racer_1_time, racer_2_time, winner, self.race.race_info.seed, self.race.start_time.timestamp(), cancelled) if not cancelled: racer_1_member = self.necrobot.find_member_with_id(self.match.racer_1.discord_id) racer_2_member = self.necrobot.find_member_with_id(self.match.racer_2.discord_id) racer_1_mention = racer_1_member.mention if racer_1_member else '' racer_2_mention = racer_2_member.mention if racer_2_member else '' write_str = '{0}, {1}: The race is over, and has been recorded.'.format(racer_1_mention, racer_2_mention) else: write_str = 'Race cancelled.' yield from self.write(write_str) yield from self.write('If you wish to contest the previous race\'s result, use the `.contest` command. This marks the race as contested; CoNDOR Staff will be alerted, and will ' 'look into your race.') if self.played_all_races: #Send match ending event if all races have been played self.events.matchend(self.match.racer_1.twitch_name, self.match.racer_2.twitch_name) yield from self.record_match() else: yield from self.begin_new_race() @asyncio.coroutine def record_match(self): self._cm.condordb.record_match(self.match) yield from self._cm.condorsheet.record_match(self.match) yield from self.write('Match results recorded.') yield from self.update_leaderboard()
class RaceRoom(command.Module): def get_new_raceinfo(): to_return = RaceInfo() to_return.seed_fixed = False to_return.seeded = True to_return.character = 'Cadence' to_return.descriptor = 'Condor Race' to_return.sudden_death = False to_return.flagplant = False to_return.seed = seedgen.get_new_seed() return to_return def __init__(self, condor_module, condor_match, race_channel): self.channel = race_channel #The channel in which this race is taking place self.is_closed = False #True if room has been closed self.match = condor_match self.race = None #The current race self.recorded_race = False #Whether the current race has been recorded self.entered_racers = [] #Racers that have typed .here in this channel self.before_races = True self.cancelling_racers = [] #Racers that have typed .cancel self._cm = condor_module self.command_types = [command.DefaultHelp(self), Here(self), Ready(self), Unready(self), Done(self), Undone(self), Cancel(self), #Forfeit(self), #Unforfeit(self), #Comment(self), #Igt(self), Time(self), Contest(self), ForceCancel(self), ForceChangeWinner(self), #ForceClose(self), ForceForfeit(self), #ForceForfeitAll(self), ForceRecordRace(self), ForceNewRace(self), ForceCancelRace(self), ForceRecordMatch(self), #Kick(self), ] @property def infostr(self): return 'Race' @property def client(self): return self._cm.necrobot.client @property def necrobot(self): return self._cm.necrobot @property def condordb(self): return self._cm.condordb #True if the user has admin permissions for this race def is_race_admin(self, member): admin_roles = self._cm.necrobot.admin_roles for role in member.roles: if role in admin_roles: return True return False # Set up the leaderboard etc. Should be called after creation; code not put into __init__ b/c coroutine @asyncio.coroutine def initialize(self, users_to_mention=[]): yield from self.update_leaderboard() asyncio.ensure_future(self.countdown_to_match_start()) # Write text to the raceroom. Return a Message for the text written @asyncio.coroutine def write(self, text): return self.client.send_message(self.channel, text) # Write text to the bot_notifications channel. @asyncio.coroutine def alert_staff(self, text): return self.client.send_message(self._cm.necrobot.notifications_channel, text) # Register a racer as wanting to cancel @asyncio.coroutine def wants_to_cancel(self, member): for racer in self.match.racers: if int(racer.discord_id) == int(member.id) and not racer in self.cancelling_racers: self.cancelling_racers.append(racer) if len(self.cancelling_racers) == 2: yield from self.cancel_race() return True else: return False # Cancel the race @asyncio.coroutine def cancel_race(self): if self.race and not self.race.is_before_race: self.cancelling_racers = [] yield from self.race.cancel() yield from self.record_race(cancelled=True) yield from self.write('The current race was cancelled.') else: self.cancelling_racers = [] race_number = int(self._cm.condordb.largest_recorded_race_number(self.match)) if race_number > 0: self.condordb.cancel_race(self.match, race_number) yield from self.write('The previous race was cancelled.'.format(race_number)) yield from self.update_leaderboard() #Updates the leaderboard @asyncio.coroutine def update_leaderboard(self): if self.race or self.match.time_until_match.total_seconds() < 0: topic = '``` \n' topic += 'Necrodancer World Cup Match (Cadence Seeded)\n' max_name_len = 0 for racer in self.match.racers: max_name_len = max(max_name_len, len(racer.discord_name)) for racer in self.match.racers: wins = self._cm.condordb.number_of_wins(self.match, racer, count_draws=True) topic += ' ' + racer.discord_name + (' ' * (max_name_len - len(racer.discord_name))) + ' --- Wins: {0}\n'.format(str(round(wins,1) if wins % 1 else int(wins))) race_number = self._cm.condordb.number_of_finished_races(self.match) + 1 if race_number > config.RACE_NUMBER_OF_RACES: topic += 'Match complete. \n' else: topic += 'Current race: #{}\n'.format(race_number) if self.race: topic += self.race.leaderboard topic += '\n ```' asyncio.ensure_future(self.client.edit_channel(self.channel, topic=topic)) else: topic_str = '``` \n' minutes_until_match = int( (self.match.time_until_match.total_seconds() + 30) // 60 ) topic_str += 'The race is scheduled to begin in {0} minutes! Please let the bot know you\'re here by typing .here. \n\n'.format(minutes_until_match) waiting_str = '' if self.match.racer_1 not in self.entered_racers: waiting_str += self.match.racer_1.twitch_name + ', ' if self.match.racer_2 not in self.entered_racers: waiting_str += self.match.racer_2.twitch_name + ', ' topic_str += 'Still waiting for .here from: {0} \n'.format(waiting_str[:-2]) if waiting_str else 'Both racers are here!\n' topic_str += '```' asyncio.ensure_future(self.client.edit_channel(self.channel, topic=topic_str)) @asyncio.coroutine def alert_racers(self, send_pm=False): member_1 = self._cm.necrobot.find_member_with_id(self.match.racer_1.discord_id) member_2 = self._cm.necrobot.find_member_with_id(self.match.racer_2.discord_id) alert_str = '' if member_1: alert_str += member_1.mention + ', ' if member_2: alert_str += member_2.mention + ', ' minutes_until_match = int( (self.match.time_until_match.total_seconds() + 30) // 60 ) if alert_str: yield from self.write('{0}: The match is scheduled to begin in {1} minutes.'.format(alert_str[:-2], minutes_until_match)) if send_pm: if member_1: yield from self.client.send_message(member_1, '{0}: Your match with {1} is scheduled to begin in {2} minutes.'.format(member_1.mention, self.match.racer_2.escaped_twitch_name, minutes_until_match)) if member_2: yield from self.client.send_message(member_2, '{0}: Your match with {1} is scheduled to begin in {2} minutes.'.format(member_2.mention, self.match.racer_1.escaped_twitch_name, minutes_until_match)) @asyncio.coroutine def countdown_to_match_start(self): time_until_match = self.match.time_until_match asyncio.ensure_future(self.constantly_update_leaderboard()) if time_until_match < datetime.timedelta(seconds=0): if not self.played_all_races: yield from self.write('I believe that I was just restarted; an error may have occurred. I am beginning a new race and attempting to pick up this ' \ 'match where we left off. If this is an error, or if there are unrecorded races, please contact CoNDOR Staff (`.staff`).') yield from self.begin_new_race() else: pm_warning = datetime.timedelta(minutes=30) first_warning = datetime.timedelta(minutes=15) alert_staff_warning = datetime.timedelta(minutes=5) if time_until_match > pm_warning: yield from asyncio.sleep( (time_until_match - pm_warning).total_seconds() ) if not self.race: yield from self.alert_racers(send_pm=True) time_until_match = self.match.time_until_match if time_until_match > first_warning: yield from asyncio.sleep( (time_until_match - first_warning).total_seconds() ) if not self.race: yield from self.alert_racers() time_until_match = self.match.time_until_match if time_until_match > alert_staff_warning: yield from asyncio.sleep( (time_until_match - alert_staff_warning).total_seconds() ) # this is done at the alert_staff_warning, unless this function was called after the alert_staff_warning, in which case do it immediately if not self.race: yield from self.alert_racers() for racer in self.match.racers: if racer not in self.entered_racers: discord_name = '' if racer.discord_name: discord_name = ' (Discord name: {0})'.format(racer.discord_name) minutes_until_race = int( (self.match.time_until_match.total_seconds() + 30) // 60) yield from self.alert_staff('Alert: {0}{1} has not yet shown up for their match, which is scheduled in {2} minutes.'.format(racer.escaped_twitch_name, discord_name, minutes_until_race)) yield from self._cm.post_match_alert(self.match) yield from asyncio.sleep(self.match.time_until_match.total_seconds()) if not self.race: yield from self.begin_new_race() @asyncio.coroutine def constantly_update_leaderboard(self): while self.match.time_until_match.total_seconds() > 0: asyncio.ensure_future(self.update_leaderboard()) yield from asyncio.sleep(30) @asyncio.coroutine def begin_new_race(self): self.cancelling_racers = [] self.before_races = False self.race = Race(self, RaceRoom.get_new_raceinfo()) yield from self.race.initialize() self.recorded_race = False for racer in self.match.racers: racer_as_member = self._cm.necrobot.find_member_with_id(racer.discord_id) if racer_as_member: yield from self.race.enter_racer(racer_as_member) else: yield from self.write('Error: Couldn\'t find the racer {0}. Please contact CoNDOR Staff (`.staff`).'.format(racer.escaped_twitch_name)) yield from self.update_leaderboard() race_number = int(self._cm.condordb.number_of_finished_races(self.match) + 1) race_str = '{}th'.format(race_number) if race_number == int(1): race_str = 'first' elif race_number == int(2): race_str = 'second' elif race_number == int(3): race_str = 'third' yield from self.write('Please input the seed ({1}) and type `.ready` when you are ready for the {0} race. '\ 'When both racers `.ready`, the race will begin.'.format(race_str, self.race.race_info.seed)) # Returns true if all racers are ready @property def all_racers_ready(self): return self.race and self.race.num_not_ready == 0 @property def played_all_races(self): if self.match.is_best_of: return self._cm.condordb.number_of_wins_of_leader(self.match) >= (self.match.number_of_races//2 + 1) else: return self._cm.condordb.number_of_finished_races(self.match) >= self.match.number_of_races @property def race_to_contest(self): if not self.race: return 0 if self.race.is_before_race: return self.race_number - 1 else: return self.race_number # Begins the race if ready. (Writes a message if all racers are ready but an admin is not.) # Returns true on success @asyncio.coroutine def begin_if_ready(self): if self.race and self.all_racers_ready: yield from self.race.begin_race_countdown() return True @asyncio.coroutine def enter_racer(self, member): for racer in self.match.racers: if int(racer.discord_id) == int(member.id): if racer in self.entered_racers: yield from self.write('{0} is already here.'.format(member.mention)) return self.entered_racers.append(racer) yield from self.write('{0} is here for the race.'.format(member.mention)) yield from self.update_leaderboard() return yield from self.write('{0}: I do not recognize you as one of the racers in this match. Contact CoNDOR Staff (`.staff`) if this is in error.'.format(member.mention)) @asyncio.coroutine def record_race(self, cancelled=False): if self.race and self.race.start_time: self.recorded_race = True racer_1_time = -1 racer_2_time = -1 racer_1_finished = False racer_2_finished = False for racer in self.race.racer_list: if int(racer.id) == int(self.match.racer_1.discord_id): if racer.is_finished: racer_1_time = racer.time racer_1_finished = True elif int(racer.id) == int(self.match.racer_2.discord_id): if racer.is_finished: racer_2_time = racer.time racer_2_finished = True winner = 0 if racer_1_finished and not racer_2_finished: winner = 1 elif not racer_1_finished and racer_2_finished: winner = 2 elif racer_1_finished and racer_2_finished: if racer_1_time < racer_2_time: winner = 1 elif racer_2_time < racer_1_time: winner = 2 if abs(racer_1_time - racer_2_time) <= (config.RACE_NOTIFY_IF_TIMES_WITHIN_SEC*100): race_number = self._cm.condordb.number_of_finished_races(self.match) + 1 yield from self.client.send_message(self.necrobot.notifications_channel, 'Race number {0} has finished within {1} seconds in channel {2}. ({3} -- {4}, {5} -- {6})'.format( race_number, config.RACE_NOTIFY_IF_TIMES_WITHIN_SEC, self.channel.mention, self.match.racer_1.escaped_twitch_name, racetime.to_str(racer_1_time), self.match.racer_2.escaped_twitch_name, racetime.to_str(racer_2_time))) self._cm.condordb.record_race(self.match, racer_1_time, racer_2_time, winner, self.race.race_info.seed, self.race.start_time.timestamp(), cancelled) if not cancelled: racer_1_member = self.necrobot.find_member_with_id(self.match.racer_1.discord_id) racer_2_member = self.necrobot.find_member_with_id(self.match.racer_2.discord_id) racer_1_mention = racer_1_member.mention if racer_1_member else '' racer_2_mention = racer_2_member.mention if racer_2_member else '' write_str = '{0}, {1}: The race is over, and has been recorded.'.format(racer_1_mention, racer_2_mention) else: write_str = 'Race cancelled.' yield from self.write(write_str) yield from self.write('If you wish to contest the previous race\'s result, use the `.contest` command. This marks the race as contested; CoNDOR Staff will be alerted, and will ' 'look into your race.') if self.played_all_races: yield from self.record_match() else: yield from self.begin_new_race() @asyncio.coroutine def record_match(self): self._cm.condordb.record_match(self.match) yield from self._cm.condorsheet.record_match(self.match) yield from self.write('Match results recorded.') yield from self.update_leaderboard()