Пример #1
0
 def __init__(self):
     Race.__init__(self)
     self.intelligence = 1
     self.charisma = 2
     self.languages = ['Common', 'Infernal']
     self.features = ['Darkvision', 'Hellish Resistance', 'Infernal Legacy']
     self.cantrips = ['Thaumaturgy']
Пример #2
0
def main():
    """The main entry point for the turtle game"""
    race_meet = RaceMeet()
    print("Race name: {}".format(race_meet.name))
    print("Race length: {} metres".format(race_meet.length))
    print("Number of competitors: {}\n".format(
        race_meet.number_of_competitors))

    competitors = generate_competitor_list(race_meet.number_of_competitors)

    race = Race()
    competitor_times = {}

    for i in range(0, len(competitors)):
        try:
            total_time_for_competitor = (race.get_total_time_for_turtle(
                competitors[i].speed, competitors[i].stamina,
                race_meet.length))
        except TurtleHasNoEnergyError:
            print(("Competitor {}: {} didn't have the energy to complete the "
                   "race...").format(i + 1, competitors[i].name))
            continue
        competitor_times[competitors[i].name] = total_time_for_competitor
        print(("Competitor {}: "
               "{} ran the race in {} seconds").format(
                   i + 1, competitors[i].name, total_time_for_competitor))
Пример #3
0
class Character:
    ''' This class should hold information about each character made using the generator '''
    def __init__(self, name_in):
        self.name = name_in
        self.stats = {
            "str": 0,
            "dex": 0,
            "con": 0,
            "wis": 0,
            "int": 0,
            "cha": 0
        }
        self.species = Race()
        print("Creating character: ", self.name)

    def roll_stats(self):
        '''Function to generate random stats'''
        keys = list(self.stats)
        for i in range(6):
            # Roll 4d6, drop the lowest
            dice = []
            for j in range(4):
                dice.append(random.randint(1, 6))
            dice.remove(min(dice))
            self.stats[keys[i]] = sum(dice)
        print("Random Stats = ", self.stats)

    def generate(self):
        ''' Function to generate a full character '''
        self.roll_stats()
        self.species.generate()
Пример #4
0
 def start(self, champ_name, champ_races):
     championship = Championship(champ_name, int(champ_races))
     race = Race(self.__drivers(), round(random.uniform(1.00, 1.60), 2))
     print(championship)
     print(race)
     print(championship.start(race.start_race()))
     self.__store_results(championship.total)
    def __init__(self):
        with open("conf/filepaths.yaml") as filepath_config:
            self.conf = yaml.safe_load(filepath_config)
        self.sheet_stuff = utils.load_json(self.conf["CHARACTER_STATS_PATH"])
        self.all_items = utils.load_json(self.conf["ITEM_PATH"])
        self.clss = PlayerClass(
            self.sheet_stuff["saving_throws"],
            utils.load_json(self.conf["ITEM_PATH"]),
            *utils.select_random_from_json(self.conf["PLAYER_CLASS_PATH"]),
        )
        self.stats = sheet_maths.generate_stats()
        self.race = Race(
            *utils.select_random_from_json(self.conf["RACES_PATH"]))
        self.finalise_stats()
        self.mods = sheet_maths.generate_mods(self.stats)
        self.saves = sheet_maths.generate_saves(self.mods, self.clss.saves,
                                                self.clss.proficiency_bonus)
        self.weapons = self.finalise_weapons()
        self.bg = Background(
            *utils.select_random_from_json(self.conf["BACKGROUND_PATH"]))
        self.final_languages = self.select_languages()

        self.final_profs = self.select_profs()
        self.final_skills = self.select_skills()
        self.ac = self.finalise_ac()
        if "Perception" in self.final_skills:
            self.pp = self.mods["WISmod"] + self.clss.proficiency_bonus + 10
        else:
            self.pp = self.mods["WISmod"] + 10
Пример #6
0
    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))
Пример #7
0
    def __init__(self, name):
        self.name = name
        self.class_name = self.chooseClass()
        self.race = Race()
        self.rolls = []
        self.scores = {
            'Strength': 0,
            'Dexterity': 0,
            'Constitution': 0,
            'Intelligence': 0,
            'Wisdom': 0,
            'Charisma': 0,
        }

        self.rollStats()
        self.assignScores()

        self.modifiers = {
            'Strength': 0,
            'Dexterity': 0,
            'Constitution': 0,
            'Intelligence': 0,
            'Wisdom': 0,
            'Charisma': 0,
        }
        self.getMods()
        self.printStats()
Пример #8
0
 def __init__(self, ancestry):
     Race.__init__(self)
     self.strength = 2
     self.charisma = 1
     self.languages = ['Common', 'Draconic']
     self.features = [
         'Draconic Ancestry: ' + ancestry, 'Breath Weapon',
         'Damage Resistance(' + ancestry + ')'
     ]
Пример #9
0
 def __init__(self):
     Race.__init__(self)
     self.strength = 2
     self.constitution = 1
     self.languages = ['Common', 'Orc']
     self.features = [
         'Darkvision', 'Relentless Endurance', 'Savage Attacks'
     ]
     self.proficiencies = ['Intimidation']
Пример #10
0
 def __init__(self, language):
     Race.__init__(self)
     self.strength = 1
     self.dexterity = 1
     self.constitution = 1
     self.intelligence = 1
     self.wisdom = 1
     self.charisma = 1
     self.languages = ['Common', language]
Пример #11
0
 def testRaceStartingNow(self):
     # create a race
     race = Race(name='Brass Monkey Race 2 Large Handicap')
     # set it's start time to be in three minutes
     race.startTime = datetime.datetime.now() + datetime.timedelta(seconds = START_SECONDS-1) 
     # check that it's running but not started
     self.assertTrue(race.isRunning())
     self.assertFalse(race.isStarted())
     # check its status
     self.assertEqual(race.status(),"Starting")
Пример #12
0
 def __init__(self, subrace):
     Race.__init__(self)
     self.intelligence = 2
     self.speed = 25
     self.languages = ['Common', 'Gnomish']
     self.features = ['Darkvision', 'Gnome Cunning']
     self.subrace = subrace
     if self.subrace == 'Forest Gnome':
         self._forest_gnome()
     if self.subrace == 'Rock Gnome':
         self._rock_gnome()
Пример #13
0
 def test_TheOneWhoDNFsStandsLower(self):
     participant1 = 7
     participant2 = 9
     sut = Race(laps=3, bibs=[participant1, participant2])
     sut.start('12:00:00')
     sut.split(participant2, '12:10:00')
     sut.split(participant1, '12:12:00')
     sut.split(participant2, '12:15:00')
     sut.dnf(participant2)
     standings = [result.bib for result in sut.results]
     self.assertSequenceEqual([participant1, participant2], standings)
Пример #14
0
    def test_DoesNotAcceptDnfIfBibHasAlreadyFinished(self):
        some_participant = 7
        sut = Race(laps=3, bibs=[some_participant])
        sut.start('12:00:00')

        sut.split(some_participant, '12:10:10')
        sut.split(some_participant, '12:15:20')
        sut.split(some_participant, '12:20:00')

        with self.assertRaises(BibHasAlreadyFinished):
            sut.dnf(some_participant)
Пример #15
0
 def setUp(self):
     self.driver1 = Driver('Ivo', Car('Opel', 'Astra', 240))
     self.driver2 = Driver('Rado', Car('Peugeot', '107', 180))
     self.driver3 = Driver('Slavqna', Car('Opel', 'Meriva', 300))
     self.driver4 = Driver('Pavlin', Car('AUDI', 'R8', 380))
     self.driver5 = Driver('Roni', Car('Golf', '5', 200))
     self.driver6 = Driver('Ceco', Car('AUDI', 'Q5', 310))
     self.race = Race([
         self.driver1, self.driver2, self.driver3, self.driver4,
         self.driver5, self.driver6
     ], 0.2)
Пример #16
0
    def __init__(self, r, headings, filename):
        super().__init__(r, len(headings))
        self.onFocusGainedText = ""
        self.headings = headings
        self.setColumnWidth(0, 70)
        self.setColumnWidth(1, 200)
        self.setColumnWidth(2, 200)
        self.setColumnWidth(3, 200)
        self.setColumnWidth(4, 70)
        self.setColumnWidth(5, 70)
        self.setColumnWidth(6, 70)
        self.setHorizontalHeaderLabels(headings)
        self.check_change = True
        self.cellChanged.connect(self.c_current)
        QEsFile = r"2020_Feb_QE.txt"
        handicapsFile = r"2020.csv"
        self.filename = filename
        handicaps = []
        self.PYdict = {}
        self.dinghyLst = []
        self.cols = dict()
        for h in headings:
            self.cols[h] = []

        for line in open(handicapsFile, "r").readlines():
            tokens = line.split(",")
            if tokens[0] != "" and len(tokens) > 3:
                self.dinghyLst.append(tokens[0])
                handicaps.append(tokens[0] + "," + tokens[1] + "," + tokens[2])
                self.PYdict[tokens[0]] = int(tokens[1])

        QEs = []

        for line in open(QEsFile, "r").readlines():
            QEs.append(QE(line, self.PYdict))
        self.race = Race([], QEs)
        self.race.handicaps = handicaps
        self.completerLsts = {"QE": [], "Class": [], "Code": []}
        for qe in QEs:
            self.completerLsts["QE"].append(qe.QE)
        for c in self.PYdict.keys():
            self.completerLsts["Class"].append(c)
        self.completerLsts["Code"] = ["DNF", "OCS", "DNC"]
        self.completers = dict()
        for k in self.completerLsts.keys():
            self.completers[k] = QCompleter(self.completerLsts[k])
            self.completers[k].setCaseSensitivity(QtCore.Qt.CaseInsensitive)
        people = set()

        for Q in QEs:
            people.add(Q.helm)
            people.add(Q.crew)
        self.peopleLst = list(people)
        self.show()
Пример #17
0
 def __init__(self, subrace):
     Race.__init__(self)
     self.dexterity = 2
     self.speed = 25
     self.languages = ['Common', 'Halfling']
     self.features = ['Lucky', 'Brave', 'Halfling Nimbleness']
     self.subrace = subrace
     if self.subrace is 'Lightfoot Halfling':
         self._lightfoot()
     if self.subrace is 'Stout Halfling':
         self._stout()
Пример #18
0
    def __init__(self, hardware, *args, **kwargs):
        self.lock = threading.Lock()
        self.on_update = None
        self.hardware = hardware

        Race.__init__(self, [1, 1])
        threading.Thread.__init__(self)

        self._stop = False

        self.start()
Пример #19
0
    def testDeltaToStartTime(self):
        
        # create a race
        race = Race(name='Brass Monkey Race 2 Large Handicap')

        # set it's start time to be in ten minutes
        race.startTime = datetime.datetime.now() + datetime.timedelta(minutes = -10)

        # test that the delta is ten minutes
        # note this may fail if the clock moves on during execution
        self.assertEqual(race.deltaToStartTime(), datetime.datetime.now() - race.startTime)
Пример #20
0
 def test_LappedRiderRidesLess(self):
     leader = 7
     lapped = 9
     sut = Race(laps=3, bibs=[leader, lapped])
     sut.start('12:00:00')
     sut.split(leader, '12:05:00')
     sut.split(leader, '12:10:00')
     sut.split(lapped, '12:10:00')
     sut.split(leader, '12:15:00')
     sut.split(lapped, '12:20:00')
     lapped_state = sut.results[1].state
     self.assertEqual(ParticipantState.FINISHED, lapped_state)
Пример #21
0
 def __init__(self, name_in):
     self.name = name_in
     self.stats = {
         "str": 0,
         "dex": 0,
         "con": 0,
         "wis": 0,
         "int": 0,
         "cha": 0
     }
     self.species = Race()
     print("Creating character: ", self.name)
Пример #22
0
    def test_DoesNotAcceptSplitIfBibHasAlreadyFinished(self):
        some_participant = 7
        sut = Race(laps=3, bibs=[some_participant])
        sut.start('12:00:00')

        sut.split(some_participant, '12:10:10')
        sut.split(some_participant, '12:15:20')
        sut.split(some_participant, '12:20:00')

        with self.assertRaises(BibHasAlreadyFinished):
            excessive_split = '12:25:00'
            sut.split(some_participant, excessive_split)
Пример #23
0
    async def open(self, ctx, start_time_str):
        """ 
        usage: !kiite open TIMESTRING

            TIMESTRING: A string indicates a start time of the race.
                        The string must be following the format "hh:mm" or "yyyy/mm/dd hh:mm".
        """

        start_time = self.__parse_timestamp(start_time_str)
        race = Race(ctx.message.id, ctx.channel.id, start_time)
        self.races[race.hash()] = race
        await ctx.channel.send(race.template())
Пример #24
0
 def __init__(self, subrace, cantrip=None, language=None):
     Race.__init__(self)
     self.dexterity = 2
     self.languages = ['Common', 'Elvish']
     self.features = ['Darkvision', 'Fey Ancestry', 'Trance']
     self.subrace = subrace
     self.proficiencies = ['Perception']
     if self.subrace == 'High Elf':
         self._high_elf(cantrip, language)
     if self.subrace == 'Wood Elf':
         self._wood_elf()
     if self.subrace == 'Dark Elf (Drow)':
         self._dark_elf()
Пример #25
0
    def __init__(self, player):
        self.races = {}
        self.races["Elders"] = Race("Elders", None, "E",
                                    colorama.Fore.LIGHTWHITE_EX)
        self.races["Humans"] = Race("Human", None, "H", colorama.Fore.WHITE)

        self.races["Rindhalu"] = Race("Rindhalu", None, "R",
                                      colorama.Fore.GREEN)
        self.races["Jeraptha"] = Race("Jeraptha", self.races["Rindhalu"], "J",
                                      colorama.Fore.BLUE)
        self.races["Ruhar"] = Race("Ruhar", self.races["Jeraptha"], "R",
                                   colorama.Fore.LIGHTCYAN_EX)

        self.races["Maxolhx"] = Race("Maxolhx", None, "M",
                                     colorama.Fore.LIGHTMAGENTA_EX)
        self.races["Thuranin"] = Race("Thuranin", self.races["Maxolhx"], "T",
                                      colorama.Fore.MAGENTA)
        self.races["Kristang"] = Race("Kristang", self.races["Thuranin"], "K",
                                      colorama.Fore.YELLOW)
        self.races["Bosphuraq"] = Race("Bosphuraq", self.races["Maxolhx"], "B",
                                       colorama.Fore.RED)
        self.races["Wurgalan"] = Race("Wurgalan", self.races["Bosphuraq"], "W",
                                      colorama.Fore.LIGHTYELLOW_EX)

        self.news = {}
        self.news["global"] = []

        self._star_names = StarNamesStack()
        self.stars = []
        for n in range(len(self._star_names.names)):
            star = Star(random.randrange(config.world_width),
                        random.randrange(config.world_height),
                        self._star_names.pop(), self.get_random_owner_race())
            self.stars.append(star)
            self.news[star.name] = []
        self._scatter_stars()
        self._scatter_stars()

        sol = Sol(self, player.world_x, player.world_y)
        self.stars.append(sol)
        player.star = sol
        for b in sol.bodies:
            if b.name == 'Planet Earth (Medium Terran)':
                player.system_x = b.body_x
                player.system_y = b.body_y
                player.body = b
                break

        self.fleets = []
        self.spawn_fleets()
        self.spawn_investigator_fleet()
Пример #26
0
 def testDeltaToStartTimeException(self):
     
     # create a race
     race = Race(name='Brass Monkey Race 2 Large Handicap')
     # check that we get an exception if we ask for a start time
     try:
         delta = race.deltaToStartTime()
     except RaceException:
         pass
     except:
         e = sys.exc_info()[0]
         self.fail('Unexpected exception thrown:',e)
     else:
         self.fail('RaceException not thrown')
Пример #27
0
 def __init__(self, subrace, tool):
     Race.__init__(self)
     self.constitution = 2
     self.speed = 25
     self.languages = ['Common', 'Dwarvish']
     self.features = ['Darkvision', 'Dwarven Resillience', 'Stone Cunning']
     self.other = [
         'Battleaxe', 'Handaxe', 'Throwing Hammer', 'Warhammer', tool
     ]
     self.subrace = subrace
     if self.subrace == 'Hill Dwarf':
         self._hill_dwarf()
     if self.subrace == 'Mountain Dwarf':
         self._mountain_dwarf()
Пример #28
0
 def __init__(self, name):
     super().__init__(name)
     self.name = name
     self.race = Race()
     self.scores = {
         'Strength': 0,
         'Dexterity': 0,
         'Constitution': 0,
         'Intelligence': 0,
         'Wisdom': 0,
         'Charisma': 0,
     }
     self.scores['Strength'] = self.getRoll()
     self.scores['Dexterity'] = self.getRoll()
     self.scores['Constitution'] = self.getRoll()
     self.scores['Intelligence'] = self.getRoll()
     self.scores['Wisdom'] = self.getRoll()
     self.scores['Charisma'] = self.getRoll()
     self.getClass()
     self.modifiers = {
         'Strength': 0,
         'Dexterity': 0,
         'Constitution': 0,
         'Intelligence': 0,
         'Wisdom': 0,
         'Charisma': 0,
     }
     self.getMods()
Пример #29
0
 def get_race(self, key):
     with dbapi2.connect(self.app.config['dsn']) as connection:
         cursor = connection.cursor()
         query = "SELECT TITLE, RACE_TYPE, FOUNDERID, PARTICIPANT_COUNT, TIME, CYCROUTEID FROM RACE WHERE (ID = %s)"
         cursor.execute(query, (key,))
         title, race_type, founder, participant_count, time, place  = cursor.fetchone()
     return Race(title, race_type, founder, participant_count, time, place)
Пример #30
0
    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))
Пример #31
0
 def load_track(self, dt, *args, **kwargs):
     if not self.images_loaded:
         self.track.load_images()
         self.label.text = self.text + '5%'
         self.total = len(self.track.partition_list)
         self.images_loaded = True
     elif not self.overlay_loaded:
         self.track.load_overlay()
         self.label.text = self.text + '25%'
         self.overlay_loaded = True
     else:
         partitions_left = self.track.load_partitions()
         percent = 25 + int(
             ((self.total - partitions_left) * 1.0 / self.total) * 75)
         self.label.text = self.text + str(percent) + '%'
         if partitions_left == 0:
             # load the music last
             self.track.load_music()
             # hack to prevent circular imports
             from race import Race
             race = Race(self.track, [
                 state.profile.car,
                 ComputerCar.get_default(),
                 ComputerCar.get_default()
             ])
             director.replace(race)
Пример #32
0
    def start(self, championship_name):
        print('Starting a new championship called {} with {} races.'.format(
            self.name, self.races_count))
        print('Running {} races...'.format(self.races_count))
        print('')

        for i in range(self.races_count):
            crash_chance = randint(0, 100) / 100.0
            r = Race(self.load_drivers(), crash_chance)
            print('Race #{}'.format(i + 1))
            r.start(championship_name, i + 1)
            print('')

        with open('result.json', 'r') as f:
            data = json.load(f)
        Championship.total_ranking(data, self.name)
Пример #33
0
 def make_rematch(self):
     if not self._rematch_made:
         yield from self.race.record()
         new_race_info = self.race.race_info.copy()
         self.race = Race(self, new_race_info)
         asyncio.ensure_future(self.race.initialize())
         self._rematch_made = True
         yield from self.write('Rematch created!')
Пример #34
0
 def get_races(self):
     with dbapi2.connect(self.app.config['dsn']) as connection:
         cursor = connection.cursor()
         query = "SELECT * FROM RACE ORDER BY ID"
         cursor.execute(query)
         races = [(key, Race(title, race_type, founder, participant_count, time, place))
                   for key, title, race_type, founder, participant_count, time, place in cursor]
     return races
Пример #35
0
 def test_TheOneWhoRidesMoreLapsStandsHigher_2(self):
     participant1 = 7
     participant2 = 9
     sut = Race(laps=3, bibs=[participant1, participant2])
     sut.start('12:00:00')
     sut.split(participant2, '12:14:00')
     sut.split(participant1, '12:15:00')
     sut.split(participant1, '12:20:00')
     standings = [result.bib for result in sut.results]
     self.assertSequenceEqual([participant1, participant2], standings)
Пример #36
0
    def test_OrderOfSplitsMatters(self):
        some_participant = 7
        other_participant = 9
        sut = Race(laps=3, bibs=[some_participant, other_participant])
        sut.start('12:00:00')

        shuffled_splits = ['12:15:20', '12:10:10']
        sut.split(some_participant, shuffled_splits[0])
        with self.assertRaises(SplitsAreOutOfOrder):
            sut.split(other_participant, shuffled_splits[1])
Пример #37
0
    def __init__(self, race_module, race_channel, race_info):
        self.channel = race_channel                 #The channel in which this race is taking place
        self.creator = None                         #Can store a user that created this room. Not used internally.
        self.is_closed = False                      #True if room has been closed
        self.race = Race(self, race_info)           #The current race
        self.admin_ready = True

        self._rm = race_module
        self._rematch_made = False                  #True once a rematch of this has been made (prevents duplicates)
        self._mention_on_rematch = []               #A list of users that should be @mentioned when a rematch is created
        self.mentioned_users = []                  #A list of users that were @mentioned when this race started
        self._nopoke = False

        self.command_types = [command.DefaultHelp(self),
                              Enter(self),
                              Unenter(self),
                              Ready(self),
                              Unready(self),
                              Done(self),
                              Undone(self),
                              Forfeit(self),
                              Unforfeit(self),
                              Comment(self),
                              Death(self),
                              Igt(self),
                              Rematch(self),
                              DelayRecord(self),
                              Notify(self),
                              Time(self),
                              Missing(self),
                              Shame(self),
                              Poke(self),
                              ForceCancel(self),
                              ForceClose(self),
                              ForceForfeit(self),
                              ForceForfeitAll(self),
                              ForceRecord(self),
                              Kick(self)]
Пример #38
0
from horse import Horse
from race import Race

name_horse1 = input("Nombre del primer caballo: ")
name_horse2 = input("Nombre del segundo caballo: ")

horse1 = Horse(name_horse1)
horse2 = Horse(name_horse2)

race = Race(horse1, horse2)

race.start()
Пример #39
0
 def test_race(self):
     slug = Slug("Mickey")
     race = Race()
     race.slugs.append(slug)
     winner = race.do_race()
     self.assertTrue(winner is not None)
Пример #40
0
class TestRace(unittest.TestCase):

	def setUp(self):
		self.test_race = Race('Dwarf')
		self.expected_effect = Effect()
		self.expected_description = 'Dwarves are a hearty breed, and make excellent warriors due to their high strength and toughness.'

	def tearDown(self):
		self.test_race = None
		self.expected_effect = None
		self.expected_description = None

	def test_total_hp(self):
		self.assertEqual(0, self.test_race.total_hp())

	def test_total_strength(self):
		self.assertEqual(5, self.test_race.total_strength())

	def test_total_intelligence(self):
		self.assertEqual(0, self.test_race.total_intelligence())

	def test_total_agility(self):
		self.assertEqual(0, self.test_race.total_agility())

	def test_total_attack(self):
		self.assertEqual(Damage(0,0), self.test_race.total_attack())

	def test_total_defense(self):
		self.assertEqual(Damage(20,30), self.test_race.total_defense())

	def test_valid_name(self):
		self.assertFalse(self.test_race.valid_name('INVALID'))

	def test_valid_name2(self):
		self.assertTrue(self.test_race.valid_name('DWARF'))

	def test_valid_name3(self):
		self.assertTrue(self.test_race.valid_name('dwarf'))

	def test_race_effect(self):
		self.assertEqual(self.expected_effect, self.test_race.race_effect("Dwarf"))

	def test_race_description(self):
		self.assertEqual(self.expected_description, self.test_race.race_description("Dwarf"))

	def test_race_description2(self):
		self.assertEqual(self.expected_description, self.test_race.race_description("dwarf"))

	def test_race_description3(self):
		self.assertEqual(self.expected_description, self.test_race.race_description("DWARF"))
Пример #41
0
    def resilience_defense(self):
        """docstring for resilience_defense"""
        return 10 + self.ability.bonus(self.ability.constitution) #+ misc

    def movemnet_speed(self):
        """docstring for movemnet_speed"""
        return 5 + self.ability.modifier(self.ability.dexterity) #+ misc


if __name__ == '__main__':
    from level import Level
    from ability import Ability
    from class_ import Class
    from race import Race
    level = Level()
    race = Race()
    ability = Ability(level)
    ability.generate()
    ability.wisdom = 22
    class_ = Class()
    statistics = Statistics(ability, level, class_)
    def yell():
        """docstring for debug"""
        print "hp:%s ap:%s mb:%s rb:%s mab:%s ad:%s ed:%s md:%s rd:%s spd:%s at level: %s" % (
            statistics.max_health_points(),
            statistics.max_anima_points(),
            statistics.melee_bonus(),
            statistics.ranged_bonus(),
            statistics.magic_bonus(),
            statistics.armor_defense(10),
            statistics.evasion_defense(),
Пример #42
0
	def setUp(self):
		self.test_race = Race('Dwarf')
		self.expected_effect = Effect()
		self.expected_description = 'Dwarves are a hearty breed, and make excellent warriors due to their high strength and toughness.'
Пример #43
0
class RacePrivateRoom(raceroom.RaceRoom):

    def __init__(self, race_module, race_channel, race_private_info):
        raceroom.RaceRoom.__init__(self, race_module, race_channel, race_private_info.race_info)
        self._match_info = race_private_info.match_info
        self.permission_info = permissioninfo.get_permission_info(race_module.server, race_private_info)

        self.command_types = [command.DefaultHelp(self),
                              raceroom.Enter(self),
                              raceroom.Unenter(self),
                              raceroom.Ready(self),
                              raceroom.Unready(self),
                              raceroom.Done(self),
                              raceroom.Undone(self),
                              raceroom.Forfeit(self),
                              raceroom.Unforfeit(self),
                              raceroom.Comment(self),
                              raceroom.Igt(self),
                              raceroom.Death(self),
                              raceroom.Rematch(self),
                              raceroom.DelayRecord(self),
                              raceroom.Notify(self),
                              raceroom.Time(self),
                              raceroom.ForceCancel(self),
                              raceroom.ForceClose(self),
                              raceroom.ForceForfeit(self),
                              raceroom.ForceForfeitAll(self),
                              raceroom.Kick(self),
                              Add(self),
                              Admins(self),
                              Remove(self),
                              ChangeRules(self),
                              MakeAdmin(self),
                              Reseed(self),
                              ForceReset(self),
                              Pause(self),
                              Unpause(self)]

    @property
    def infostr(self):
        return 'Private race'

    # Sets up the leaderboard for the race
    # Overrides
    @asyncio.coroutine
    def initialize(self):
        yield from self._set_permissions()
        yield from raceroom.RaceRoom.initialize(self)

    # Makes a rematch of this race in this room, if one has not already been made
    # Overrides
    @asyncio.coroutine
    def make_rematch(self):
        if not self._rematch_made:
            yield from self.race.record()
            new_race_info = self.race.race_info.copy()
            self.race = Race(self, new_race_info)
            asyncio.ensure_future(self.race.initialize())
            self._rematch_made = True
            yield from self.write('Rematch created!')

    # Begins the race if ready. (Writes a message if all racers are ready but an admin is not.)
    # Overrides
    @asyncio.coroutine
    def begin_if_ready(self):
        success = yield from raceroom.RaceRoom.begin_if_ready(self)
        if success:
            self._rematch_made = False
        return success

    # Find all members with the given username
    def find_members(self, username):
        return self._rm.necrobot.find_members(username)

    # True if the user has admin permissions for this race
    # Overrides
    def is_race_admin(self, member):
        return self.permission_info.is_admin(member) or raceroom.RaceRoom.is_race_admin(self, member)

    # A string to add to the race details ("Private")
    # Overrides
    def format_rider(self):
        return '(private)'

    # Allow the member to see the channel
    @asyncio.coroutine
    def allow(self, member):
        read_permit = discord.PermissionOverwrite()
        read_permit.read_messages = True
        yield from self.client.edit_channel_permissions(self.channel, member, read_permit)

    #Restrict the member from seeing the channel
    @asyncio.coroutine
    def deny(self, member):
        read_deny = discord.PermissionOverwrite()
        read_deny.read_messages = False
        yield from self.client.edit_channel_permissions(self.channel, member, read_deny)

    # Make room private to all but admins and racers in permission_info
    @asyncio.coroutine
    def _set_permissions(self):
        read_permit = discord.Permissions.none()
        read_permit.read_messages = True

        #deny access to @everyone
        yield from self.deny(self._rm.server.default_role)

        #allow access for self
        yield from self.allow(self._rm.necrobot.get_as_member(self.client.user))

        #give admin roles permission
        for role in self.permission_info.admin_roles:
            yield from self.allow(role)

        #give admins permission
        for member in self.permission_info.admins:
            yield from self.allow(member)

        #give racers permission
        for member in self.permission_info.racers:
            yield from self.allow(member)
Пример #44
0
            if not sigma: sigma = 1.
            threshold = float(a)
        elif o == '-g':
            ghosts = a.split(',')
        elif o == '-a':
            ais = True
        elif o == '-c':
            shape = a
        elif o == '--filter':
            density = 0.01
            sigma = 1.
            threshold = 5.
        else:
            assert False, 'unhandled option'

    race = Race(n, shape, length, width)
    for name in ghosts:
        race.add_ghost(name)
    if ais:
        add_ai(race)
    if density:
        race.circuit.add_obstacles(density)
    if threshold or sigma:
        race.circuit.filter_obstacles(threshold, sigma) # , True)
    race.run()
    ask(race)

def ask(race):
    while 1:
        tmp = raw_input('R for replay, '+
                        'M for one more (just one..), '+
Пример #45
0
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()
Пример #46
0
class RaceRoom(command.Module):

    def __init__(self, race_module, race_channel, race_info):
        self.channel = race_channel                 #The channel in which this race is taking place
        self.creator = None                         #Can store a user that created this room. Not used internally.
        self.is_closed = False                      #True if room has been closed
        self.race = Race(self, race_info)           #The current race
        self.admin_ready = True

        self._rm = race_module
        self._rematch_made = False                  #True once a rematch of this has been made (prevents duplicates)
        self._mention_on_rematch = []               #A list of users that should be @mentioned when a rematch is created
        self.mentioned_users = []                  #A list of users that were @mentioned when this race started
        self._nopoke = False

        self.command_types = [command.DefaultHelp(self),
                              Enter(self),
                              Unenter(self),
                              Ready(self),
                              Unready(self),
                              Done(self),
                              Undone(self),
                              Forfeit(self),
                              Unforfeit(self),
                              Comment(self),
                              Death(self),
                              Igt(self),
                              Rematch(self),
                              DelayRecord(self),
                              Notify(self),
                              Time(self),
                              Missing(self),
                              Shame(self),
                              Poke(self),
                              ForceCancel(self),
                              ForceClose(self),
                              ForceForfeit(self),
                              ForceForfeitAll(self),
                              ForceRecord(self),
                              Kick(self)]

    @property
    def infostr(self):
        return 'Race'

    @property
    def client(self):
        return self._rm.client

    # Notifies the given user on a rematch
    def notify(self, user):
        if not user in self._mention_on_rematch:
            self._mention_on_rematch.append(user)

    # Removes notifications for the given user on rematch
    def dont_notify(self, user):
        self._mention_on_rematch = [u for u in self._mention_on_rematch if u != user]

    # 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=[]):
        asyncio.ensure_future(self.race.initialize())
        asyncio.ensure_future(self.client.edit_channel(self.channel, topic=self.race.leaderboard))
        asyncio.ensure_future(self._monitor_for_cleanup())

        #send @mention message
        mention_text = ''
        for user in users_to_mention:
            mention_text += user.mention + ' '
            self.mentioned_users.append(user)
        if mention_text:
            asyncio.ensure_future(self.client.send_message(self.channel, 'Alerting users: ' + mention_text))

        #put seed in chat
        if self.race.race_info.seeded:
            asyncio.ensure_future(self.client.send_message(self.channel, 'The seed for this race is {0}.'.format(self.race.race_info.seed)))

    # 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)

    # A string to add to the race details (used for private races; empty in base class)
    def format_rider(self):
        return ''

    #Updates the leaderboard
    @asyncio.coroutine
    def update_leaderboard(self):
        asyncio.ensure_future(self.client.edit_channel(self.channel, topic=self.race.leaderboard))

    # Close the channel.
    @asyncio.coroutine
    def close(self):
        self.is_closed = True
        yield from self.client.delete_channel(self.channel)

    # Returns true if all racers are ready
    @property
    def all_racers_ready(self):
        return self.race.num_not_ready == 0 and (not config.REQUIRE_AT_LEAST_TWO_FOR_RACE or len(self.race.racers) > 1)

    # 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.all_racers_ready:
            if self.admin_ready:
                yield from self.race.begin_race_countdown()
                return True
            else:
                yield from self.write('Waiting on an admin to type `.ready`.')
                return False

    # Makes a rematch of this race in a new room, if one has not already been made
    @asyncio.coroutine
    def make_rematch(self):
        if not self._rematch_made:
            self._rematch_made = True
            new_race_info = self.race.race_info.copy()
            new_race_channel = yield from self._rm.make_race(new_race_info, mention=self._mention_on_rematch, suppress_alerts=True)
            if new_race_channel:
                yield from self.write('Rematch created in {}!'.format(new_race_channel.mention))
##                yield from self._rm.client.send_message(self._rm.main_channel, 'A new race has been started:\nFormat: {1}\nChannel: {0}'.format(new_race_channel.mention, new_race_info.format_str()))
            else:
                self._rematch_made = False

    #True if the user has admin permissions for this race
    def is_race_admin(self, member):
        admin_roles = self._rm.necrobot.admin_roles
        for role in member.roles:
            if role in admin_roles:
                return True

        return False

    # Checks to see whether the room should be cleaned.
    @asyncio.coroutine
    def _monitor_for_cleanup(self):
        # Pre-race cleanup loop
        while not self.is_closed:
            yield from asyncio.sleep(30) #Wait between check times

            # Pre-race
            if self.race.is_before_race:
                if (not self.race.racers) and self.race.no_entrants_time: #if there are no entrants (and we've stored the last time this was not the case)
                    if time.monotonic() - self.race.no_entrants_time > config.NO_ENTRANTS_CLEANUP_WARNING_SEC:
                        time_remaining = config.NO_ENTRANTS_CLEANUP_SEC - config.NO_ENTRANTS_CLEANUP_WARNING_SEC
                        yield from self.write('Warning: Race has had zero entrants for some time and will be closed in {} seconds.'.format(time_remaining))
                        yield from asyncio.sleep(time_remaining)
                        if not self.race.racers:
                            yield from self.close()
                            return

            # Post-race
            elif self.race.complete:
                msg_list = yield from self.client.logs_from(self.channel, 1)
                for msg in msg_list:
                    if (datetime.datetime.utcnow() - msg.timestamp).total_seconds() > config.CLEANUP_TIME_SEC:
                        yield from self.close()
                        return

    ## TODO: more intelligent result posting
    @asyncio.coroutine
    def post_result(self, text):
        asyncio.ensure_future(self.client.send_message(self._rm.results_channel, text))


    # Alerts unready users
    @asyncio.coroutine
    def poke(self):
        if self._nopoke:
            return

        ready_racers = []
        unready_racers = []
        for racer in self.race.racers.values():
            if racer.is_ready:
                ready_racers.append(racer)
            else:
                unready_racers.append(racer)

        num_unready = len(unready_racers)
        quorum = (num_unready == 1) or (3*num_unready <= len(ready_racers))

        if ready_racers and quorum:
            self._nopoke = True
            asyncio.ensure_future(self.run_nopoke_delay())
            alert_string = ''
            for racer in unready_racers:
                alert_string += racer.member.mention + ', '
            yield from self.write('Poking {0}.'.format(alert_string[:-2]))

    # Implements a delay before pokes can happen again
    @asyncio.coroutine
    def run_nopoke_delay(self):
        yield from asyncio.sleep(config.RACE_POKE_DELAY)
        self._nopoke = False