def __init__(self, **kwargs): # You'd pass in a dict containing information on the 'mon here. # {'species': 'vaporeon', 'level': 100, 'moves': ['Surf', 'Ice Beam']} ... etc # Initialising. They'll be overwritten if they exist self.level = 100 self.ivs = [0] * 6 self.evs = [0] * 6 self.nature = 'Hardy' for arg in kwargs: setattr(self, arg, kwargs.get(arg)) dex = POKEDEX.get(utils.condense(self.species)) base_stats = dex.get('baseStats') self.types = dex.get('types') self.maxhp = statcalc_hp(base_stats['hp'], self.ivs[0], self.evs[0], self.level) self.hp = self.maxhp self.attack = statcalc('atk', base_stats['atk'], self.ivs[1], self.evs[1], self.level, self.nature) self.defense = statcalc('def', base_stats['def'], self.ivs[2], self.evs[2], self.level, self.nature) self.spattack = statcalc('spa', base_stats['spa'], self.ivs[3], self.evs[3], self.level, self.nature) self.spdefense = statcalc('spd', base_stats['spd'], self.ivs[4], self.evs[4], self.level, self.nature) self.speed = statcalc('spe', base_stats['spe'], self.ivs[5], self.evs[5], self.level, self.nature) # Volatiles self.volatiles = {'boosts': {}, 'volatile_status': None} self.status = None
def best_switch(self, active, sidedata, target): print 'call to switch' highest_score = 0 alive_mon_indexes = self.pick_alive_mons(sidedata) side_mon_info = sidedata.get('pokemon') # Loops through all mons, finds which has the highest score, and switches print alive_mon_indexes best_mon_index = alive_mon_indexes[0] for i in alive_mon_indexes: mon = side_mon_info[i - 1] mon_info = mon.get('details').split(', ') mon_species = utils.condense(mon_info[0]) mon_level = mon_info[1][1:] try: mon_types = battleutils.POKEDEX.get(mon_species).get('types') except Exception as e: print e mon_types = ['Normal'] movelist = mon.get('moves') scores = [battleutils.calculate_move_score(active, mon_types, target, x) for x in movelist] print movelist print scores best_score = max(scores) if best_score > highest_score: print 'best score %s is higher than highest score %s!' % (best_score, highest_score) highest_score = best_score best_move = movelist[scores.index(best_score)] print 'best move is %s!' % best_move best_mon = mon_species best_mon_index = i result = '/switch ' + str(best_mon_index) print result return result
def received_message(self, m): # PS sometimes sends multiple messages split by newlines... messages = str(m).split('\n') if messages[0][0] == '>': room = messages.pop(0) else: room = '>lobby' for rawmessage in messages: is_battle = False rawmessage = "%s\n%s" % (room, rawmessage) print rawmessage msg = rawmessage.split("|") battle_regex = re.compile('>battle-') if battle_regex.match(msg[0]): # print 'handling battle message', msg self.bh.handle(msg) if len(msg) < 2: continue downmsg = msg[1].lower() # print msg, ' - ', is_battle, ' - ', downmsg if downmsg == 'challstr': print '%s: Attempting to login...' % self.user assertion = utils.old_login(self.user, self.config.get('Chatbot', 'password'), msg[3], msg[2]) #assertion = utils.login(self.user, # self.config.get('Chatbot','password'), # '|'.join(msg[2:])) if assertion is None: raise Exception('%s: Could not login' % self.user) self.send('|/trn %s,0,%s' % (self.user, assertion)) elif downmsg == 'formats': data = '|'.join(msg[2:]) # this takes all of the formats data PS sends on connection # and turns it into a list self.ch.battle_formats = map(utils.condense, (re.sub(r'\|\d\|[^|]+', '', ('|' + re.sub(r'(,[0-9a-f])', '', data))) ).split('|'))[1:] elif downmsg == 'updateuser': if utils.condense(msg[2]) == utils.condense(self.user): # Bot has logged in. print '%s: Logged in!' % self.user self.ch.queue_worker.start() for r in self.rooms: print '%s: Joining room %s.' % (self.user, r) self.ch.queue_message('|/join %s' % r) elif downmsg in ['c', 'c:', 'pm', 'j', 'n', 'l', 'users', 'raw', ':', 'init']: print 'match', downmsg print msg self.ch.handle(msg[1:], room) elif downmsg == 'tournament': # self.ch.handle_tournament(msg) print 'not implemented handle_tournament' elif downmsg == 'updatechallenges': self.bh.handle_challenge(msg)
def handle(self, msg, room): room = room.replace('>', '') m_info = self.make_msg_info(msg, room, self.ws) if m_info['where'] == ':': # : messages contain an UNIX timestamp of when the room was joined # nvm, PS's time is usually off self.join_time[room] = str(int(time.time())) # Prevents the chatbot from responding to messages # sent before it entered the room if (m_info.get('who') and ((m_info.get('when') and int(m_info.get('when')) > int(self.join_time[room])) or m_info.get('where') in {'j', 'l', 'pm'})): for trigger in self.triggers: # print 'testing trigger %s' % trigger try: if trigger.match(m_info): print 'match %s' % trigger future = self.thread_pool_executor.submit(self.call_trigger_response, trigger, m_info) future.room = room future.m_info = m_info future.add_done_callback(self.future_callback) except Exception as e: self.send_pm(self.ws.master, "Crashed in match: %s, %s, %s" % (e.message, e.args, trigger)) # User list is currently hardcoded here. Might move this to triggers later on if m_info['where'] == 'j' and condense(m_info['who']) not in map(condense, self.current_users[room]): self.current_users[room].append(msg[1]) elif m_info['where'] == 'l': for user in self.current_users[room]: if condense(user) == condense(msg[1]): self.current_users[room].remove(user) elif m_info['where'] == 'n': # |N| messages are of the format |N|(rank)newname|oldnameid # Rank is a blank space if the nick is a regular user # i.e. |N|@Scotteh|stretcher newuser, olduser, userfound = msg[1], msg[2], False for user in self.current_users[room]: if condense(user) == condense(msg[2]): self.current_users[room].remove(user) userfound = True if userfound: self.current_users[room].append(msg[1]) elif m_info['where'] == 'users': # Resets the userlist for the room if it exists, and creates a new one # |users| messages are only sent on room join self.current_users[room] = [] for user in msg[1].split(',')[1:]: self.current_users[room].append(user) if m_info['where'] == 'raw' and int(time.time()) > int(self.join_time[room]): print (int(time.time()), self.join_time[room]) # Get checker. Hardcoded. getmap = {2: 'dubs', 3: 'trips', 4: 'quads', 5: 'quints', 6: 'sexts', 7: 'septs', 8: 'octs', 9: 'nons', 10: 'decs'} if m_info['all'][1].startswith('<div class="infobox">Roll '): raw_msg = msg[1][21:-6] # Strips the leading HTML # Don't try and understand the next line, it takes raw_msg as input and # creates a list of size 2 lists splitting the raw_msg and showing the consecutive # characters, and returns the amount of consecutive characters at the end # '11223344441122' => [['1', 2], ['2', 2], ['3', 2], ['4', 4], ['1', 2], ['2', 2]] get = getmap.get([[k,len(list(g))] for k, g in groupby(raw_msg)][-1][1]) if get: self.send_msg(room, 'nice ' + get)
def match(self, info): return condense(info.get('who')) == self.ch.ws.master and info.get('what').startswith('.eval ')
def get_rank(self, user): u_id = condense(user) for u in self.users: if u_id == condense(u): return u[0]
def calculate_move_score(active, types, target, move): move = utils.condense(move) # Score is zero for all of these blacklist = ['suckerpunch', 'focuspunch', 'fakeout', 'return', 'frustration', 'snore', 'dreameater', 'lastresort', 'explosion', 'selfdestruct', 'synchronoise', 'belch', 'trumpcard', 'wringout' ] badlist = ['gigaimpact', 'hyperbeam', 'rockwrecker', 'frenzyplant', 'hydrocannon', 'blastburn', 'roaroftime', 'skyattack', 'solarbeam', 'freezeshock', 'iceburn', 'doomdesire', 'futuresight ', 'leafstorm', 'overheat', 'dracometeor', 'psychoboost', 'superpower', 'hammerarm' ] if not MOVES.get(move): return 0 if MOVES.get(move).get('category') == 'Status' or move in blacklist: return 0 res = 1.0 for user_type in types: if MOVES[move]['type'] == user_type: res *= 1.5 if move in badlist: res *= 0.5 res *= MOVES[move]['basePower'] if type(MOVES[move]['accuracy']) == int: res *= (MOVES[move]['accuracy'] / 100.0) res *= effectiveness(move, target) return res
async def match(self, info): return (utils.condense(info.get('who')) == self.cb.master and info.get('what').startswith('.eval'))
def handle(self, msg): # Commenting out until I decide whether to properly integrate triggers in battle rooms with regular triggers. # self.ch.handle(msg, self.id) if msg[0] == 'init': self.ch.send_msg(self.id, '/timer') elif msg[0] == 'c': # These are hardcoded. if utils.condense(msg[1]) == 'scotteh': if msg[2] == '!alive': self.ch.send_msg(self.id, self.name_alive_mons(self.sidedata)) elif msg[2] == '!moves': if self.active is not None: self.ch.send_msg(self.id, ', '.join(self.pick_move(self.active))) elif msg[2] == '!item': self.ch.send_msg(self.id, self.sidedata['pokemon'][0]['item']) elif msg[2].startswith('!custom'): self.ch.send_msg(self.id, msg[2][8:]) elif msg[2].startswith('.eval'): expression = msg[2][6:] try: response = eval(expression) self.ch.send_msg(self.id, response) except Exception as e: self.ch.send_msg(self.id, e) elif msg[0] == 'player': # Sets p1 and p2 in a new player object if msg[1] == 'p1': if msg[2] == self.ch.user: # This is me self.me = 'p1' else: self.me = 'p2' self.battle.p1 = battleutils.Player(id=msg[1], username=utils.condense(msg[2])) else: self.battle.p2 = battleutils.Player(id=msg[1], username=utils.condense(msg[2])) elif msg[0] == 'poke': if msg[1] == 'p1': self.battle.add_to_team(self.battle.p1, msg[2]) else: self.battle.add_to_team(self.battle.p2, msg[2]) elif msg[0] == 'switch' or msg[0] == 'drag': # New mon was sent out if msg[1][0:2] != self.me: if self.waiting: self.waiting = False self.ch.send_msg(self.id, '/switch %s|%s' % (random.choice(self.pick_alive_mons(self.sidedata)), self.rqid)) mon_info = msg[2].split(', ') mon_species = utils.condense(mon_info[0]) mon_level = int(mon_info[1][1:]) print 'Encountered a level %s %s' % (mon_level, mon_species) self.active_opponent = battleutils.Pokemon(species=mon_species, level=mon_level) else: mon_info = msg[2].split(', ') mon_species = utils.condense(mon_info[0]) self.types = battleutils.POKEDEX[mon_species]['types'] elif msg[0] == 'request': self.canMegaEvo = False request = json.loads(msg[1]) self.rqid = request.get('rqid') self.active = request.get('active', [None])[0] # Note: check if active has multiple elements for doubles self.sidedata = request.get('side') self.player = self.sidedata.get('id') self.canMegaEvo = self.sidedata.get('pokemon')[0].get('canMegaEvo') elif msg[0] == 'turn': # move_msg = '/move %s' % random.choice(self.pick_move(self.active)) # move_msg = '/move %s' % self.best_move(self.active, self.types, self.active_opponent) move_msg = self.best_move(self.active, self.types, self.active_opponent) print 'move_msg is %s' % move_msg if move_msg.startswith('/move'): message = (move_msg + '|' if not self.canMegaEvo else move_msg + ' mega |') + str(self.rqid) self.ch.send_msg(self.id, message) else: self.ch.send_msg(self.id, move_msg) elif msg[0] == 'teampreview': self.ch.send_msg(self.id, "/team %s|%s" % (random.randint(1, 6), self.rqid)) elif msg[0] == 'faint' and msg[1][0:2] == self.player: if self.lastmove in {'U-turn', 'Volt Switch'}: # The opponent needs to send out their 'mon first self.waiting = True else: mon_choice = self.best_switch(self.active, self.sidedata, self.active_opponent) self.ch.send_msg(self.id, '%s|%s' % (mon_choice, self.rqid)) elif self.waiting and msg[0] == 'switch' and msg[1][0:2] != self.player: # Opponent has sent out their 'mon self.waiting = False self.ch.send_msg(self.id, '/switch %s|%s' % (random.choice(self.pick_alive_mons(self.sidedata)), self.rqid)) elif msg[0] == 'win': self.ch.send_msg(self.id, '/leave') elif msg[0] == 'deinit': del self.bh.battles[self.id] elif msg[0] == '-crit' and msg[1][0:2] == self.player: self.ch.send_msg(self.id, 'wow stop hacking anytime') elif msg[0] == 'move': self.lastmove = msg[2] if msg[1][0:2] == self.player: if msg[2] in {'U-turn', 'Volt Switch', 'Baton Pass', 'Parting Shot'}: # Horrible hack self.ch.send_msg(self.id, '/switch %s' % random.choice(self.pick_alive_mons(self.sidedata)[1:]))
async def handle_msg(m, cb): messages = m.split('\n') if messages[0][0] == '>': room = messages.pop(0)[1:] else: room = 'global' for rawmessage in messages: print(f'{room}{rawmessage}') rawmessage = f'{">" + room}\n{rawmessage}' msg = rawmessage.split("|") if len(msg) < 2: continue if room.startswith('battle-') and cb.rooms.get(room): await cb.rooms[room].battle.handle(msg) downmsg = msg[1].lower() if downmsg == 'challstr': username = cb.username if cb.config[cb.id].get('password'): assertion = await login(username, cb.config[cb.id]['password'], '|'.join(msg[2:4])) else: assertion = await unreg_login(username, '|'.join(msg[2:4])) if len(assertion) == 0 or assertion is None: raise Exception('login failed :(') await cb.send('', f'/trn {username},0,{assertion}') elif downmsg == 'updateuser': if condense(msg[2]) == condense(cb.username): print("Logged in!") rooms = cb.config[cb.id]['rooms'] for room in rooms.split(','): await cb.send('', f'/join {room}') elif downmsg == 'formats': data = '|'.join(msg[2:]) cb.battle_formats = list( map(condense, (re.sub( r'\|\d\|[^|]+', '', ('|' + re.sub(r'(,[0-9a-f])', '', data)))).split('|')))[1:] elif downmsg == 'init': cb.rooms[room] = Room(room, cb) elif downmsg == 'deinit': del cb.rooms[room] elif downmsg == 'title': cb.rooms[room].title = msg[2] elif downmsg == 'users': cb.rooms[room].users = [] for user in msg[2].split(',')[1:]: cb.rooms[room].users.append(user) print(cb.rooms[room].__dict__) elif downmsg == ':': cb.rooms[room].join_time = int(msg[2]) elif downmsg == 'j' and condense(msg[2]) not in cb.rooms[room].users: cb.rooms[room].users.append(msg[2]) elif downmsg == 'l': for user in cb.rooms[room].users: if condense(user) == condense(msg[2]): cb.rooms[room].users.remove(user) elif downmsg == 'n': newuser, olduser, userfound = msg[2], msg[3], False for user in cb.rooms[room].users: if condense(user) == condense(olduser): cb.rooms[room].users.remove(user) userfound = True if userfound: cb.rooms[room].users.append(newuser) elif downmsg == 'updatechallenges': challs = json.loads(msg[2]) for chall in challs['challengesFrom']: if challs['challengesFrom'][chall] == 'gen7doublescustomgame': if cb.teams: team = random.choice(cb.teams['gen7doublescustomgame']) await cb.send('', f'/utm {team}') await cb.send('', f'/accept {chall}') if downmsg in ['c', 'c:', 'pm', 'j', 'l', 'html']: await handle_chat(msg[1:], room, cb)
async def handle_msg(m, cb): messages = m.split('\n') if messages[0][0] == '>': room = messages.pop(0)[1:] else: room = 'global' for rawmessage in messages: print(f'{room}{rawmessage}') rawmessage = f'{">" + room}\n{rawmessage}' msg = rawmessage.split("|") if len(msg) < 2: continue if room.startswith('battle-') and cb.rooms.get(room): await cb.rooms[room].battle.handle(msg) downmsg = msg[1].lower() if downmsg == 'challstr': username = cb.username if cb.config[cb.id].get('password'): assertion = await login(username, cb.config[cb.id]['password'], '|'.join(msg[2:4])) else: assertion = await unreg_login(username, '|'.join(msg[2:4])) if len(assertion) == 0 or assertion is None: raise Exception('login failed :(') await cb.send('', f'/trn {username},0,{assertion}') elif downmsg == 'updateuser': if '@' in msg[2][1:]: user, status = msg[2].rsplit('@', 1) else: user = msg[2] if condense(user) == condense(cb.username): print("Logged in!") rooms = cb.config[cb.id]['rooms'] # join rooms for room in rooms.split(','): await cb.send('', f'/join {room}') # send status to last room await cb.send(room, f'/status {cb.status}') elif downmsg == 'formats': formats = msg[2:] res = {} format_name = False cur_format = None for format in formats: if format_name: res[format] = [] cur_format = format format_name = False continue if format[0] == ',': format_name = True continue name, type = format.split(',', 1) res[cur_format].append({ 'name': name, 'info': get_format_info(type) }) cb.battle_formats = res elif downmsg == 'init': cb.rooms[room] = Room(room, cb) elif downmsg == 'deinit': del cb.rooms[room] elif downmsg == 'title': cb.rooms[room].title = msg[2] elif downmsg == 'users': cb.rooms[room].users = [] for user in msg[2].split(',')[1:]: cb.rooms[room].users.append(user) print(cb.rooms[room].__dict__) elif downmsg == ':': cb.rooms[room].join_time = int(msg[2]) elif downmsg == 'j': if '@' in msg[2][1:]: user, status = msg[2].rsplit('@', 1) else: user = msg[2] if condense(user) not in cb.rooms[room].users: cb.rooms[room].users.append(user) elif downmsg == 'l': if '@' in msg[2][1:]: user, status = msg[2].rsplit('@', 1) else: user = msg[2] for existing_user in cb.rooms[room].users: if condense(existing_user) == condense(user): cb.rooms[room].users.remove(existing_user) elif downmsg == 'n': newuser, olduser, userfound = msg[2], msg[3], False if '@' in newuser[1:]: newuser, status = newuser[1:].rsplit('@', 1) for user in cb.rooms[room].users: if condense(user) == condense(olduser): cb.rooms[room].users.remove(user) userfound = True if userfound: cb.rooms[room].users.append(newuser) elif downmsg == 'updatechallenges': challs = json.loads(msg[2]) for chall in challs['challengesFrom']: if challs['challengesFrom'][chall] == 'gen7doublescustomgame': if cb.teams: team = random.choice(cb.teams['gen7doublescustomgame']) await cb.send('', f'/utm {team}') await cb.send('', f'/accept {chall}') if downmsg in ['c', 'c:', 'pm', 'j', 'l', 'html']: await handle_chat(msg[1:], room, cb)