def _execute_pokemon_evolve(self, pokemon, cache): if pokemon.name in cache: return False response_dict = self.api.evolve_pokemon(pokemon_id=pokemon.id) if response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("result", 0) == 1: self.emit_event( "pokemon_evolved", formatted="Successfully evolved {pokemon} with CP {cp} and IV {iv}!", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "ncp": "?", "dps": "?", "xp": "?"}, ) awarded_candies = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("candy_awarded", 0) inventory.candies().get(pokemon.pokemon_id).consume(pokemon.evolution_cost - awarded_candies) inventory.pokemons().remove(pokemon.id) pokemon = Pokemon( response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("evolved_pokemon_data", {}) ) inventory.pokemons().add(pokemon) sleep(self.evolve_speed) return True else: # cache pokemons we can't evolve. Less server calls cache[pokemon.name] = 1 sleep(0.7) return False
def transfer_pokemon(self, pokemon): if self.config_transfer and (not self.bot.config.test): response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.id) else: response_dict = {"responses": {"RELEASE_POKEMON": {"candy_awarded": 0}}} if not response_dict: return False self.emit_event("pokemon_release", formatted="Exchanged {pokemon} [IV {iv}] [CP {cp}] [NCP {ncp}] [DPS {dps}]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "ncp": round(pokemon.ncp, 2), "dps": round(pokemon.dps, 2)}) if self.config_transfer and (not self.bot.config.test): candy = response_dict.get("responses", {}).get("RELEASE_POKEMON", {}).get("candy_awarded", 0) inventory.candies().get(pokemon.pokemon_id).add(candy) inventory.pokemons().remove(pokemon.id) action_delay(self.transfer_wait_min, self.transfer_wait_max) return True
def _get_award(self): response_dict = self.bot.api.get_buddy_walked() result = response_dict.get('responses', {}).get('GET_BUDDY_WALKED', {}) success = result.get('success', False) family_id = result.get('family_candy_id', 0) candy_awarded = result.get('candy_earned_count', 0) if success and family_id != 0: candy = inventory.candies().get(family_id) candy.add(candy_awarded) self.candy_awarded += candy_awarded msg = "{candy} {family} candy earned. You now have {quantity} candy!" if self.candy_limit != 0 and len(self.buddy_list) > 1: msg += " (Candy limit: {candy_earned}/{candy_limit})" if candy_awarded == 0: msg += " Probably reached candy daily limit" self.emit_event( 'buddy_candy_earned', formatted=msg, data={ 'candy': candy_awarded, 'family': inventory.candies().get(family_id).type, 'quantity': candy.quantity, 'candy_earned': self.candy_awarded, 'candy_limit': self.candy_limit } ) return True else: self.emit_event( 'buddy_candy_fail', formatted='Error trying to get candy from buddy.' ) return False
def _execute_pokemon_evolve(self, pokemon, cache): if pokemon.name in cache: return False response_dict = self.api.evolve_pokemon(pokemon_id=pokemon.id) if response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('result', 0) == 1: self.emit_event( 'pokemon_evolved', formatted="Successfully evolved {pokemon} with CP {cp} and IV {iv}!", data={ 'pokemon': pokemon.name, 'iv': pokemon.iv, 'cp': pokemon.cp, 'ncp': '?', 'dps': '?', 'xp': '?' } ) awarded_candies = response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('candy_awarded', 0) inventory.candies().get(pokemon.pokemon_id).consume(pokemon.evolution_cost - awarded_candies) inventory.pokemons().remove(pokemon.id) pokemon = Pokemon(response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('evolved_pokemon_data', {})) inventory.pokemons().add(pokemon) sleep(self.evolve_speed) return True else: # cache pokemons we can't evolve. Less server calls cache[pokemon.name] = 1 sleep(0.7) return False
def release_pokemon(self, pokemon): """ :type pokemon: Pokemon """ try: if self.bot.config.test: candy_awarded = 1 else: response_dict = self.bot.api.release_pokemon( pokemon_id=pokemon.id) candy_awarded = response_dict['responses']['RELEASE_POKEMON'][ 'candy_awarded'] except KeyError: return # We could refresh here too, but adding 1 saves a inventory request candy = inventory.candies().get(pokemon.pokemon_id) candy.add(candy_awarded) inventory.pokemons().remove(pokemon.id) self.bot.metrics.released_pokemon() self.emit_event( 'pokemon_release', formatted='Exchanged {pokemon} [CP {cp}] [IV {iv}] for candy.', data={ 'pokemon': pokemon.name, 'cp': pokemon.cp, 'iv': pokemon.iv, 'ncp': pokemon.cp_percent, 'dps': pokemon.moveset.dps }) action_delay(self.transfer_wait_min, self.transfer_wait_max)
def work(self): if not self._should_run(): return filtered_list, filtered_dict = self._sort_and_filter() pokemon_to_be_evolved = 0 pokemon_ids = [] for pokemon in filtered_list: if pokemon.pokemon_id not in pokemon_ids: pokemon_ids.append(pokemon.pokemon_id) candy = inventory.candies().get(pokemon.pokemon_id) pokemon_to_be_evolved = pokemon_to_be_evolved + min( candy.quantity / (pokemon.evolution_cost - 1), filtered_dict[pokemon.pokemon_id]) self._log_update_if_should(pokemon_to_be_evolved, self.min_pokemon_to_be_evolved) has_minimum_to_evolve = pokemon_to_be_evolved >= self.min_pokemon_to_be_evolved if has_minimum_to_evolve: if self.use_lucky_egg: self._use_lucky_egg() cache = {} for pokemon in filtered_list: if pokemon.can_evolve_now(): self._execute_pokemon_evolve(pokemon, cache)
def get_worth_pokemons(self, pokemons, closest_first=False): if self.config_hunt_all: worth_pokemons = pokemons else: worth_pokemons = [] # worth_pokemons += [p for p in pokemons if not inventory.pokedex().seen(p["pokemon_id"])] if self.config_hunt_vip: worth_pokemons += [ p for p in pokemons if p["name"] in self.bot.config.vips ] if self.config_target_family_of_vip or self.config_treat_family_of_vip_as_vip: worth_pokemons += [ p for p in pokemons if (p not in worth_pokemons) and self._is_family_of_vip(p) ] if self.config_hunt_pokedex: worth_pokemons += [ p for p in pokemons if (p not in worth_pokemons) and self._is_needed_pokedex(p) ] if closest_first: worth_pokemons.sort(key=lambda p: p["distance"]) else: worth_pokemons.sort(key=lambda p: inventory.candies().get(p[ "pokemon_id"]).quantity) return worth_pokemons
def get_buddy_walked(self, pokemon): if not self.bot.config.test: response_dict = self.bot.api.get_buddy_walked() else: response_dict = {"responses": {"GET_BUDDY_WALKED": {"success": True, "family_candy_id": 0, "candy_earned_count": 0}}} if not response_dict: return False success = response_dict.get("responses", {}).get("GET_BUDDY_WALKED", {}).get("success", False) if not success: return False family_candy_id = response_dict.get("responses", {}).get("GET_BUDDY_WALKED", {}).get("family_candy_id", 0) candy_earned_count = response_dict.get("responses", {}).get("GET_BUDDY_WALKED", {}).get("candy_earned_count", 0) candy = inventory.candies().get(family_candy_id) if not self.bot.config.test: candy.add(candy_earned_count) self.emit_event("buddy_reward", formatted="Buddy {pokemon} rewards {family} candies [+{candy_earned} candies] [{candy} candies]", data={"pokemon": pokemon.name, "family": candy.type, "candy_earned": candy_earned_count, "candy": candy.quantity}) if not self.bot.config.test: action_delay(self.config_action_wait_min, self.config_action_wait_max) return True
def upgrade_pokemon(self, pokemon): level = int(pokemon.level * 2) - 1 candy = inventory.candies().get(pokemon.pokemon_id) for i in range(level, 80): upgrade_cost = self.pokemon_upgrade_cost[i - 1] upgrade_candy_cost = upgrade_cost[0] upgrade_stardust_cost = upgrade_cost[1] if self.config_upgrade and (not self.bot.config.test): response_dict = self.bot.api.upgrade_pokemon( pokemon_id=pokemon.unique_id) else: response_dict = { "responses": { "UPGRADE_POKEMON": { "result": SUCCESS } } } if not response_dict: return False result = response_dict.get("responses", {}).get("UPGRADE_POKEMON", {}).get("result", 0) if result != SUCCESS: return False upgrade = response_dict.get("responses", {}).get( "UPGRADE_POKEMON", {}).get("upgraded_pokemon", {}) if self.config_upgrade and (not self.bot.config.test): candy.consume(upgrade_candy_cost) self.stardust_count -= upgrade_stardust_cost self.emit_event( "pokemon_upgraded", formatted= "Upgraded {pokemon} [IV {iv}] [CP {cp}] [{candy} candies] [{stardust} stardust]", data={ "pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "candy": candy.quantity, "stardust": self.stardust_count }) if self.config_upgrade and (not self.bot.config.test): inventory.pokemons().remove(pokemon.unique_id) new_pokemon = inventory.Pokemon(upgrade) inventory.pokemons().add(new_pokemon) action_delay(self.config_transfer_wait_min, self.config_transfer_wait_max) return True
def release_pokemon(self, pokemon): """ :type pokemon: Pokemon """ try: if self.bot.config.test: candy_awarded = 1 else: response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.id) candy_awarded = response_dict['responses']['RELEASE_POKEMON']['candy_awarded'] except KeyError: return # We could refresh here too, but adding 1 saves a inventory request candy = inventory.candies().get(pokemon.pokemon_id) candy.add(candy_awarded) inventory.pokemons().remove(pokemon.id) self.bot.metrics.released_pokemon() self.emit_event( 'pokemon_release', formatted='Exchanged {pokemon} [CP {cp}] [IV {iv}] for candy.', data={ 'pokemon': pokemon.name, 'cp': pokemon.cp, 'iv': pokemon.iv, 'ncp': pokemon.cp_percent, 'dps': pokemon.moveset.dps } ) action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max)
def save_web_inventory(self): web_inventory = os.path.join(_base_dir, "web", "inventory-%s.json" % self.bot.config.username) with open(web_inventory, "r") as infile: ii = json.load(infile) ii = [x for x in ii if not x.get("inventory_item_data", {}).get("pokedex_entry", None)] ii = [x for x in ii if not x.get("inventory_item_data", {}).get("candy", None)] ii = [x for x in ii if not x.get("inventory_item_data", {}).get("item", None)] ii = [x for x in ii if not x.get("inventory_item_data", {}).get("pokemon_data", None)] for pokedex in inventory.pokedex().all(): ii.append({"inventory_item_data": {"pokedex_entry": pokedex}}) for family_id, candy in inventory.candies()._data.items(): ii.append({"inventory_item_data": {"candy": {"family_id": family_id, "candy": candy.quantity}}}) for item_id, item in inventory.items()._data.items(): ii.append({"inventory_item_data": {"item": {"item_id": item_id, "count": item.count}}}) for pokemon in inventory.pokemons().all(): ii.append({"inventory_item_data": {"pokemon_data": pokemon._data}}) with open(web_inventory, "w") as outfile: json.dump(ii, outfile)
def release_pokemon(self, pokemon): """ :type pokemon: Pokemon """ try: if self.bot.config.test: candy_awarded = 1 else: request = self.bot.api.create_request() request.release_pokemon(pokemon_id=pokemon.unique_id) response_dict = request.call() candy_awarded = response_dict['responses'][ 'RELEASE_POKEMON']['candy_awarded'] except KeyError: return # We could refresh here too, but adding 1 saves a inventory request candy = inventory.candies().get(pokemon.pokemon_id) candy.add(candy_awarded) inventory.pokemons().remove(pokemon.unique_id) self.bot.metrics.released_pokemon() self.emit_event( 'pokemon_release', data={ 'pokemon': pokemon.name, 'iv': pokemon.iv, 'cp': pokemon.cp, 'ivcp': pokemon.ivcp, 'candy': candy.quantity, 'candy_type': candy.type }, formatted="Released {} (CP: {}, IV: {}, IVCP: {:.2f}) You now have" " {} {} candies".format(pokemon.name, pokemon.cp, pokemon.iv, pokemon.ivcp, candy.quantity, candy.type) ) with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='transfer_log'") result = c.fetchone() while True: if result[0] == 1: conn.execute('''INSERT INTO transfer_log (pokemon, iv, cp) VALUES (?, ?, ?)''', (pokemon.name, pokemon.iv, pokemon.cp)) break else: self.emit_event( 'transfer_log', sender=self, level='info', formatted="transfer_log table not found, skipping log" ) break action_delay(self.transfer_wait_min, self.transfer_wait_max)
def _execute_pokemon_evolve(self, pokemon, cache): if pokemon.name in cache: return False response_dict = self.bot.api.evolve_pokemon(pokemon_id=pokemon.unique_id) if response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('result', 0) == 1: xp = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("experience_awarded", 0) evolution = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("evolved_pokemon_data", {}) awarded_candies = response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('candy_awarded', 0) candy = inventory.candies().get(pokemon.pokemon_id) candy.consume(pokemon.evolution_cost - awarded_candies) self.emit_event( 'pokemon_evolved', formatted="*Evolved {}* (IV {}) (CP {}) ({} candies) (+{} xp)".format(pokemon.name, pokemon.iv, pokemon.cp, candy.quantity, xp), data={ 'pokemon': pokemon.name, 'iv': pokemon.iv, 'cp': pokemon.cp, 'candy': candy.quantity, 'xp': xp, } ) inventory.pokemons().remove(pokemon.unique_id) new_pokemon = inventory.Pokemon(evolution) inventory.pokemons().add(new_pokemon) inventory.player().exp += xp action_delay(self.min_evolve_speed, self.max_evolve_speed) evolve_result = True else: # cache pokemons we can't evolve. Less server calls cache[pokemon.name] = 1 sleep(0.7) evolve_result = False with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='evolve_log'") result = c.fetchone() while True: if result[0] == 1: conn.execute('''INSERT INTO evolve_log (pokemon, iv, cp) VALUES (?, ?, ?)''', (pokemon.name, pokemon.iv, pokemon.cp)) break else: self.emit_event( 'evolve_log', sender=self, level='info', formatted="evolve_log table not found, skipping log" ) break return evolve_result
def release_pokemon(self, pokemon): """ :type pokemon: Pokemon """ try: if self.bot.config.test: candy_awarded = 1 else: request = self.bot.api.create_request() request.release_pokemon(pokemon_id=pokemon.unique_id) response_dict = request.call() candy_awarded = response_dict['responses']['RELEASE_POKEMON'][ 'candy_awarded'] except KeyError: return # We could refresh here too, but adding 1 saves a inventory request candy = inventory.candies().get(pokemon.pokemon_id) candy.add(candy_awarded) inventory.pokemons().remove(pokemon.unique_id) self.bot.metrics.released_pokemon() self.emit_event( 'pokemon_release', data={ 'pokemon': pokemon.name, 'iv': pokemon.iv, 'cp': pokemon.cp, 'ivcp': pokemon.ivcp, 'candy': candy.quantity, 'candy_type': candy.type }, formatted="Released {} (CP: {}, IV: {}, IVCP: {:.2f}) You now have" " {} {} candies".format(pokemon.name, pokemon.cp, pokemon.iv, pokemon.ivcp, candy.quantity, candy.type)) with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='transfer_log'" ) result = c.fetchone() while True: if result[0] == 1: conn.execute( '''INSERT INTO transfer_log (pokemon, iv, cp) VALUES (?, ?, ?)''', (pokemon.name, pokemon.iv, pokemon.cp)) break else: self.emit_event( 'transfer_log', sender=self, level='info', formatted="transfer_log table not found, skipping log") break action_delay(self.transfer_wait_min, self.transfer_wait_max)
def _execute_pokemon_evolve(self, pokemon, cache): if pokemon.name in cache: return False response_dict = self.api.evolve_pokemon(pokemon_id=pokemon.unique_id) if response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('result', 0) == 1: xp = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("experience_awarded", 0) evolution = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("evolved_pokemon_data", {}) awarded_candies = response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('candy_awarded', 0) candy = inventory.candies().get(pokemon.pokemon_id) candy.consume(pokemon.evolution_cost - awarded_candies) self.emit_event( 'pokemon_evolved', formatted="*Evolved {}* (IV {}) (CP {}) ({} candies) (+{} xp)".format(pokemon.name, pokemon.iv, pokemon.cp, candy.quantity, xp), data={ 'pokemon': pokemon.name, 'iv': pokemon.iv, 'cp': pokemon.cp, 'candy': candy.quantity, 'xp': xp, } ) inventory.pokemons().remove(pokemon.unique_id) new_pokemon = inventory.Pokemon(evolution) inventory.pokemons().add(new_pokemon) inventory.player().exp += xp action_delay(self.min_evolve_speed, self.max_evolve_speed) evolve_result = True else: # cache pokemons we can't evolve. Less server calls cache[pokemon.name] = 1 sleep(0.7) evolve_result = False with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='evolve_log'") result = c.fetchone() while True: if result[0] == 1: conn.execute('''INSERT INTO evolve_log (pokemon, iv, cp) VALUES (?, ?, ?)''', (pokemon.name, pokemon.iv, pokemon.cp)) break else: self.emit_event( 'evolve_log', sender=self, level='info', formatted="evolve_log table not found, skipping log" ) break return evolve_result
def get_nearby_pokemons(self): radius = self.config_max_distance pokemons = [ p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius ] if 'wild_pokemons' in self.bot.cell: for pokemon in self.bot.cell['wild_pokemons']: if pokemon['encounter_id'] in map( lambda pokemon: pokemon['encounter_id'], pokemons): # Already added this Pokemon continue if self.get_distance(self.bot.start_position, pokemon) <= radius: pokemons.append(pokemon) if 'catchable_pokemons' in self.bot.cell: for pokemon in self.bot.cell['catchable_pokemons']: if pokemon['encounter_id'] in map( lambda pokemon: pokemon['encounter_id'], pokemons): # Already added this Pokemon continue if self.get_distance(self.bot.start_position, pokemon) <= radius: pokemons.append(pokemon) for pokemon in pokemons: if "pokemon_data" in pokemon: pokemon["pokemon_id"] = pokemon["pokemon_data"]["pokemon_id"] pokemon["name"] = inventory.pokemons().name_for( pokemon["pokemon_id"]) if "name" not in pokemon and "pokemon_id" not in pokemon: self.logger.warning("Strange result? %s" % pokemon) # Skip this one! continue pokemon["distance"] = self.get_distance(self.bot.position, pokemon) if "name" not in pokemon: pokemon["name"] = inventory.pokemons().name_for( pokemon["pokemon_id"]) if "pokemon_id" not in pokemon: pokemon["pokemon_id"] = inventory.pokemons().id_for( pokemon["name"]) pokemon["candies"] = inventory.candies().get( pokemon["pokemon_id"]).quantity # Pokemon also has a fort_id of the PokeStop the Pokemon is hiding at. # We should set our first destination at that Pokestop. pokemons.sort(key=lambda p: p["distance"]) return pokemons
def transfer_pokemon(self, pokemon): if self.config_transfer and (not self.bot.config.test): response_dict = self.bot.api.release_pokemon( pokemon_id=pokemon.unique_id) else: response_dict = { "responses": { "RELEASE_POKEMON": { "candy_awarded": 0 } } } if not response_dict: return False candy_awarded = response_dict.get("responses", {}).get("RELEASE_POKEMON", {}).get("candy_awarded", 0) candy = inventory.candies().get(pokemon.pokemon_id) if self.config_transfer and (not self.bot.config.test): candy.add(candy_awarded) self.emit_event( "pokemon_release", formatted= "Exchanged {pokemon} [IV {iv}] [CP {cp}] [{candy} candies]", data={ "pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "candy": candy.quantity }) if self.config_transfer and (not self.bot.config.test): inventory.pokemons().remove(pokemon.unique_id) with self.bot.database as db: cursor = db.cursor() cursor.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='transfer_log'" ) db_result = cursor.fetchone() if db_result[0] == 1: db.execute( "INSERT INTO transfer_log (pokemon, iv, cp) VALUES (?, ?, ?)", (pokemon.name, pokemon.iv, pokemon.cp)) action_delay(self.config_action_wait_min, self.config_action_wait_max) return True
def evolve_pokemon(self, pokemon): while pokemon.unique_id in self.evolution_map: pokemon = self.evolution_map[pokemon.unique_id] if self.config_evolve and (not self.bot.config.test): response_dict = self.bot.api.evolve_pokemon(pokemon_id=pokemon.unique_id) else: response_dict = {"responses": {"EVOLVE_POKEMON": {"result": SUCCESS}}} if not response_dict: return False result = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("result", 0) if result != SUCCESS: return False xp = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("experience_awarded", 0) candy_awarded = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("candy_awarded", 0) candy = inventory.candies().get(pokemon.pokemon_id) evolution = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("evolved_pokemon_data", {}) if self.config_evolve and (not self.bot.config.test): candy.consume(pokemon.evolution_cost - candy_awarded) inventory.player().exp += xp self.emit_event("pokemon_evolved", formatted="Evolved {pokemon} [IV {iv}] [CP {cp}] [{candy} candies] [+{xp} xp]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "candy": candy.quantity, "xp": xp}) if self.config_evolve and (not self.bot.config.test): new_pokemon = inventory.Pokemon(evolution) self.evolution_map[pokemon.unique_id] = new_pokemon inventory.pokemons().remove(pokemon.unique_id) inventory.pokemons().add(new_pokemon) with self.bot.database as db: cursor = db.cursor() cursor.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='evolve_log'") db_result = cursor.fetchone() if db_result[0] == 1: db.execute("INSERT INTO evolve_log (pokemon, iv, cp) VALUES (?, ?, ?)", (pokemon.name, pokemon.iv, pokemon.cp)) sleep(self.config_evolve_time, 0.1) return True
def get_buddy_walked(self, pokemon): if not self.bot.config.test: response_dict = self.bot.api.get_buddy_walked() else: response_dict = { "responses": { "GET_BUDDY_WALKED": { "success": True, "family_candy_id": 0, "candy_earned_count": 0 } } } if not response_dict: return False success = response_dict.get("responses", {}).get("GET_BUDDY_WALKED", {}).get("success", False) if not success: return False candy_earned_count = response_dict.get("responses", {}).get( "GET_BUDDY_WALKED", {}).get("candy_earned_count", 0) if candy_earned_count == 0: return family_candy_id = self.get_family_id(pokemon) candy = inventory.candies().get(family_candy_id) if not self.bot.config.test: candy.add(candy_earned_count) self.emit_event( "buddy_reward", formatted= "Buddy {pokemon} rewards {family} candies [+{candy_earned} candies] [{candy} candies]", data={ "pokemon": pokemon.name, "family": candy.type, "candy_earned": candy_earned_count, "candy": candy.quantity }) if not self.bot.config.test: action_delay(self.config_action_wait_min, self.config_action_wait_max) return True
def save_web_inventory(self): web_inventory = os.path.join( _base_dir, "web", "inventory-%s.json" % self.bot.config.username) with open(web_inventory, "r") as infile: ii = json.load(infile) ii = [ x for x in ii if not x.get("inventory_item_data", {}).get("pokedex_entry", None) ] ii = [ x for x in ii if not x.get("inventory_item_data", {}).get("candy", None) ] ii = [ x for x in ii if not x.get("inventory_item_data", {}).get("item", None) ] ii = [ x for x in ii if not x.get("inventory_item_data", {}).get("pokemon_data", None) ] for pokedex in inventory.pokedex().all(): ii.append({"inventory_item_data": {"pokedex_entry": pokedex}}) for family_id, candy in inventory.candies()._data.items(): ii.append({ "inventory_item_data": { "candy": { "family_id": family_id, "candy": candy.quantity } } }) for item_id, item in inventory.items()._data.items(): ii.append({ "inventory_item_data": { "item": { "item_id": item_id, "count": item.count } } }) for pokemon in inventory.pokemons().all(): ii.append({"inventory_item_data": {"pokemon_data": pokemon._data}}) with open(web_inventory, "w") as outfile: json.dump(ii, outfile)
def get_nearby_pokemons(self): radius = self.config_max_distance pokemons = [p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius] for pokemon in pokemons: pokemon["distance"] = self.get_distance(self.bot.position, p) pokemon["name"] = inventory.pokemons().name_for(pokemon["pokemon_id"]) pokemon["candies"] = inventory.candies().get(pokemon["pokemon_id"]).quantity pokemons.sort(key=lambda p: p["distance"]) return pokemons
def _pokemon_matches_config(self, config, pokemon, default_logic='and'): pokemon_config = config.get(pokemon.name, config.get('any')) if not pokemon_config: return False catch_results = { 'ncp': False, 'cp': False, 'iv': False, } candies = inventory.candies().get(pokemon.pokemon_id).quantity threshold = pokemon_config.get('candy_threshold', -1) if (threshold > 0 and candies >= threshold): self.emit_event( 'ignore_candy_above_thresold', level='info', formatted= 'Amount of candies for {name} is {amount}, greater than threshold {threshold}', data={ 'name': pokemon.name, 'amount': candies, 'threshold': threshold }) return False if pokemon_config.get('never_catch', False): return False if pokemon_config.get('always_catch', False): return True catch_ncp = pokemon_config.get('catch_above_ncp', 0.8) if pokemon.cp_percent > catch_ncp: catch_results['ncp'] = True catch_cp = pokemon_config.get('catch_above_cp', 1200) if pokemon.cp > catch_cp: catch_results['cp'] = True catch_iv = pokemon_config.get('catch_above_iv', 0.8) if pokemon.iv > catch_iv: catch_results['iv'] = True # check if encountered pokemon is our locked pokemon if self.bot.capture_locked and self.bot.capture_locked != pokemon.pokemon_id: return False return LOGIC_TO_FUNCTION[pokemon_config.get( 'logic', default_logic)](*catch_results.values())
def _execute_pokemon_evolve(self, pokemon, cache): if pokemon.name in cache: return False response_dict = self.api.evolve_pokemon(pokemon_id=pokemon.id) if response_dict.get('responses', {}).get('EVOLVE_POKEMON', {}).get('result', 0) == 1: self.emit_event( 'pokemon_evolved', formatted="Successfully evolved {pokemon} with CP {cp} and IV {iv}!", data={ 'pokemon': pokemon.name, 'iv': pokemon.iv, 'cp': pokemon.cp } ) inventory.candies().get(pokemon.pokemon_id).consume(pokemon.evolution_cost) sleep(self.evolve_speed) return True else: # cache pokemons we can't evolve. Less server calls cache[pokemon.name] = 1 sleep(0.7) return False
def upgrade_pokemon(self, pokemon): upgrade_level = min(self.config_upgrade_level, inventory.player().level + 1.5, 40) candy = inventory.candies().get(pokemon.pokemon_id) for i in range(int(pokemon.level * 2), int(upgrade_level * 2)): upgrade_cost = self.pokemon_upgrade_cost[i - 2] upgrade_candy_cost = upgrade_cost[0] upgrade_stardust_cost = upgrade_cost[1] if self.config_upgrade and (not self.bot.config.test): request = self.bot.api.create_request() request.upgrade_pokemon(pokemon_id=pokemon.unique_id) response_dict = request.call() else: response_dict = {"responses": {"UPGRADE_POKEMON": {"result": SUCCESS}}} if not response_dict: return False result = response_dict.get("responses", {}).get("UPGRADE_POKEMON", {}).get("result", 0) if result != SUCCESS: return False upgrade = response_dict.get("responses", {}).get("UPGRADE_POKEMON", {}).get("upgraded_pokemon", {}) if self.config_upgrade and (not self.bot.config.test): candy.consume(upgrade_candy_cost) self.bot.stardust -= upgrade_stardust_cost new_pokemon = inventory.Pokemon(upgrade) self.emit_event("pokemon_upgraded", formatted="Upgraded {pokemon} [IV {iv}] [CP {cp} -> {new_cp}] [{candy} candies] [{stardust} stardust]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "new_cp": new_pokemon.cp, "candy": candy.quantity, "stardust": self.bot.stardust}) if self.config_upgrade and (not self.bot.config.test): inventory.pokemons().remove(pokemon.unique_id) new_pokemon = inventory.Pokemon(upgrade) inventory.pokemons().add(new_pokemon) pokemon = new_pokemon action_delay(self.config_action_wait_min, self.config_action_wait_max) return True
def _pokemon_matches_config(self, config, pokemon, default_logic='and'): pokemon_config = config.get(pokemon.name, config.get('any')) if not pokemon_config: return False catch_results = { 'ncp': False, 'cp': False, 'iv': False, } candies = inventory.candies().get(pokemon.pokemon_id).quantity threshold = pokemon_config.get('candy_threshold', -1) if (threshold > 0 and candies >= threshold): self.emit_event( 'ignore_candy_above_thresold', level='info', formatted='Amount of candies for {name} is {amount}, greater than threshold {threshold}', data={ 'name': pokemon.name, 'amount': candies, 'threshold': threshold } ) return False if pokemon_config.get('never_catch', False): return False if pokemon_config.get('always_catch', False): return True catch_ncp = pokemon_config.get('catch_above_ncp', 0.8) if pokemon.cp_percent > catch_ncp: catch_results['ncp'] = True catch_cp = pokemon_config.get('catch_above_cp', 1200) if pokemon.cp > catch_cp: catch_results['cp'] = True catch_iv = pokemon_config.get('catch_above_iv', 0.8) if pokemon.iv > catch_iv: catch_results['iv'] = True # check if encountered pokemon is our locked pokemon if self.bot.capture_locked and self.bot.capture_locked != pokemon.pokemon_id: return False return LOGIC_TO_FUNCTION[pokemon_config.get('logic', default_logic)](*catch_results.values())
def evolve_pokemon(self, pokemon): if self.config_evolve and (not self.bot.config.test): response_dict = self.bot.api.evolve_pokemon(pokemon_id=pokemon.id) else: response_dict = {"responses": {"EVOLVE_POKEMON": {"result": 1}}} if not response_dict: return False result = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("result", 0) if result != SUCCESS: return False xp = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("experience_awarded", 0) candy = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("candy_awarded", 0) evolution = response_dict.get("responses", {}).get("EVOLVE_POKEMON", {}).get("evolved_pokemon_data", {}) self.emit_event("pokemon_evolved", formatted="Evolved {pokemon} [IV {iv}] [CP {cp}] [NCP {ncp}] [DPS {dps}] [+{xp} xp]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "ncp": round(pokemon.ncp, 2), "dps": round(pokemon.dps, 2), "xp": xp}) if self.config_evolve and (not self.bot.config.test): inventory.candies().get(pokemon.pokemon_id).consume(pokemon.evolution_cost - candy) inventory.pokemons().remove(pokemon.id) new_pokemon = inventory.Pokemon(evolution) inventory.pokemons().add(new_pokemon) sleep(self.config_evolve_time) return True
def get_nearby_pokemons(self): radius = self.config_max_distance pokemons = [p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius] for pokemon in pokemons: pokemon["distance"] = self.get_distance(self.bot.position, pokemon) pokemon["name"] = inventory.pokemons().name_for(pokemon["pokemon_id"]) pokemon["candies"] = inventory.candies().get(pokemon["pokemon_id"]).quantity # Pokemon also has a fort_id of the PokeStop the Pokemon is hiding at. # We should set our first destination at that Pokestop. pokemons.sort(key=lambda p: p["distance"]) return pokemons
def get_worth_pokemons(self, pokemons): if self.config_hunt_all: worth_pokemons = pokemons else: worth_pokemons = [] if self.config_hunt_vip: worth_pokemons += [p for p in pokemons if p["name"] in self.bot.config.vips] if self.config_hunt_pokedex: worth_pokemons += [p for p in pokemons if (p not in worth_pokemons) and self._is_needed_pokedex(p)] worth_pokemons.sort(key=lambda p: inventory.candies().get(p["pokemon_id"]).quantity) return worth_pokemons
def get_worth_pokemons(self, pokemons): if self.config_hunt_all: worth_pokemons = pokemons else: worth_pokemons = [] if self.config_hunt_vip: worth_pokemons += [p for p in pokemons if p["name"] in self.bot.config.vips] if self.config_hunt_pokedex: worth_pokemons += [p for p in pokemons if (p not in worth_pokemons) and any(not inventory.pokedex().seen(fid) for fid in self.get_family_ids(p))] worth_pokemons.sort(key=lambda p: inventory.candies().get(p["pokemon_id"]).quantity) return worth_pokemons
def get_nearby_pokemons(self): radius = self.config_max_distance pokemons = [p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius] if 'wild_pokemons' in self.bot.cell: for pokemon in self.bot.cell['wild_pokemons']: if pokemon['encounter_id'] in map(lambda pokemon: pokemon['encounter_id'], pokemons): # Already added this Pokemon continue if self.get_distance(self.bot.start_position, pokemon) <= radius: pokemons.append(pokemon) if 'catchable_pokemons' in self.bot.cell: for pokemon in self.bot.cell['catchable_pokemons']: if pokemon['encounter_id'] in map(lambda pokemon: pokemon['encounter_id'], pokemons): # Already added this Pokemon continue if self.get_distance(self.bot.start_position, pokemon) <= radius: pokemons.append(pokemon) for pokemon in pokemons: if "pokemon_data" in pokemon: pokemon["pokemon_id"] = pokemon["pokemon_data"]["pokemon_id"] pokemon["name"] = inventory.pokemons().name_for(pokemon["pokemon_id"]) if "name" not in pokemon and "pokemon_id" not in pokemon: self.logger.warning("Strange result? %s" % pokemon) # Skip this one! continue pokemon["distance"] = self.get_distance(self.bot.position, pokemon) if "name" not in pokemon: pokemon["name"] = inventory.pokemons().name_for(pokemon["pokemon_id"]) if "pokemon_id" not in pokemon: pokemon["pokemon_id"] = inventory.pokemons().id_for(pokemon["name"]) pokemon["candies"] = inventory.candies().get(pokemon["pokemon_id"]).quantity # Pokemon also has a fort_id of the PokeStop the Pokemon is hiding at. # We should set our first destination at that Pokestop. pokemons.sort(key=lambda p: p["distance"]) return pokemons
def get_nearby_pokemons(self): radius = self.config_max_distance pokemons = [ p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius ] for pokemon in pokemons: pokemon["distance"] = self.get_distance(self.bot.position, p) pokemon["name"] = inventory.pokemons().name_for( pokemon["pokemon_id"]) pokemon["candies"] = inventory.candies().get( pokemon["pokemon_id"]).quantity pokemons.sort(key=lambda p: p["distance"]) return pokemons
def showtop(self, chatid, num, order): if not num.isnumeric(): num = 10 else: num = int(num) if order not in ["cp", "iv"]: order = "iv" pkmns = sorted(inventory.pokemons().all(), key=lambda p: getattr(p, order), reverse=True)[:num] outMsg = "\n".join([ "*{}* (_CP:_ {}) (_IV:_ {}) (Candy:{})".format( p.name, p.cp, p.iv, inventory.candies().get(p.pokemon_id).quantity) for p in pkmns ]) self.sendMessage(chat_id=chatid, parse_mode='Markdown', text=outMsg)
def get_top(self, num, order): if not num.isnumeric(): num = 10 else: num = int(num) if order not in ["cp", "iv", "dated"]: order = "iv" pkmns = sorted(inventory.pokemons().all(), key=lambda p: getattr(p, order), reverse=True)[:num] res = [] for p in pkmns: res.append([ p.name, p.cp, p.iv, inventory.candies().get(p.pokemon_id).quantity ]) return res
def work(self): if not self._should_run(): return filtered_list, filtered_dict = self._sort_and_filter() pokemon_to_be_evolved = 0 pokemon_ids = [] for pokemon in filtered_list: if pokemon.pokemon_id not in pokemon_ids: pokemon_ids.append(pokemon.pokemon_id) candy = inventory.candies().get(pokemon.pokemon_id) pokemon_to_be_evolved = pokemon_to_be_evolved + min(candy.quantity / (pokemon.evolution_cost - 1), filtered_dict[pokemon.pokemon_id]) if pokemon_to_be_evolved >= self.min_pokemon_to_be_evolved: if self.use_lucky_egg: self._use_lucky_egg() cache = {} for pokemon in filtered_list: if pokemon.can_evolve_now(): self._execute_pokemon_evolve(pokemon, cache)
def get_worth_pokemons(self, pokemons): if self.config_hunt_all: worth_pokemons = pokemons else: worth_pokemons = [] if self.config_hunt_vip: worth_pokemons += [ p for p in pokemons if p["name"] in self.bot.config.vips ] if self.config_hunt_pokedex: worth_pokemons += [ p for p in pokemons if (p not in worth_pokemons) and self._is_needed_pokedex(p) ] worth_pokemons.sort( key=lambda p: inventory.candies().get(p["pokemon_id"]).quantity) return worth_pokemons
def _is_needed_pokedex(self, pokemon): candies = inventory.candies().get(pokemon["pokemon_id"]).quantity if candies > 150: # We have enough candies, pass on hunting this Pokemon return False # get family ids, gets ALL ids, also for previous evo! # We could see a Ivysaur on the map, and need a Bulbasaur # Then we have no need for a Ivysaur. If we see a Bulbasaur and need # a Ivysaur, then we DO need this pokemon. got_current_evo = False ids = [] for fid in self.get_family_ids(pokemon): if got_current_evo: ids += [fid] else: if fid == pokemon["pokemon_id"]: ids += [fid] got_current_evo = True # Check if we need this, or a next EVO in the Pokedex if any(not inventory.pokedex().seen(fid) for fid in ids): return True
def get_worth_pokemons(self, pokemons, closest_first=False): if self.config_hunt_all: worth_pokemons = pokemons else: worth_pokemons = [] # worth_pokemons += [p for p in pokemons if not inventory.pokedex().seen(p["pokemon_id"])] if self.config_hunt_vip: worth_pokemons += [p for p in pokemons if p["name"] in self.bot.config.vips] if self.config_target_family_of_vip or self.config_treat_family_of_vip_as_vip: worth_pokemons += [p for p in pokemons if (p not in worth_pokemons) and self._is_family_of_vip(p)] if self.config_hunt_pokedex: worth_pokemons += [p for p in pokemons if (p not in worth_pokemons) and self._is_needed_pokedex(p)] if closest_first: worth_pokemons.sort(key=lambda p: p["distance"]) else: worth_pokemons.sort(key=lambda p: inventory.candies().get(p["pokemon_id"]).quantity) return worth_pokemons
def transfer_pokemon(self, pokemon): if self.config_transfer and (not self.bot.config.test): response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.unique_id) else: response_dict = {"responses": {"RELEASE_POKEMON": {"candy_awarded": 0}}} if not response_dict: return False candy_awarded = response_dict.get("responses", {}).get("RELEASE_POKEMON", {}).get("candy_awarded", 0) candy = inventory.candies().get(pokemon.pokemon_id) if self.config_transfer and (not self.bot.config.test): candy.add(candy_awarded) self.emit_event("pokemon_release", formatted="Exchanged {pokemon} [IV {iv}] [CP {cp}] [{candy} candies]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "candy": candy.quantity}) if self.config_transfer and (not self.bot.config.test): inventory.pokemons().remove(pokemon.unique_id) with self.bot.database as db: cursor = db.cursor() cursor.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='transfer_log'") db_result = cursor.fetchone() if db_result[0] == 1: db.execute("INSERT INTO transfer_log (pokemon, iv, cp) VALUES (?, ?, ?)", (pokemon.name, pokemon.iv, pokemon.cp)) action_delay(self.config_action_wait_min, self.config_action_wait_max) return True
def transfer_pokemon(self, pokemons): error_codes = { 0: 'UNSET', 1: 'SUCCESS', 2: 'POKEMON_DEPLOYED', 3: 'FAILED', 4: 'ERROR_POKEMON_IS_EGG', 5: 'ERROR_POKEMON_IS_BUDDY' } if self.config_bulktransfer_enabled and len(pokemons) > 1: while len(pokemons) > 0: action_delay(self.config_action_wait_min, self.config_action_wait_max) pokemon_ids = [] count = 0 transfered = [] while len(pokemons) > 0 and count < self.config_max_bulktransfer: pokemon = pokemons.pop() transfered.append(pokemon) pokemon_ids.append(pokemon.unique_id) count = count + 1 try: if self.config_transfer: response_dict = self.bot.api.release_pokemon(pokemon_ids=pokemon_ids) result = response_dict['responses']['RELEASE_POKEMON']['result'] if result != 1: self.logger.error(u'Error while transfer pokemon: {}'.format(error_codes[result])) return False except Exception: return False for pokemon in transfered: candy = inventory.candies().get(pokemon.pokemon_id) if self.config_transfer and (not self.bot.config.test): candy.add(1) self.emit_event("pokemon_release", formatted="Exchanged {pokemon} [IV {iv}] [CP {cp}] [{candy} candies]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "candy": candy.quantity}) if self.config_transfer: inventory.pokemons().remove(pokemon.unique_id) with self.bot.database as db: cursor = db.cursor() cursor.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='transfer_log'") db_result = cursor.fetchone() if db_result[0] == 1: db.execute("INSERT INTO transfer_log (pokemon, iv, cp) VALUES (?, ?, ?)", (pokemon.name, pokemon.iv, pokemon.cp)) else: for pokemon in pokemons: if self.config_transfer and (not self.bot.config.test): response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.unique_id) else: response_dict = {"responses": {"RELEASE_POKEMON": {"candy_awarded": 0}}} if not response_dict: return False candy_awarded = response_dict.get("responses", {}).get("RELEASE_POKEMON", {}).get("candy_awarded", 0) candy = inventory.candies().get(pokemon.pokemon_id) if self.config_transfer and (not self.bot.config.test): candy.add(candy_awarded) self.emit_event("pokemon_release", formatted="Exchanged {pokemon} [IV {iv}] [CP {cp}] [{candy} candies]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp, "candy": candy.quantity}) if self.config_transfer and (not self.bot.config.test): inventory.pokemons().remove(pokemon.unique_id) with self.bot.database as db: cursor = db.cursor() cursor.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='transfer_log'") db_result = cursor.fetchone() if db_result[0] == 1: db.execute("INSERT INTO transfer_log (pokemon, iv, cp) VALUES (?, ?, ?)", (pokemon.name, pokemon.iv, pokemon.cp)) action_delay(self.config_action_wait_min, self.config_action_wait_max) return True
def get_evolution_plan(self, family_id, family_list, keep, try_evolve, try_upgrade): candies = inventory.candies().get(family_id).quantity family_name = inventory.Pokemons().name_for(family_id) # All the rest is crap, for now crap = list(family_list) crap = [p for p in crap if p not in keep] crap = [p for p in crap if not p.in_fort and not p.is_favorite and not (p.unique_id == self.buddyid)] crap.sort(key=lambda p: (p.iv, p.cp), reverse=True) # We will gain a candy whether we choose to transfer or evolve these Pokemon candies += len(crap) evolve = [] for pokemon in try_evolve: pokemon_id = pokemon.pokemon_id needed_evolution_item = inventory.pokemons().evolution_item_for(pokemon_id) if needed_evolution_item is not None: # We need a special Item to evolve this Pokemon! item = inventory.items().get(needed_evolution_item) needed = inventory.pokemons().evolution_items_needed_for(pokemon_id) if item.count < needed: self.logger.info("To evolve a {} we need {} of {}. We have {}".format(pokemon.name, needed, item.name, item.count)) continue if self.config_evolve_to_final: pokemon_id = pokemon.pokemon_id while inventory.pokemons().has_next_evolution(pokemon_id): candies -= inventory.pokemons().evolution_cost_for(pokemon_id) pokemon_id = inventory.pokemons().next_evolution_ids_for(pokemon_id)[0] else: candies -= pokemon.evolution_cost if candies < 0: continue if self.config_evolve_to_final: pokemon_id = pokemon.pokemon_id while inventory.pokemons().has_next_evolution(pokemon_id): candies += 1 evolve.append(pokemon) pokemon_id = inventory.pokemons().next_evolution_ids_for(pokemon_id)[0] else: candies += 1 evolve.append(pokemon) upgrade = [] upgrade_level = min(self.config_upgrade_level, inventory.player().level + 1.5, 40) for pokemon in try_upgrade: if pokemon.level >= upgrade_level: continue full_upgrade_candy_cost = 0 full_upgrade_stardust_cost = 0 for i in range(int(pokemon.level * 2), int(upgrade_level * 2)): upgrade_cost = self.pokemon_upgrade_cost[i - 2] full_upgrade_candy_cost += upgrade_cost[0] full_upgrade_stardust_cost += upgrade_cost[1] candies -= full_upgrade_candy_cost self.ongoing_stardust_count -= full_upgrade_stardust_cost if (candies < 0) or (self.ongoing_stardust_count < 0): continue upgrade.append(pokemon) if (not self.config_evolve_for_xp) or (family_name in self.config_evolve_for_xp_blacklist): xp = [] transfer = crap elif self.config_evolve_for_xp_whitelist and (family_name not in self.config_evolve_for_xp_whitelist): xp = [] transfer = crap else: # Compute how many crap we should keep if we want to batch evolve them for xp lowest_evolution_cost = inventory.pokemons().evolution_cost_for(family_id) # transfer + keep_for_xp = len(crap) # leftover_candies = candies - len(crap) + transfer * 1 # keep_for_xp = (leftover_candies - 1) / (lowest_evolution_cost - 1) # keep_for_xp = (candies - len(crap) + transfer - 1) / (lowest_evolution_cost - 1) # keep_for_xp = (candies - keep_for_xp - 1) / (lowest_evolution_cost - 1) if (candies > 0) and lowest_evolution_cost: keep_for_xp = int((candies - 1) / lowest_evolution_cost) else: keep_for_xp = 0 xp = [p for p in crap if p.has_next_evolution() and p.evolution_cost == lowest_evolution_cost][:keep_for_xp] transfer = [p for p in crap if p not in xp] return (transfer, evolve, upgrade, xp)
def _do_catch(self, pokemon, encounter_id, catch_rate_by_ball, is_vip=False): # settings that may be exposed at some point """ :type pokemon: Pokemon """ berry_id = ITEM_RAZZBERRY maximum_ball = ITEM_ULTRABALL if is_vip else ITEM_GREATBALL ideal_catch_rate_before_throw = self.vip_berry_threshold if is_vip else self.berry_threshold berry_count = self.inventory.get(ITEM_RAZZBERRY).count ball_count = {} for ball_id in [ITEM_POKEBALL, ITEM_GREATBALL, ITEM_ULTRABALL]: ball_count[ball_id] = self.inventory.get(ball_id).count # use `min_ultraball_to_keep` from config if is not None min_ultraball_to_keep = ball_count[ITEM_ULTRABALL] if self.min_ultraball_to_keep is not None: if self.min_ultraball_to_keep >= 0 and self.min_ultraball_to_keep < min_ultraball_to_keep: min_ultraball_to_keep = self.min_ultraball_to_keep used_berry = False while True: # find lowest available ball current_ball = ITEM_POKEBALL while ball_count[current_ball] == 0 and current_ball < maximum_ball: current_ball += 1 if ball_count[current_ball] == 0: self.emit_event('no_pokeballs', formatted='No usable pokeballs found!') # use untraball if there is no other balls with constraint to `min_ultraball_to_keep` if maximum_ball != ITEM_ULTRABALL and ball_count[ITEM_ULTRABALL] > min_ultraball_to_keep: maximum_ball = ITEM_ULTRABALL continue else: return WorkerResult.ERROR # check future ball count num_next_balls = 0 next_ball = current_ball while next_ball < maximum_ball: next_ball += 1 num_next_balls += ball_count[next_ball] # check if we've got berries to spare berries_to_spare = berry_count > 0 if is_vip else berry_count > num_next_balls + 30 # use a berry if we are under our ideal rate and have berries to spare changed_ball = False if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and berries_to_spare and not used_berry: new_catch_rate_by_ball = self._use_berry(berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) if new_catch_rate_by_ball != catch_rate_by_ball: catch_rate_by_ball = new_catch_rate_by_ball self.inventory.get(ITEM_RAZZBERRY).remove(1) berry_count -= 1 used_berry = True # pick the best ball to catch with best_ball = current_ball while best_ball < maximum_ball: best_ball += 1 if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and ball_count[best_ball] > 0: # if current ball chance to catch is under our ideal rate, and player has better ball - then use it current_ball = best_ball changed_ball = True # if the rate is still low and we didn't throw a berry before, throw one if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and berry_count > 0 and not used_berry: new_catch_rate_by_ball = self._use_berry(berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) if new_catch_rate_by_ball != catch_rate_by_ball: catch_rate_by_ball = new_catch_rate_by_ball self.inventory.get(ITEM_RAZZBERRY).remove(1) berry_count -= 1 used_berry = True # If we change ball then wait to simulate user selecting it if changed_ball: action_delay(self.catchsim_changeball_wait_min, self.catchsim_changeball_wait_max) # Randomize the quality of the throw # Default structure throw_parameters = {'normalized_reticle_size': 1.950, 'spin_modifier': 1.0, 'normalized_hit_position': 1.0, 'throw_type_label': 'Excellent'} self.generate_spin_parameter(throw_parameters) self.generate_throw_quality_parameters(throw_parameters) # try to catch pokemon! ball_count[current_ball] -= 1 self.inventory.get(current_ball).remove(1) # Take some time to throw the ball from config options action_delay(self.catchsim_catch_wait_min, self.catchsim_catch_wait_max) self.emit_event( 'threw_pokeball', formatted='{throw_type}{spin_label} throw! Used {ball_name}, with chance {success_percentage} ({count_left} left)', data={ 'throw_type': throw_parameters['throw_type_label'], 'spin_label': throw_parameters['spin_label'], 'ball_name': self.inventory.get(current_ball).name, 'success_percentage': self._pct(catch_rate_by_ball[current_ball]), 'count_left': ball_count[current_ball] } ) hit_pokemon = 1 if random() >= self.catch_throw_parameters_hit_rate and not is_vip: hit_pokemon = 0 response_dict = self.api.catch_pokemon( encounter_id=encounter_id, pokeball=current_ball, normalized_reticle_size=throw_parameters['normalized_reticle_size'], spawn_point_id=self.spawn_point_guid, hit_pokemon=hit_pokemon, spin_modifier=throw_parameters['spin_modifier'], normalized_hit_position=throw_parameters['normalized_hit_position'] ) try: catch_pokemon_status = response_dict['responses']['CATCH_POKEMON']['status'] except KeyError: break # retry failed pokemon if catch_pokemon_status == CATCH_STATUS_FAILED: self.emit_event( 'pokemon_capture_failed', formatted='{pokemon} capture failed.. trying again!', data={'pokemon': pokemon.name} ) used_berry = False # sleep according to flee_count and flee_duration config settings # randomly chooses a number of times to 'show' wobble animation between 1 and flee_count # multiplies this by flee_duration to get total sleep if self.catchsim_flee_count: sleep((randrange(self.catchsim_flee_count)+1) * self.catchsim_flee_duration) continue # abandon if pokemon vanished elif catch_pokemon_status == CATCH_STATUS_VANISHED: self.emit_event( 'pokemon_vanished', formatted='{pokemon} vanished!', data={ 'pokemon': pokemon.name, 'encounter_id': self.pokemon['encounter_id'], 'latitude': self.pokemon['latitude'], 'longitude': self.pokemon['longitude'], 'pokemon_id': pokemon.pokemon_id } ) if self._pct(catch_rate_by_ball[current_ball]) == 100: self.bot.softban = True # pokemon caught! elif catch_pokemon_status == CATCH_STATUS_SUCCESS: pokemon.unique_id = response_dict['responses']['CATCH_POKEMON']['captured_pokemon_id'] self.bot.metrics.captured_pokemon(pokemon.name, pokemon.cp, pokemon.iv_display, pokemon.iv) try: inventory.pokemons().add(pokemon) self.emit_event( 'pokemon_caught', formatted='Captured {pokemon}! [CP {cp}] [NCP {ncp}] [Potential {iv}] [{iv_display}] [+{exp} exp]', data={ 'pokemon': pokemon.name, 'ncp': round(pokemon.cp_percent, 2), 'cp': pokemon.cp, 'iv': pokemon.iv, 'iv_display': pokemon.iv_display, 'exp': sum(response_dict['responses']['CATCH_POKEMON']['capture_award']['xp']), 'encounter_id': self.pokemon['encounter_id'], 'latitude': self.pokemon['latitude'], 'longitude': self.pokemon['longitude'], 'pokemon_id': pokemon.pokemon_id } ) with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='catch_log'") result = c.fetchone() while True: if result[0] == 1: conn.execute('''INSERT INTO catch_log (pokemon, cp, iv, encounter_id, pokemon_id) VALUES (?, ?, ?, ?, ?)''', (pokemon.name, pokemon.cp, pokemon.iv, str(encounter_id), pokemon.pokemon_id)) break else: self.emit_event( 'catch_log', sender=self, level='info', formatted="catch_log table not found, skipping log" ) break user_data_caught = os.path.join(_base_dir, 'data', 'caught-%s.json' % self.bot.config.username) with open(user_data_caught, 'ab') as outfile: outfile.write(str(datetime.now())) json.dump({ 'pokemon': pokemon.name, 'cp': pokemon.cp, 'iv': pokemon.iv, 'encounter_id': self.pokemon['encounter_id'], 'pokemon_id': pokemon.pokemon_id }, outfile) outfile.write('\n') except IOError as e: self.logger.info('[x] Error while opening location file: %s' % e) candy = inventory.candies().get(pokemon.pokemon_id) candy.add(self.get_candy_gained_count(response_dict)) self.emit_event( 'gained_candy', formatted='You now have {quantity} {type} candy!', data = { 'quantity': candy.quantity, 'type': candy.type, }, ) self.bot.softban = False elif catch_pokemon_status == CATCH_STATUS_MISSED: self.emit_event( 'pokemon_capture_failed', formatted='Pokeball thrown to {pokemon} missed.. trying again!', data={'pokemon': pokemon.name} ) # Take some time to throw the ball from config options action_delay(self.catchsim_catch_wait_min, self.catchsim_catch_wait_max) continue break
def _pokemon_matches_config(self, config, pokemon, default_logic='and'): pokemon_config = config.get(pokemon.name, config.get('any')) if not pokemon_config: return False catch_results = { 'ncp': False, 'cp': False, 'iv': False, 'fa': True, 'ca': True } catch_logic = pokemon_config.get('logic', default_logic) candies = inventory.candies().get(pokemon.pokemon_id).quantity threshold = pokemon_config.get('candy_threshold', -1) if threshold > 0 and candies >= threshold: # Got enough candies return False if pokemon_config.get('never_catch', False): return False if pokemon_config.get('always_catch', False): return True if pokemon_config.get('catch_above_ncp',-1) >= 0: if pokemon.cp_percent >= pokemon_config.get('catch_above_ncp'): catch_results['ncp'] = True if pokemon_config.get('catch_above_cp',-1) >= 0: if pokemon.cp >= pokemon_config.get('catch_above_cp'): catch_results['cp'] = True if pokemon_config.get('catch_below_cp',-1) >= 0: if pokemon.cp <= pokemon_config.get('catch_below_cp'): catch_results['cp'] = True if pokemon_config.get('catch_above_iv',-1) >= 0: if pokemon.iv > pokemon_config.get('catch_above_iv', pokemon.iv): catch_results['iv'] = True catch_results['fa'] = ( len(pokemon_config.get('fast_attack', [])) == 0 or unicode(pokemon.fast_attack) in map(lambda x: unicode(x), pokemon_config.get('fast_attack', []))) catch_results['ca'] = ( len(pokemon_config.get('charged_attack', [])) == 0 or unicode(pokemon.charged_attack) in map(lambda x: unicode(x), pokemon_config.get('charged_attack', []))) self.bot.logger.debug("Our comparison results: FA: {}, CA: {}, CP: {}, NCP: {}, IV: {}".format(catch_results['fa'], catch_results['ca'], catch_results['cp'], catch_results['ncp'], catch_results['iv'])) # check if encountered pokemon is our locked pokemon if self.bot.capture_locked and self.bot.capture_locked != pokemon.pokemon_id: self.bot.logger.debug("Pokemon locked!") return False # build catch results cr = { 'ncp': False, 'cp': False, 'iv': False } if catch_logic == 'and': cr['ncp'] = True, cr['cp'] = True, cr['iv'] = True elif catch_logic == 'andor': cr['ncp'] = True, cr['cp'] = True elif catch_logic == 'orand': cr['cp'] = True, cr['iv'] = True if pokemon_config.get('catch_above_ncp',-1) >= 0: cr['ncp'] = catch_results['ncp'] if pokemon_config.get('catch_above_cp',-1) >= 0: cr['cp'] = catch_results['cp'] if pokemon_config.get('catch_below_cp',-1) >= 0: cr['cp'] = catch_results['cp'] if pokemon_config.get('catch_above_iv',-1) >= 0: cr['iv'] = catch_results['iv'] if DEBUG_ON: print "Debug information for match rules..." print "catch_results ncp = {}".format(catch_results['ncp']) print "catch_results cp = {}".format(catch_results['cp']) print "catch_results iv = {}".format(catch_results['iv']) print "cr = {}".format(cr) print "catch_above_ncp = {}".format(pokemon_config.get('catch_above_ncp')) print "catch_above_cp iv = {}".format(pokemon_config.get('catch_above_cp')) print "catch_below_cp iv = {}".format(pokemon_config.get('catch_below_cp')) print "catch_above_iv iv = {}".format(pokemon_config.get('catch_above_iv')) print "Pokemon {}".format(pokemon.name) print "pokemon ncp = {}".format(pokemon.cp_percent) print "pokemon cp = {}".format(pokemon.cp) print "pokemon iv = {}".format(pokemon.iv) print "catch logic = {}".format(catch_logic) if LOGIC_TO_FUNCTION[catch_logic](*cr.values()): return catch_results['fa'] and catch_results['ca'] else: return False
def get_evolution_plan(self, family_id, family_list, keep, try_evolve, try_upgrade): candies = inventory.candies().get(family_id).quantity # All the rest is crap, for now crap = list(family_list) crap = [p for p in crap if p not in keep] crap = [p for p in crap if not p.in_fort and not p.is_favorite] crap.sort(key=lambda p: (p.iv, p.cp), reverse=True) # We will gain a candy whether we choose to transfer or evolve these Pokemon candies += len(crap) evolve = [] for pokemon in try_evolve: candies -= pokemon.evolution_cost if candies < 0: continue candies += 1 evolve.append(pokemon) upgrade = [] upgrade_level = min(self.config_upgrade_level, inventory.player().level * 2) for pokemon in try_upgrade: level = int(pokemon.level * 2) - 1 if level >= upgrade_level: continue full_upgrade_candy_cost = 0 full_upgrade_stardust_cost = 0 for i in range(level, upgrade_level): upgrade_cost = self.pokemon_upgrade_cost[i - 1] full_upgrade_candy_cost += upgrade_cost[0] full_upgrade_stardust_cost += upgrade_cost[1] candies -= full_upgrade_candy_cost self.ongoing_stardust_count -= full_upgrade_stardust_cost if (candies < 0) or (self.ongoing_stardust_count < 0): continue upgrade.append(pokemon) if self.config_evolve_for_xp: # Compute how many crap we should keep if we want to batch evolve them for xp lowest_evolution_cost = inventory.pokemons().evolution_cost_for(family_id) # transfer + keep_for_xp = len(crap) # leftover_candies = candies - len(crap) + transfer * 1 # keep_for_xp = (leftover_candies - 1) / (lowest_evolution_cost - 1) # keep_for_xp = (candies - len(crap) + transfer - 1) / (lowest_evolution_cost - 1) # keep_for_xp = (candies - keep_for_xp - 1) / (lowest_evolution_cost - 1) if (candies > 0) and lowest_evolution_cost: keep_for_xp = int((candies - 1) / lowest_evolution_cost) else: keep_for_xp = 0 xp = [p for p in crap if p.has_next_evolution() and p.evolution_cost == lowest_evolution_cost][:keep_for_xp] # If not much to evolve, better keep the candies if len(xp) < math.ceil(self.max_pokemon_storage * 0.02): xp = [] transfer = [p for p in crap if p not in xp] else: xp = [] transfer = crap return (transfer, evolve, upgrade, xp)
def _do_catch(self, pokemon, encounter_id, catch_rate_by_ball, is_vip=False): # settings that may be exposed at some point berry_id = ITEM_RAZZBERRY maximum_ball = ITEM_ULTRABALL if is_vip else ITEM_GREATBALL ideal_catch_rate_before_throw = 0.9 if is_vip else 0.35 berry_count = self.bot.item_inventory_count(berry_id) items_stock = self.bot.current_inventory() while True: # find lowest available ball current_ball = ITEM_POKEBALL while items_stock[current_ball] == 0 and current_ball < maximum_ball: current_ball += 1 if items_stock[current_ball] == 0: self.emit_event('no_pokeballs', formatted='No usable pokeballs found!') break # check future ball count num_next_balls = 0 next_ball = current_ball while next_ball < maximum_ball: next_ball += 1 num_next_balls += items_stock[next_ball] # check if we've got berries to spare berries_to_spare = berry_count > 0 if is_vip else berry_count > num_next_balls + 30 # use a berry if we are under our ideal rate and have berries to spare used_berry = False if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and berries_to_spare: catch_rate_by_ball = self._use_berry(berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) berry_count -= 1 used_berry = True # pick the best ball to catch with best_ball = current_ball while best_ball < maximum_ball: best_ball += 1 if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and items_stock[best_ball] > 0: # if current ball chance to catch is under our ideal rate, and player has better ball - then use it current_ball = best_ball # if the rate is still low and we didn't throw a berry before, throw one if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and berry_count > 0 and not used_berry: catch_rate_by_ball = self._use_berry(berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) berry_count -= 1 # get current pokemon list before catch pokemon_before_catch = self._get_current_pokemon_ids() # try to catch pokemon! items_stock[current_ball] -= 1 self.emit_event( 'threw_pokeball', formatted='Used {ball_name}, with chance {success_percentage} ({count_left} left)', data={ 'ball_name': self.item_list[str(current_ball)], 'success_percentage': self._pct(catch_rate_by_ball[current_ball]), 'count_left': items_stock[current_ball] } ) reticle_size_parameter = normalized_reticle_size(self.config.catch_randomize_reticle_factor) spin_modifier_parameter = spin_modifier(self.config.catch_randomize_spin_factor) response_dict = self.api.catch_pokemon( encounter_id=encounter_id, pokeball=current_ball, normalized_reticle_size=reticle_size_parameter, spawn_point_id=self.spawn_point_guid, hit_pokemon=1, spin_modifier=spin_modifier_parameter, normalized_hit_position=1 ) try: catch_pokemon_status = response_dict['responses']['CATCH_POKEMON']['status'] except KeyError: break # retry failed pokemon if catch_pokemon_status == CATCH_STATUS_FAILED: self.emit_event( 'pokemon_capture_failed', formatted='{pokemon} capture failed.. trying again!', data={'pokemon': pokemon.name} ) sleep(2) continue # abandon if pokemon vanished elif catch_pokemon_status == CATCH_STATUS_VANISHED: self.emit_event( 'pokemon_vanished', formatted='{pokemon} vanished!', data={'pokemon': pokemon.name} ) if self._pct(catch_rate_by_ball[current_ball]) == 100: self.bot.softban = True # pokemon caught! elif catch_pokemon_status == CATCH_STATUS_SUCCESS: self.bot.metrics.captured_pokemon(pokemon.name, pokemon.cp, pokemon.iv_display, pokemon.iv) self.emit_event( 'pokemon_caught', formatted='Captured {pokemon}! [CP {cp}] [Potential {iv}] [{iv_display}] [+{exp} exp]', data={ 'pokemon': pokemon.name, 'cp': pokemon.cp, 'iv': pokemon.iv, 'iv_display': pokemon.iv_display, 'exp': sum(response_dict['responses']['CATCH_POKEMON']['capture_award']['xp']) } ) # We could refresh here too, but adding 3 saves a inventory request candy = inventory.candies().get(pokemon.num) candy.add(3) self.emit_event( 'gained_candy', formatted='You now have {quantity} {type} candy!', data = { 'quantity': candy.quantity, 'type': candy.type, }, ) self.bot.softban = False # evolve pokemon if necessary if self.config.evolve_captured and (self.config.evolve_captured[0] == 'all' or pokemon.name in self.config.evolve_captured): pokemon_after_catch = self._get_current_pokemon_ids() pokemon_to_evolve = list(set(pokemon_after_catch) - set(pokemon_before_catch)) if len(pokemon_to_evolve) == 0: break self._do_evolve(pokemon, pokemon_to_evolve[0]) break
def _do_catch(self, pokemon, encounter_id, catch_rate_by_ball, is_vip=False): # settings that may be exposed at some point """ :type pokemon: Pokemon """ berry_id = ITEM_RAZZBERRY maximum_ball = ITEM_ULTRABALL if is_vip else ITEM_GREATBALL ideal_catch_rate_before_throw = 0.9 if is_vip else 0.35 berry_count = self.inventory.get(ITEM_RAZZBERRY).count ball_count = {} for ball_id in [ITEM_POKEBALL, ITEM_GREATBALL, ITEM_ULTRABALL]: ball_count[ball_id] = self.inventory.get(ball_id).count # use `min_ultraball_to_keep` from config if is not None min_ultraball_to_keep = ball_count[ITEM_ULTRABALL] if self.config.min_ultraball_to_keep is not None: if self.config.min_ultraball_to_keep >= 0 and self.config.min_ultraball_to_keep < min_ultraball_to_keep: min_ultraball_to_keep = self.config.min_ultraball_to_keep while True: # find lowest available ball current_ball = ITEM_POKEBALL while ball_count[current_ball] == 0 and current_ball < maximum_ball: current_ball += 1 if ball_count[current_ball] == 0: self.emit_event('no_pokeballs', formatted='No usable pokeballs found!') # use untraball if there is no other balls with constraint to `min_ultraball_to_keep` if maximum_ball != ITEM_ULTRABALL and ball_count[ITEM_ULTRABALL] > min_ultraball_to_keep: maximum_ball = ITEM_ULTRABALL continue else: break # check future ball count num_next_balls = 0 next_ball = current_ball while next_ball < maximum_ball: next_ball += 1 num_next_balls += ball_count[next_ball] # check if we've got berries to spare berries_to_spare = berry_count > 0 if is_vip else berry_count > num_next_balls + 30 # use a berry if we are under our ideal rate and have berries to spare used_berry = False if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and berries_to_spare: new_catch_rate_by_ball = self._use_berry(berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) if new_catch_rate_by_ball != catch_rate_by_ball: catch_rate_by_ball = new_catch_rate_by_ball self.inventory.get(ITEM_RAZZBERRY).remove(1) berry_count -= 1 used_berry = True # pick the best ball to catch with best_ball = current_ball while best_ball < maximum_ball: best_ball += 1 if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and ball_count[best_ball] > 0: # if current ball chance to catch is under our ideal rate, and player has better ball - then use it current_ball = best_ball # if the rate is still low and we didn't throw a berry before, throw one if catch_rate_by_ball[current_ball] < ideal_catch_rate_before_throw and berry_count > 0 and not used_berry: new_catch_rate_by_ball = self._use_berry(berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) if new_catch_rate_by_ball != catch_rate_by_ball: catch_rate_by_ball = new_catch_rate_by_ball self.inventory.get(ITEM_RAZZBERRY).remove(1) berry_count -= 1 # Randomize the quality of the throw # Default structure throw_parameters = {'normalized_reticle_size': 1.950, 'spin_modifier': 1.0, 'normalized_hit_position': 1.0, 'throw_type_label': 'Excellent'} self.generate_spin_parameter(throw_parameters) self.generate_throw_quality_parameters(throw_parameters) # try to catch pokemon! # TODO : Log which type of throw we selected ball_count[current_ball] -= 1 self.inventory.get(current_ball).remove(1) self.emit_event( 'threw_pokeball', formatted='Used {ball_name}, with chance {success_percentage} ({count_left} left)', data={ 'ball_name': self.inventory.get(current_ball).name, 'success_percentage': self._pct(catch_rate_by_ball[current_ball]), 'count_left': ball_count[current_ball] } ) response_dict = self.api.catch_pokemon( encounter_id=encounter_id, pokeball=current_ball, normalized_reticle_size=throw_parameters['normalized_reticle_size'], spawn_point_id=self.spawn_point_guid, hit_pokemon=1, spin_modifier=throw_parameters['spin_modifier'], normalized_hit_position=throw_parameters['normalized_hit_position'] ) try: catch_pokemon_status = response_dict['responses']['CATCH_POKEMON']['status'] except KeyError: break # retry failed pokemon if catch_pokemon_status == CATCH_STATUS_FAILED: self.emit_event( 'pokemon_capture_failed', formatted='{pokemon} capture failed.. trying again!', data={'pokemon': pokemon.name} ) sleep(2) continue # abandon if pokemon vanished elif catch_pokemon_status == CATCH_STATUS_VANISHED: self.emit_event( 'pokemon_vanished', formatted='{pokemon} vanished!', data={ 'pokemon': pokemon.name, 'encounter_id': self.pokemon['encounter_id'], 'latitude': self.pokemon['latitude'], 'longitude': self.pokemon['longitude'], 'pokemon_id': pokemon.pokemon_id } ) if self._pct(catch_rate_by_ball[current_ball]) == 100: self.bot.softban = True # pokemon caught! elif catch_pokemon_status == CATCH_STATUS_SUCCESS: pokemon.id = response_dict['responses']['CATCH_POKEMON']['captured_pokemon_id'] self.bot.metrics.captured_pokemon(pokemon.name, pokemon.cp, pokemon.iv_display, pokemon.iv) inventory.pokemons().add(pokemon) self.emit_event( 'pokemon_caught', formatted='Captured {pokemon}! [CP {cp}] [Potential {iv}] [{iv_display}] [+{exp} exp]', data={ 'pokemon': pokemon.name, 'cp': pokemon.cp, 'iv': pokemon.iv, 'iv_display': pokemon.iv_display, 'exp': sum(response_dict['responses']['CATCH_POKEMON']['capture_award']['xp']), 'encounter_id': self.pokemon['encounter_id'], 'latitude': self.pokemon['latitude'], 'longitude': self.pokemon['longitude'], 'pokemon_id': pokemon.pokemon_id } ) # We could refresh here too, but adding 3 saves a inventory request candy = inventory.candies(True).get(pokemon.pokemon_id) self.emit_event( 'gained_candy', formatted='You now have {quantity} {type} candy!', data = { 'quantity': candy.quantity, 'type': candy.type, }, ) self.bot.softban = False break
def _check_candy_limit_absolute(self, pokemon): return self.candy_limit_absolute != 0 and inventory.candies().get(pokemon.family_id).quantity >= self.candy_limit_absolute
def get_evolution_plan(self, family_id, family_list, keep, try_evolve, try_upgrade): candies = inventory.candies().get(family_id).quantity family_name = inventory.Pokemons().name_for(family_id) # All the rest is crap, for now crap = list(family_list) crap = [p for p in crap if p not in keep] crap = [p for p in crap if not p.in_fort and not p.is_favorite and not (p.unique_id == self.buddyid)] crap.sort(key=lambda p: (p.iv, p.cp), reverse=True) # We will gain a candy whether we choose to transfer or evolve these Pokemon candies += len(crap) evolve = [] for pokemon in try_evolve: if self.config_evolve_to_final: pokemon_id = pokemon.pokemon_id while inventory.pokemons().has_next_evolution(pokemon_id): candies -= inventory.pokemons().evolution_cost_for(pokemon_id) pokemon_id = inventory.pokemons().next_evolution_ids_for(pokemon_id)[0] else: candies -= pokemon.evolution_cost if candies < 0: continue if self.config_evolve_to_final: pokemon_id = pokemon.pokemon_id while inventory.pokemons().has_next_evolution(pokemon_id): candies += 1 evolve.append(pokemon) pokemon_id = inventory.pokemons().next_evolution_ids_for(pokemon_id)[0] else: candies += 1 evolve.append(pokemon) upgrade = [] upgrade_level = min(self.config_upgrade_level, inventory.player().level + 1.5, 40) for pokemon in try_upgrade: if pokemon.level >= upgrade_level: continue full_upgrade_candy_cost = 0 full_upgrade_stardust_cost = 0 for i in range(int(pokemon.level * 2), int(upgrade_level * 2)): upgrade_cost = self.pokemon_upgrade_cost[i - 2] full_upgrade_candy_cost += upgrade_cost[0] full_upgrade_stardust_cost += upgrade_cost[1] candies -= full_upgrade_candy_cost self.ongoing_stardust_count -= full_upgrade_stardust_cost if (candies < 0) or (self.ongoing_stardust_count < 0): continue upgrade.append(pokemon) if (not self.config_evolve_for_xp) or (family_name in self.config_evolve_for_xp_blacklist): xp = [] transfer = crap elif self.config_evolve_for_xp_whitelist and (family_name not in self.config_evolve_for_xp_whitelist): xp = [] transfer = crap else: # Compute how many crap we should keep if we want to batch evolve them for xp lowest_evolution_cost = inventory.pokemons().evolution_cost_for(family_id) # transfer + keep_for_xp = len(crap) # leftover_candies = candies - len(crap) + transfer * 1 # keep_for_xp = (leftover_candies - 1) / (lowest_evolution_cost - 1) # keep_for_xp = (candies - len(crap) + transfer - 1) / (lowest_evolution_cost - 1) # keep_for_xp = (candies - keep_for_xp - 1) / (lowest_evolution_cost - 1) if (candies > 0) and lowest_evolution_cost: keep_for_xp = int((candies - 1) / lowest_evolution_cost) else: keep_for_xp = 0 xp = [p for p in crap if p.has_next_evolution() and p.evolution_cost == lowest_evolution_cost][:keep_for_xp] transfer = [p for p in crap if p not in xp] return (transfer, evolve, upgrade, xp)
def _pokemon_matches_config(self, config, pokemon, default_logic='and'): pokemon_config = config.get(pokemon.name, config.get('any')) if not pokemon_config: return False catch_results = { 'ncp': False, 'cp': False, 'iv': False, 'fa': True, 'ca': True } catch_logic = pokemon_config.get('logic', default_logic) candies = inventory.candies().get(pokemon.pokemon_id).quantity threshold = pokemon_config.get('candy_threshold', -1) if threshold > 0 and candies >= threshold: # Got enough candies return False if pokemon_config.get('never_catch', False): return False if pokemon_config.get('always_catch', False): return True if pokemon_config.get('catch_above_ncp', -1) >= 0: if pokemon.cp_percent >= pokemon_config.get('catch_above_ncp'): catch_results['ncp'] = True if pokemon_config.get('catch_above_cp', -1) >= 0: if pokemon.cp >= pokemon_config.get('catch_above_cp'): catch_results['cp'] = True if pokemon_config.get('catch_below_cp', -1) >= 0: if pokemon.cp <= pokemon_config.get('catch_below_cp'): catch_results['cp'] = True if pokemon_config.get('catch_above_iv', -1) >= 0: if pokemon.iv > pokemon_config.get('catch_above_iv', pokemon.iv): catch_results['iv'] = True catch_results['fa'] = (len(pokemon_config.get('fast_attack', [])) == 0 or unicode(pokemon.fast_attack) in map( lambda x: unicode(x), pokemon_config.get('fast_attack', []))) catch_results['ca'] = (len(pokemon_config.get('charged_attack', [])) == 0 or unicode(pokemon.charged_attack) in map( lambda x: unicode(x), pokemon_config.get('charged_attack', []))) self.bot.logger.debug( "Our comparison results: FA: {}, CA: {}, CP: {}, NCP: {}, IV: {}". format(catch_results['fa'], catch_results['ca'], catch_results['cp'], catch_results['ncp'], catch_results['iv'])) # check if encountered pokemon is our locked pokemon if self.bot.capture_locked and self.bot.capture_locked != pokemon.pokemon_id: self.bot.logger.debug("Pokemon locked!") return False # build catch results cr = {'ncp': False, 'cp': False, 'iv': False} if catch_logic == 'and': cr['ncp'] = True, cr['cp'] = True, cr['iv'] = True elif catch_logic == 'andor': cr['ncp'] = True, cr['cp'] = True elif catch_logic == 'orand': cr['cp'] = True, cr['iv'] = True if pokemon_config.get('catch_above_ncp', -1) >= 0: cr['ncp'] = catch_results['ncp'] if pokemon_config.get('catch_above_cp', -1) >= 0: cr['cp'] = catch_results['cp'] if pokemon_config.get('catch_below_cp', -1) >= 0: cr['cp'] = catch_results['cp'] if pokemon_config.get('catch_above_iv', -1) >= 0: cr['iv'] = catch_results['iv'] if DEBUG_ON: print "Debug information for match rules..." print "catch_results ncp = {}".format(catch_results['ncp']) print "catch_results cp = {}".format(catch_results['cp']) print "catch_results iv = {}".format(catch_results['iv']) print "cr = {}".format(cr) print "catch_above_ncp = {}".format( pokemon_config.get('catch_above_ncp')) print "catch_above_cp iv = {}".format( pokemon_config.get('catch_above_cp')) print "catch_below_cp iv = {}".format( pokemon_config.get('catch_below_cp')) print "catch_above_iv iv = {}".format( pokemon_config.get('catch_above_iv')) print "Pokemon {}".format(pokemon.name) print "pokemon ncp = {}".format(pokemon.cp_percent) print "pokemon cp = {}".format(pokemon.cp) print "pokemon iv = {}".format(pokemon.iv) print "catch logic = {}".format(catch_logic) if LOGIC_TO_FUNCTION[catch_logic](*cr.values()): return catch_results['fa'] and catch_results['ca'] else: return False
def showtop(self, chatid, num, order): if not num.isnumeric(): num = 10 else: num = int(num) if order not in ["cp", "iv"]: order = "iv" pkmns = sorted(inventory.pokemons().all(), key=lambda p: getattr(p, order), reverse=True)[:num] outMsg = "\n".join(["<b>{}</b> \nCP: {} \nIV: {} \nCandy: {}\n".format(p.name, p.cp, p.iv, inventory.candies().get(p.pokemon_id).quantity) for p in pkmns]) self.sendMessage(chat_id=chatid, parse_mode='HTML', text=outMsg) return
def get_evolution_plan(self, family_id, family, evolve_best, keep_best): candies = inventory.candies().get(family_id).quantity # All the rest is crap, for now crap = family[:] crap = [p for p in crap if p not in evolve_best] crap = [p for p in crap if p not in keep_best] crap.sort(key=lambda p: p.iv * p.ncp, reverse=True) candies += len(crap) # Let's see if we can evolve our best pokemons can_evolve_best = [] for pokemon in evolve_best: if not pokemon.has_next_evolution(): continue candies -= pokemon.evolution_cost if candies < 0: continue can_evolve_best.append(pokemon) # Not sure if the evo keep the same id next_pid = pokemon.next_evolution_ids[0] next_evo = copy.copy(pokemon) next_evo.pokemon_id = next_pid next_evo.static = inventory.pokemons().data_for(next_pid) next_evo.name = inventory.pokemons().name_for(next_pid) evolve_best.append(next_evo) if self.config_evolve_for_xp: # Compute how many crap we should keep if we want to batch evolve them for xp junior_evolution_cost = inventory.pokemons().evolution_cost_for(family_id) # transfer + keep_for_evo = len(crap) # leftover_candies = candies - len(crap) + transfer * 1 # keep_for_evo = leftover_candies / junior_evolution_cost # # keep_for_evo = (candies - len(crap) + transfer) / junior_evolution_cost # keep_for_evo = (candies - keep_for_evo) / junior_evolution_cost if (candies > 0) and junior_evolution_cost: keep_for_evo = int(candies / (junior_evolution_cost + 1)) else: keep_for_evo = 0 evo_crap = [p for p in crap if p.has_next_evolution() and p.evolution_cost == junior_evolution_cost][:keep_for_evo] # If not much to evolve, better keep the candies if len(evo_crap) < math.ceil(self.max_pokemon_storage * 0.01): evo_crap = [] transfer = [p for p in crap if p not in evo_crap] else: evo_crap = [] transfer = crap return (transfer, can_evolve_best, evo_crap)
def _do_catch(self, pokemon, encounter_id, catch_rate_by_ball, is_vip=False): # settings that may be exposed at some point """ :type pokemon: Pokemon """ berry_count = self.inventory.get(ITEM_RAZZBERRY).count ball_count = {} for ball_id in [ITEM_POKEBALL, ITEM_GREATBALL, ITEM_ULTRABALL]: ball_count[ball_id] = self.inventory.get(ball_id).count # use `min_ultraball_to_keep` from config if is not None min_ultraball_to_keep = ball_count[ITEM_ULTRABALL] if self.min_ultraball_to_keep is not None and self.min_ultraball_to_keep >= 0: min_ultraball_to_keep = self.min_ultraball_to_keep berry_id = ITEM_RAZZBERRY maximum_ball = ITEM_GREATBALL if ball_count[ ITEM_ULTRABALL] < min_ultraball_to_keep else ITEM_ULTRABALL ideal_catch_rate_before_throw = self.vip_berry_threshold if is_vip else self.berry_threshold used_berry = False original_catch_rate_by_ball = catch_rate_by_ball while True: # find lowest available ball current_ball = ITEM_POKEBALL while ball_count[current_ball] == 0 and current_ball < maximum_ball: current_ball += 1 if ball_count[current_ball] == 0: self.emit_event('no_pokeballs', formatted='No pokeballs left! Fleeing...') return WorkerResult.ERROR # check future ball count num_next_balls = 0 next_ball = current_ball while next_ball < maximum_ball: next_ball += 1 num_next_balls += ball_count[next_ball] # check if we've got berries to spare berries_to_spare = berry_count > 0 if is_vip else berry_count > num_next_balls + 30 # use a berry if we are under our ideal rate and have berries to spare changed_ball = False if catch_rate_by_ball[ current_ball] < ideal_catch_rate_before_throw and berries_to_spare and not used_berry: new_catch_rate_by_ball = self._use_berry( berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) if new_catch_rate_by_ball != catch_rate_by_ball: catch_rate_by_ball = new_catch_rate_by_ball self.inventory.get(ITEM_RAZZBERRY).remove(1) berry_count -= 1 used_berry = True # pick the best ball to catch with best_ball = current_ball while best_ball < maximum_ball: best_ball += 1 if catch_rate_by_ball[ current_ball] < ideal_catch_rate_before_throw and ball_count[ best_ball] > 0: # if current ball chance to catch is under our ideal rate, and player has better ball - then use it current_ball = best_ball changed_ball = True # if the rate is still low and we didn't throw a berry before, throw one if catch_rate_by_ball[ current_ball] < ideal_catch_rate_before_throw and berry_count > 0 and not used_berry: new_catch_rate_by_ball = self._use_berry( berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) if new_catch_rate_by_ball != catch_rate_by_ball: catch_rate_by_ball = new_catch_rate_by_ball self.inventory.get(ITEM_RAZZBERRY).remove(1) berry_count -= 1 used_berry = True # If we change ball then wait to simulate user selecting it if changed_ball: action_delay(self.catchsim_changeball_wait_min, self.catchsim_changeball_wait_max) # Randomize the quality of the throw # Default structure throw_parameters = { 'normalized_reticle_size': 1.950, 'spin_modifier': 1.0, 'normalized_hit_position': 1.0, 'throw_type_label': 'Excellent' } self.generate_spin_parameter(throw_parameters) self.generate_throw_quality_parameters(throw_parameters) # try to catch pokemon! ball_count[current_ball] -= 1 self.inventory.get(current_ball).remove(1) # Take some time to throw the ball from config options action_delay(self.catchsim_catch_wait_min, self.catchsim_catch_wait_max) self.emit_event( 'threw_pokeball', formatted= '{throw_type}{spin_label} throw! Used {ball_name}, with chance {success_percentage} ({count_left} left)', data={ 'throw_type': throw_parameters['throw_type_label'], 'spin_label': throw_parameters['spin_label'], 'ball_name': self.inventory.get(current_ball).name, 'success_percentage': self._pct(catch_rate_by_ball[current_ball]), 'count_left': ball_count[current_ball] }) hit_pokemon = 1 if random() >= self.catch_throw_parameters_hit_rate and not is_vip: hit_pokemon = 0 response_dict = self.bot.api.catch_pokemon( encounter_id=encounter_id, pokeball=current_ball, normalized_reticle_size=throw_parameters[ 'normalized_reticle_size'], spawn_point_id=self.spawn_point_guid, hit_pokemon=hit_pokemon, spin_modifier=throw_parameters['spin_modifier'], normalized_hit_position=throw_parameters[ 'normalized_hit_position']) try: catch_pokemon_status = response_dict['responses'][ 'CATCH_POKEMON']['status'] except KeyError: break # retry failed pokemon if catch_pokemon_status == CATCH_STATUS_FAILED: self.emit_event( 'pokemon_capture_failed', formatted='{pokemon} capture failed.. trying again!', data={'pokemon': pokemon.name}) used_berry = False catch_rate_by_ball = original_catch_rate_by_ball # sleep according to flee_count and flee_duration config settings # randomly chooses a number of times to 'show' wobble animation between 1 and flee_count # multiplies this by flee_duration to get total sleep if self.catchsim_flee_count: sleep((randrange(self.catchsim_flee_count) + 1) * self.catchsim_flee_duration) continue # abandon if pokemon vanished elif catch_pokemon_status == CATCH_STATUS_VANISHED: #insert into DB with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='vanish_log'" ) result = c.fetchone() while True: if result[0] == 1: conn.execute( '''INSERT INTO vanish_log (pokemon, cp, iv, encounter_id, pokemon_id) VALUES (?, ?, ?, ?, ?)''', (pokemon.name, pokemon.cp, pokemon.iv, str(encounter_id), pokemon.pokemon_id)) break else: self.emit_event( 'vanish_log', sender=self, level='info', formatted="vanish_log table not found, skipping log") break self.emit_event('pokemon_vanished', formatted='{} vanished!'.format(pokemon.name), data={ 'pokemon': pokemon.name, 'encounter_id': self.pokemon['encounter_id'], 'latitude': self.pokemon['latitude'], 'longitude': self.pokemon['longitude'], 'pokemon_id': pokemon.pokemon_id }) with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT DISTINCT COUNT(encounter_id) FROM vanish_log WHERE dated > (SELECT dated FROM catch_log WHERE dated IN (SELECT MAX(dated) FROM catch_log))" ) result = c.fetchone() self.consecutive_vanishes_so_far = result[0] if self.rest_completed == False and self.consecutive_vanishes_so_far >= self.consecutive_vanish_limit: self.start_rest() if self._pct(catch_rate_by_ball[current_ball]) == 100: self.bot.softban = True # pokemon caught! elif catch_pokemon_status == CATCH_STATUS_SUCCESS: if self.rest_completed == True: self.rest_completed = False pokemon.unique_id = response_dict['responses'][ 'CATCH_POKEMON']['captured_pokemon_id'] self.bot.metrics.captured_pokemon(pokemon.name, pokemon.cp, pokemon.iv_display, pokemon.iv) awards = response_dict['responses']['CATCH_POKEMON'][ 'capture_award'] exp_gain, candy_gain, stardust_gain = self.extract_award( awards) with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT DISTINCT COUNT(encounter_id) FROM catch_log WHERE dated >= datetime('now','-1 day')" ) result = c.fetchone() if is_vip: self.emit_event( 'pokemon_vip_caught', formatted= 'Vip Captured {pokemon}! (CP: {cp} IV: {iv} {iv_display} NCP: {ncp}) Catch Limit: ({caught_last_24_hour}/{daily_catch_limit}) +{exp} exp +{stardust} stardust', data={ 'pokemon': pokemon.name, 'ncp': str(round(pokemon.cp_percent, 2)), 'cp': str(int(pokemon.cp)), 'iv': str(pokemon.iv), 'iv_display': str(pokemon.iv_display), 'exp': str(exp_gain), 'stardust': stardust_gain, 'encounter_id': str(self.pokemon['encounter_id']), 'latitude': str(self.pokemon['latitude']), 'longitude': str(self.pokemon['longitude']), 'pokemon_id': str(pokemon.pokemon_id), 'caught_last_24_hour': str(result[0]), 'daily_catch_limit': str(self.daily_catch_limit) }) else: self.emit_event( 'pokemon_caught', formatted= 'Captured {pokemon}! (CP: {cp} IV: {iv} {iv_display} NCP: {ncp}) Catch Limit: ({caught_last_24_hour}/{daily_catch_limit}) +{exp} exp +{stardust} stardust', data={ 'pokemon': pokemon.name, 'ncp': str(round(pokemon.cp_percent, 2)), 'cp': str(int(pokemon.cp)), 'iv': str(pokemon.iv), 'iv_display': str(pokemon.iv_display), 'exp': str(exp_gain), 'stardust': stardust_gain, 'encounter_id': str(self.pokemon['encounter_id']), 'latitude': str(self.pokemon['latitude']), 'longitude': str(self.pokemon['longitude']), 'pokemon_id': str(pokemon.pokemon_id), 'caught_last_24_hour': str(result[0]), 'daily_catch_limit': str(self.daily_catch_limit) }) inventory.pokemons().add(pokemon) inventory.player().exp += exp_gain self.bot.stardust += stardust_gain candy = inventory.candies().get(pokemon.pokemon_id) candy.add(candy_gain) self.emit_event( 'gained_candy', formatted='You now have {quantity} {type} candy!', data={ 'quantity': candy.quantity, 'type': candy.type, }, ) self.bot.softban = False try: with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='catch_log'" ) result = c.fetchone() while True: if result[0] == 1: conn.execute( '''INSERT INTO catch_log (pokemon, cp, iv, encounter_id, pokemon_id) VALUES (?, ?, ?, ?, ?)''', (pokemon.name, pokemon.cp, pokemon.iv, str(encounter_id), pokemon.pokemon_id)) break else: self.emit_event( 'catch_log', sender=self, level='info', formatted="catch_log table not found, skipping log" ) break user_data_caught = os.path.join( _base_dir, 'data', 'caught-%s.json' % self.bot.config.username) with open(user_data_caught, 'ab') as outfile: json.dump( OrderedDict({ 'datetime': str(datetime.now()), 'pokemon': pokemon.name, 'cp': pokemon.cp, 'iv': pokemon.iv, 'encounter_id': self.pokemon['encounter_id'], 'pokemon_id': pokemon.pokemon_id, 'latitude': self.pokemon['latitude'], 'longitude': self.pokemon['longitude'] }), outfile) outfile.write('\n') # if it is a new pokemon to our dex, simulate app animation delay if exp_gain >= 500: sleep( randrange(self.catchsim_newtodex_wait_min, self.catchsim_newtodex_wait_max)) except IOError as e: self.logger.info( '[x] Error while opening location file: %s' % e) elif catch_pokemon_status == CATCH_STATUS_MISSED: self.emit_event( 'pokemon_capture_failed', formatted= 'Pokeball thrown to {pokemon} missed.. trying again!', data={'pokemon': pokemon.name}) # Take some time to throw the ball from config options action_delay(self.catchsim_catch_wait_min, self.catchsim_catch_wait_max) continue break
def get_evolution_plan(self, family_id, family_list, keep, try_evolve, try_upgrade): candies = inventory.candies().get(family_id).quantity # All the rest is crap, for now crap = list(family_list) crap = [p for p in crap if p not in keep] crap = [p for p in crap if not p.in_fort and not p.is_favorite] crap.sort(key=lambda p: (p.iv, p.cp), reverse=True) # We will gain a candy whether we choose to transfer or evolve these Pokemon candies += len(crap) evolve = [] for pokemon in try_evolve: candies -= pokemon.evolution_cost if candies < 0: continue candies += 1 evolve.append(pokemon) upgrade = [] upgrade_level = min(self.config_upgrade_level, inventory.player().level * 2) for pokemon in try_upgrade: level = int(pokemon.level * 2) - 1 if level >= upgrade_level: continue full_upgrade_candy_cost = 0 full_upgrade_stardust_cost = 0 for i in range(level, upgrade_level): upgrade_cost = self.pokemon_upgrade_cost[i - 1] full_upgrade_candy_cost += upgrade_cost[0] full_upgrade_stardust_cost += upgrade_cost[1] candies -= full_upgrade_candy_cost self.ongoing_stardust_count -= full_upgrade_stardust_cost if (candies < 0) or (self.ongoing_stardust_count < 0): continue upgrade.append(pokemon) if self.config_evolve_for_xp: # Compute how many crap we should keep if we want to batch evolve them for xp lowest_evolution_cost = inventory.pokemons().evolution_cost_for( family_id) # transfer + keep_for_xp = len(crap) # leftover_candies = candies - len(crap) + transfer * 1 # keep_for_xp = (leftover_candies - 1) / (lowest_evolution_cost - 1) # keep_for_xp = (candies - len(crap) + transfer - 1) / (lowest_evolution_cost - 1) # keep_for_xp = (candies - keep_for_xp - 1) / (lowest_evolution_cost - 1) if (candies > 0) and lowest_evolution_cost: keep_for_xp = int((candies - 1) / lowest_evolution_cost) else: keep_for_xp = 0 xp = [ p for p in crap if p.has_next_evolution() and p.evolution_cost == lowest_evolution_cost ][:keep_for_xp] # If not much to evolve, better keep the candies if len(xp) < math.ceil(self.max_pokemon_storage * 0.02): xp = [] transfer = [p for p in crap if p not in xp] else: xp = [] transfer = crap return (transfer, evolve, upgrade, xp)