def _set_buddy(self, pokemon): response_dict = \ self.bot.api.set_buddy_pokemon(pokemon_id=pokemon.unique_id) data = response_dict.get('responses', {}).get('SET_BUDDY_POKEMON', {}) result = data.get('result', 0) action_delay(self.buddy_change_wait_min, self.buddy_change_wait_max) if result == 1: updated_buddy = data['updated_buddy'] self.buddy = updated_buddy self.candy_awarded = 0 self.buddy_distance_needed = pokemon.buddy_distance_needed self.emit_event('buddy_update', formatted='{name} was set as Buddy Pokemon.', data={'name': pokemon.name}) return True else: error_codes = { 0: 'UNSET', 2: 'ERROR_POKEMON_DEPLOYED', 3: 'ERROR_POKEMON_NOT_OWNED', 4: 'ERROR_POKEMON_IS_EGG', } self.emit_event( 'buddy_update_fail', formatted= 'Error while setting {name} as Buddy Pokemon: {error}', data={ 'name': pokemon.name, 'error': error_codes[result] }) return False
def work(self): """ Start the process of recycling items if necessary. :return: Returns whether or not the task went well :rtype: WorkerResult """ # TODO: Use new inventory everywhere and then remove this inventory update inventory.refresh_inventory() worker_result = WorkerResult.SUCCESS if self.should_run(): if not (self.max_balls_keep is None): worker_result = self.recycle_excess_category_max(self.max_balls_keep, [1,2,3,4]) if not (self.max_potions_keep is None): worker_result = self.recycle_excess_category_max(self.max_potions_keep, [101,102,103,104]) if not (self.max_berries_keep is None): worker_result = self.recycle_excess_category_max(self.max_berries_keep, [701,702,703,704,705]) if not (self.max_revives_keep is None): worker_result = self.recycle_excess_category_max(self.max_revives_keep, [201,202]) inventory.refresh_inventory() for item_in_inventory in inventory.items().all(): if self.item_should_be_recycled(item_in_inventory): # Make the bot appears more human action_delay(self.recycle_wait_min, self.recycle_wait_max) # If at any recycling process call we got an error, we consider that the result of this task is error too. if ItemRecycler(self.bot, item_in_inventory, self.get_amount_to_recycle(item_in_inventory)).work() == WorkerResult.ERROR: worker_result = WorkerResult.ERROR return worker_result
def work(self): """ Start the process of recycling items if necessary. :return: Returns whether or not the task went well :rtype: WorkerResult """ worker_result = WorkerResult.SUCCESS if self.should_run(): if not (self.max_balls_keep is None): worker_result = self.recycle_excess_category_max(self.max_balls_keep, [1,2,3,4]) if not (self.max_potions_keep is None): worker_result = self.recycle_excess_category_max(self.max_potions_keep, [101,102,103,104]) if not (self.max_berries_keep is None): worker_result = self.recycle_excess_category_max(self.max_berries_keep, [701,702,703,704,705]) if not (self.max_revives_keep is None): worker_result = self.recycle_excess_category_max(self.max_revives_keep, [201,202]) inventory.refresh_inventory() for item_in_inventory in inventory.items().all(): if self.item_should_be_recycled(item_in_inventory): # Make the bot appears more human action_delay(self.recycle_wait_min, self.recycle_wait_max) # If at any recycling process call we got an error, we consider that the result of this task is error too. if ItemRecycler(self.bot, item_in_inventory, self.get_amount_to_recycle(item_in_inventory)).work() == WorkerResult.ERROR: worker_result = WorkerResult.ERROR return worker_result
def set_buddy_pokemon(self, pokemon): if not self.bot.config.test: response_dict = self.bot.api.set_buddy_pokemon(pokemon_id=pokemon.unique_id) else: response_dict = {"responses": {"SET_BUDDY_POKEMON": {"result": SUCCESS, "updated_buddy": {"start_km_walked": 0, "last_km_awarded": 0, "id": 0}}}} if not response_dict: return False result = response_dict.get("responses", {}).get("SET_BUDDY_POKEMON", {}).get("result", 0) if result != SUCCESS: return False if not self.bot.config.test: self.buddy = response_dict.get("responses", {}).get("SET_BUDDY_POKEMON", {}).get("updated_buddy", {}) self.buddyid = self._get_buddyid() self.emit_event("buddy_pokemon", formatted="Buddy {pokemon} [IV {iv}] [CP {cp}]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp}) self.lock_buddy = True if not self.bot.config.test: action_delay(self.config_action_wait_min, self.config_action_wait_max) 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 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 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 release_pokemon(self, pokemon_name, cp, iv, pokemon_id): logger.log('Exchanging {} [CP {}] [Potential {}] for candy!'.format(pokemon_name, cp, iv), 'green') self.bot.api.release_pokemon(pokemon_id=pokemon_id) response_dict = self.bot.api.call() action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max)
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 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 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 _revive_pokemon(self, pokemon): item = Item.ITEM_REVIVE.value amount = inventory.items().get(item).count if amount == 0: self.logger.info("No normal revives left, using MAX revive!") item = Item.ITEM_MAX_REVIVE.value amount = inventory.items().get(item).count if amount > 0: response_dict_revive = self.bot.api.use_item_revive( item_id=item, pokemon_id=pokemon.unique_id) action_delay(2, 3) if response_dict_revive: result = response_dict_revive.get('responses', {}).get( 'USE_ITEM_REVIVE', {}).get('result', 0) revive_item = inventory.items().get(item) # Remove the revive from the iventory revive_item.remove(1) if result is 1: # Request success self.emit_event('revived_pokemon', formatted='Revived {name}.', data={'name': pokemon.name}) if item == Item.ITEM_REVIVE.value: pokemon.hp = int(pokemon.hp_max / 2) self.to_heal.append(pokemon) else: # Set pokemon as revived pokemon.hp = pokemon.hp_max return True else: self.emit_event('revived_pokemon', level='error', formatted='Failed to revive {name}!', data={'name': pokemon.name}) return False
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 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 _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 work(self): """ Iterate over all user pokemons and nickname if needed """ for pokemon in pokemons().all(): # type: Pokemon if not pokemon.is_favorite or not self.ignore_favorites: if pokemon.iv >= self.nickname_above_iv: if self._nickname_pokemon(pokemon): # Make the bot appears more human action_delay(self.nickname_wait_min, self.nickname_wait_max)
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 release_pokemon(self, pokemon_name, cp, iv, pokemon_id): response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon_id) self.emit_event( 'pokemon_release', formatted='Exchanged {pokemon} [CP {cp}] [IV {iv}] for candy.', data={ 'pokemon': pokemon_name, 'cp': cp, 'iv': iv } ) action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max)
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 release_pokemon(self, pokemon_name, cp, iv, pokemon_id): response_dict = self.bot.api.release_pokemon(pokemon_id=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': cp, 'iv': iv }) action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max)
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 unfavor_pokemon(self, pokemon): request = self.bot.api.create_request() request.set_favorite_pokemon(pokemon_id=pokemon.unique_id, is_favorite=False) response_dict = request.call() sleep(1.2) # wait a bit after request if response_dict: result = response_dict.get('responses', {}).get('SET_FAVORITE_POKEMON', {}).get('result', 0) if result is 1: # Request success # Mark Pokemon as no longer favorite pokemon.is_favorite = False self.emit_event("pokemon_unfavored", formatted="Unfavored {pokemon} [IV {iv}] [CP {cp}]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp}) action_delay(self.config_action_wait_min, self.config_action_wait_max)
def recycle_excess_category_max(self, category_max, category_items_list): """ Recycle the item which excess the category max :param category_max: :param category_items_list: :return: none: :rtype: None """ worker_result = WorkerResult.SUCCESS category_inventory = self.get_category_inventory_list(category_items_list) category_count = 0 for i in category_inventory: category_count = category_count + i[1] items_to_recycle = self.get_category_items_to_recycle(category_inventory, category_count, category_max) for item in items_to_recycle: action_delay(self.recycle_wait_min, self.recycle_wait_max) if ItemRecycler(self.bot, inventory.items().get(item[0]), item[1]).work() == WorkerResult.ERROR: worker_result = WorkerResult.ERROR return worker_result
def recycle_excess_category_max(self, category_max, category_items_list): """ Recycle the item which excess the category max :param category_max: :param category_items_list: :return: none: :rtype: None """ worker_result = WorkerResult.SUCCESS category_inventory = self.get_category_inventory_list(category_items_list) category_count = 0 for i in category_inventory: category_count = category_count + i[1] items_to_recycle = self.get_category_items_to_recycle(category_inventory, category_count, category_max) for item in items_to_recycle: action_delay(self.recycle_wait_min, self.recycle_wait_max) if inventory.items().get(item[0]).recycle(item[1]) == WorkerResult.ERROR: worker_result = WorkerResult.ERROR return worker_result
def _revive_pokemon(self, pokemon): item = Item.ITEM_REVIVE.value amount = inventory.items().get(item).count if amount == 0: self.logger.info("No normal revives left, using MAX revive!") item = Item.ITEM_MAX_REVIVE.value amount = inventory.items().get(item).count if amount > 0: response_dict_revive = self.bot.api.use_item_revive(item_id=item, pokemon_id=pokemon.unique_id) action_delay(2, 3) if response_dict_revive: result = response_dict_revive.get('responses', {}).get('USE_ITEM_REVIVE', {}).get('result', 0) revive_item = inventory.items().get(item) # Remove the revive from the iventory revive_item.remove(1) if result is 1: # Request success self.emit_event( 'revived_pokemon', formatted='Revived {name}.', data={ 'name': pokemon.name } ) if item == Item.ITEM_REVIVE.value: pokemon.hp = int(pokemon.hp_max / 2) self.to_heal.append(pokemon) else: # Set pokemon as revived pokemon.hp = pokemon.hp_max return True else: self.emit_event( 'revived_pokemon', level='error', formatted='Failed to revive {name}!', data={ 'name': pokemon.name } ) return False
def favor_pokemon(self, pokemon): request = self.bot.api.create_request() request.set_favorite_pokemon(pokemon_id=pokemon.unique_id, is_favorite=True) response_dict = request.call() sleep(1.2) # wait a bit after request if response_dict: result = response_dict.get('responses', {}).get('SET_FAVORITE_POKEMON', {}).get('result', 0) if result is 1: # Request success action_delay(self.config_action_wait_min, self.config_action_wait_max) # Mark Pokemon as favorite pokemon.is_favorite = True self.emit_event("pokemon_favored", formatted="Favored {pokemon} [IV {iv}] [CP {cp}]", data={"pokemon": pokemon.name, "iv": pokemon.iv, "cp": pokemon.cp}) else: # Pokemon not found?? self.ignore_favorite.append(pokemon.unique_id) pokemon.is_favorite = True self.logger.info("Unable to set %s as favorite!" % pokemon.name)
def _set_buddy(self, pokemon): request = self.bot.api.create_request() request.set_buddy_pokemon(pokemon_id=pokemon.unique_id) response_dict = request.call() data = response_dict.get('responses', {}).get('SET_BUDDY_POKEMON', {}) result = data.get('result', 0) action_delay(self.buddy_change_wait_min, self.buddy_change_wait_max) if result == 1: updated_buddy = data['updated_buddy'] self.buddy = updated_buddy self.candy_awarded = 0 self.buddy_distance_needed = pokemon.buddy_distance_needed self.emit_event( 'buddy_update', formatted='{name} was set as Buddy Pokemon.', data={ 'name': pokemon.name } ) return True else: error_codes = { 0: 'UNSET', 2: 'ERROR_POKEMON_DEPLOYED', 3: 'ERROR_POKEMON_NOT_OWNED', 4: 'ERROR_POKEMON_IS_EGG', } self.emit_event( 'buddy_update_fail', formatted='Error while setting {name} as Buddy Pokemon: {error}', data={ 'name': pokemon.name, 'error': error_codes[result] } ) return False
def work(self): """ Discard items if necessary. :return: Returns wether or not the task went well :rtype: WorkerResult """ # TODO: Use new inventory everywhere and then remove the inventory update # Updating inventory inventory.refresh_inventory() worker_result = WorkerResult.SUCCESS if self.should_run(): # For each user's item in inventory recycle it if needed for item_in_inventory in inventory.items().all(): amount_to_recycle = self.get_amount_to_recycle(item_in_inventory) if self.item_should_be_recycled(item_in_inventory, amount_to_recycle): action_delay(self.bot.config.action_wait_min, self.bot.config.action_wait_max) if ItemRecycler(self.bot, item_in_inventory, amount_to_recycle).work() == WorkerResult.ERROR: worker_result = WorkerResult.ERROR return worker_result
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 _use_berry(self, berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball): # Delay to simulate selecting berry action_delay(self.catchsim_berry_wait_min, self.catchsim_berry_wait_max) new_catch_rate_by_ball = [] self.emit_event( 'pokemon_catch_rate', level='debug', formatted='Catch rate of {catch_rate} with {ball_name} is low. Throwing {berry_name} (have {berry_count})', data={ 'catch_rate': self._pct(catch_rate_by_ball[current_ball]), 'ball_name': self.inventory.get(current_ball).name, 'berry_name': self.inventory.get(berry_id).name, 'berry_count': berry_count } ) response_dict = self.api.use_item_capture( item_id=berry_id, encounter_id=encounter_id, spawn_point_id=self.spawn_point_guid ) responses = response_dict['responses'] if response_dict and response_dict['status_code'] == 1: # update catch rates using multiplier if 'item_capture_mult' in responses['USE_ITEM_CAPTURE']: for rate in catch_rate_by_ball: new_catch_rate_by_ball.append(rate * responses['USE_ITEM_CAPTURE']['item_capture_mult']) self.emit_event( 'threw_berry', formatted="Threw a {berry_name}! Catch rate with {ball_name} is now: {new_catch_rate}", data={ 'berry_name': self.inventory.get(berry_id).name, 'ball_name': self.inventory.get(current_ball).name, 'new_catch_rate': self._pct(new_catch_rate_by_ball[current_ball]) } ) # softban? else: new_catch_rate_by_ball = catch_rate_by_ball self.bot.softban = True self.emit_event( 'softban', level='warning', formatted='Failed to use berry. You may be softbanned.' ) with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='softban_log'") result = c.fetchone() while True: if result[0] == 1: source = str("PokemonCatchWorker") status = str("Possible Softban") conn.execute('''INSERT INTO softban_log (status, source) VALUES (?, ?)''', (status, source)) break else: self.emit_event( 'softban_log', sender=self, level='info', formatted="softban_log table not found, skipping log" ) # unknown status code else: new_catch_rate_by_ball = catch_rate_by_ball self.emit_event( 'threw_berry_failed', formatted='Unknown response when throwing berry: {status_code}.', data={ 'status_code': response_dict['status_code'] } ) return new_catch_rate_by_ball
def work(self): forts = self.get_forts_in_range() if not self.should_run() or len(forts) == 0: return WorkerResult.SUCCESS fort = forts[0] lat = fort['latitude'] lng = fort['longitude'] details = fort_details(self.bot, fort['id'], lat, lng) fort_name = details.get('name', 'Unknown') response_dict = self.bot.api.fort_search( fort_id=fort['id'], fort_latitude=lat, fort_longitude=lng, player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1])) if ('responses' in response_dict) and ('FORT_SEARCH' in response_dict['responses']): spin_details = response_dict['responses']['FORT_SEARCH'] spin_result = spin_details.get('result', -1) if (spin_result == SPIN_REQUEST_RESULT_SUCCESS) or ( spin_result == SPIN_REQUEST_RESULT_INVENTORY_FULL): self.bot.softban = False experience_awarded = spin_details.get('experience_awarded', 0) items_awarded = self.get_items_awarded_from_fort_spinned( response_dict) egg_awarded = spin_details.get('pokemon_data_egg', None) if egg_awarded is not None: items_awarded[u'Egg'] = egg_awarded['egg_km_walked_target'] if experience_awarded or items_awarded: awards = ', '.join([ "{}x {}".format(items_awarded[x], x) for x in items_awarded if x != u'Egg' ]) if egg_awarded is not None: awards += u', {} Egg'.format( egg_awarded['egg_km_walked_target']) self.emit_event( 'spun_pokestop', formatted= "Spun pokestop {pokestop}. Experience awarded: {exp}. Items awarded: {items}", data={ 'pokestop': fort_name, 'exp': experience_awarded, 'items': awards }) else: self.emit_event( 'pokestop_empty', formatted='Found nothing in pokestop {pokestop}.', data={'pokestop': fort_name}) with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='pokestop_log'" ) result = c.fetchone() c.execute( "SELECT DISTINCT COUNT(pokestop) FROM pokestop_log WHERE dated >= datetime('now','-1 day')" ) if c.fetchone()[0] >= self.config.get('daily_spin_limit', 2000): self.emit_event( 'spin_limit', formatted= 'WARNING! You have reached your daily spin limit') sys.exit(2) while True: if result[0] == 1: conn.execute( '''INSERT INTO pokestop_log (pokestop, exp, items) VALUES (?, ?, ?)''', (fort_name, str(experience_awarded), str(items_awarded))) break else: self.emit_event( 'pokestop_log', sender=self, level='info', formatted= "pokestop_log table not found, skipping log") break pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) self.bot.recent_forts = self.bot.recent_forts[1:] + [ fort['id'] ] elif spin_result == SPIN_REQUEST_RESULT_OUT_OF_RANGE: self.emit_event('pokestop_out_of_range', formatted="Pokestop {pokestop} out of range.", data={'pokestop': fort_name}) elif spin_result == SPIN_REQUEST_RESULT_IN_COOLDOWN_PERIOD: pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') if pokestop_cooldown: self.bot.fort_timeouts.update( {fort["id"]: pokestop_cooldown}) seconds_since_epoch = time.time() minutes_left = format_time((pokestop_cooldown / 1000) - seconds_since_epoch) self.emit_event( 'pokestop_on_cooldown', formatted= "Pokestop {pokestop} on cooldown. Time left: {minutes_left}.", data={ 'pokestop': fort_name, 'minutes_left': minutes_left }) else: self.emit_event('unknown_spin_result', formatted="Unknown spint result {status_code}", data={'status_code': str(spin_result)}) if 'chain_hack_sequence_number' in response_dict['responses'][ 'FORT_SEARCH']: action_delay(self.spin_wait_min, self.spin_wait_max) return response_dict['responses']['FORT_SEARCH'][ 'chain_hack_sequence_number'] else: self.emit_event( 'pokestop_searching_too_often', formatted="Possibly searching too often, take a rest.") if spin_result == 1 and not items_awarded and not experience_awarded and not pokestop_cooldown: self.bot.softban = True self.emit_event('softban', formatted='Probably got softban.') with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='softban_log'" ) result = c.fetchone() if result[0] == 1: source = str("PokemonCatchWorker") status = str("Possible Softban") conn.execute( '''INSERT INTO softban_log (status, source) VALUES (?, ?)''', (status, source)) else: self.emit_event( 'softban_log', sender=self, level='info', formatted= "softban_log table not found, skipping log") self.bot.fort_timeouts[fort["id"]] = ( time.time() + 300) * 1000 # Don't spin for 5m return WorkerResult.ERROR action_delay(self.spin_wait_min, self.spin_wait_max) if len(forts) > 1: return WorkerResult.RUNNING return WorkerResult.SUCCESS
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.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 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 changed_ball = 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 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! # TODO : Log which type of throw we selected 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='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 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.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 _use_berry(self, berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball): # Delay to simulate selecting berry action_delay(self.catchsim_berry_wait_min, self.catchsim_berry_wait_max) new_catch_rate_by_ball = [] self.emit_event( 'pokemon_catch_rate', level='debug', formatted= 'Catch rate of {catch_rate} with {ball_name} is low. Throwing {berry_name} (have {berry_count})', data={ 'catch_rate': self._pct(catch_rate_by_ball[current_ball]), 'ball_name': self.inventory.get(current_ball).name, 'berry_name': self.inventory.get(berry_id).name, 'berry_count': berry_count }) response_dict = self.api.use_item_capture( item_id=berry_id, encounter_id=encounter_id, spawn_point_id=self.spawn_point_guid) responses = response_dict['responses'] if response_dict and response_dict['status_code'] == 1: # update catch rates using multiplier if 'item_capture_mult' in responses['USE_ITEM_CAPTURE']: for rate in catch_rate_by_ball: new_catch_rate_by_ball.append( rate * responses['USE_ITEM_CAPTURE']['item_capture_mult']) self.emit_event( 'threw_berry', formatted= "Threw a {berry_name}! Catch rate with {ball_name} is now: {new_catch_rate}", data={ 'berry_name': self.inventory.get(berry_id).name, 'ball_name': self.inventory.get(current_ball).name, 'new_catch_rate': self._pct(new_catch_rate_by_ball[current_ball]) }) # softban? else: new_catch_rate_by_ball = catch_rate_by_ball self.bot.softban = True self.emit_event( 'softban', level='warning', formatted='Failed to use berry. You may be softbanned.') # unknown status code else: new_catch_rate_by_ball = catch_rate_by_ball self.emit_event( 'threw_berry_failed', formatted= 'Unknown response when throwing berry: {status_code}.', data={'status_code': response_dict['status_code']}) return new_catch_rate_by_ball
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.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 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 changed_ball = 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 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! # TODO : Log which type of throw we selected 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= '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 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.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 work(self): forts = self.get_forts_in_range() if not self.should_run() or len(forts) == 0: return WorkerResult.SUCCESS fort = forts[0] lat = fort['latitude'] lng = fort['longitude'] details = fort_details(self.bot, fort['id'], lat, lng) fort_name = details.get('name', 'Unknown') response_dict = self.bot.api.fort_search( fort_id=fort['id'], fort_latitude=lat, fort_longitude=lng, player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1]) ) if ('responses' in response_dict) and ('FORT_SEARCH' in response_dict['responses']): spin_details = response_dict['responses']['FORT_SEARCH'] spin_result = spin_details.get('result', -1) if (spin_result == SPIN_REQUEST_RESULT_SUCCESS) or (spin_result == SPIN_REQUEST_RESULT_INVENTORY_FULL): self.bot.softban = False experience_awarded = spin_details.get('experience_awarded', 0) items_awarded = self.get_items_awarded_from_fort_spinned(response_dict) if experience_awarded or items_awarded: self.emit_event( 'spun_pokestop', formatted="Spun pokestop {pokestop}. Experience awarded: {exp}. Items awarded: {items}", data={ 'pokestop': fort_name, 'exp': experience_awarded, 'items': items_awarded } ) else: self.emit_event( 'pokestop_empty', formatted='Found nothing in pokestop {pokestop}.', data={'pokestop': fort_name} ) pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) self.bot.recent_forts = self.bot.recent_forts[1:] + [fort['id']] elif spin_result == SPIN_REQUEST_RESULT_OUT_OF_RANGE: self.emit_event( 'pokestop_out_of_range', formatted="Pokestop {pokestop} out of range.", data={'pokestop': fort_name} ) elif spin_result == SPIN_REQUEST_RESULT_IN_COOLDOWN_PERIOD: pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') if pokestop_cooldown: self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) seconds_since_epoch = time.time() minutes_left = format_time( (pokestop_cooldown / 1000) - seconds_since_epoch ) self.emit_event( 'pokestop_on_cooldown', formatted="Pokestop {pokestop} on cooldown. Time left: {minutes_left}.", data={'pokestop': fort_name, 'minutes_left': minutes_left} ) else: self.emit_event( 'unknown_spin_result', formatted="Unknown spint result {status_code}", data={'status_code': str(spin_result)} ) if 'chain_hack_sequence_number' in response_dict['responses'][ 'FORT_SEARCH']: action_delay(self.spin_wait_min, self.spin_wait_max) return response_dict['responses']['FORT_SEARCH'][ 'chain_hack_sequence_number'] else: self.emit_event( 'pokestop_searching_too_often', formatted="Possibly searching too often, take a rest." ) if spin_result == 1 and not items_awarded and not experience_awarded and not pokestop_cooldown: self.bot.softban = True self.emit_event( 'softban', formatted='Probably got softban.' ) else: self.bot.fort_timeouts[fort["id"]] = (time.time() + 300) * 1000 # Don't spin for 5m return WorkerResult.ERROR action_delay(self.spin_wait_min, self.spin_wait_max) if len(forts) > 1: return WorkerResult.RUNNING return WorkerResult.SUCCESS
def _use_berry(self, berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball): # Delay to simulate selecting berry action_delay(self.catchsim_berry_wait_min, self.catchsim_berry_wait_max) new_catch_rate_by_ball = [] self.emit_event( 'pokemon_catch_rate', level='debug', formatted= 'Catch rate of {catch_rate} with {ball_name} is low. Throwing {berry_name} (have {berry_count})', data={ 'catch_rate': self._pct(catch_rate_by_ball[current_ball]), 'ball_name': self.inventory.get(current_ball).name, 'berry_name': self.inventory.get(berry_id).name, 'berry_count': berry_count }) response_dict = self.bot.api.use_item_capture( item_id=berry_id, encounter_id=encounter_id, spawn_point_id=self.spawn_point_guid) responses = response_dict['responses'] if response_dict and response_dict['status_code'] == 1: # update catch rates using multiplier if 'item_capture_mult' in responses['USE_ITEM_CAPTURE']: for rate in catch_rate_by_ball: new_catch_rate_by_ball.append( rate * responses['USE_ITEM_CAPTURE']['item_capture_mult']) self.emit_event( 'threw_berry', formatted= "Threw a {berry_name}! Catch rate with {ball_name} is now: {new_catch_rate}", data={ 'berry_name': self.inventory.get(berry_id).name, 'ball_name': self.inventory.get(current_ball).name, 'new_catch_rate': self._pct(new_catch_rate_by_ball[current_ball]) }) # softban? else: new_catch_rate_by_ball = catch_rate_by_ball self.bot.softban = True self.emit_event( 'softban', level='warning', formatted='Failed to use berry. You may be softbanned.') with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='softban_log'" ) result = c.fetchone() while True: if result[0] == 1: source = str("PokemonCatchWorker") status = str("Possible Softban") conn.execute( '''INSERT INTO softban_log (status, source) VALUES (?, ?)''', (status, source)) break else: self.emit_event( 'softban_log', sender=self, level='info', formatted="softban_log table not found, skipping log") # unknown status code else: new_catch_rate_by_ball = catch_rate_by_ball self.emit_event( 'threw_berry_failed', formatted= 'Unknown response when throwing berry: {status_code}.', data={'status_code': response_dict['status_code']}) return new_catch_rate_by_ball
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 """ if self.use_pinap_on_vip and is_vip and pokemon.level <= self.pinap_on_level_below and self.pinap_operator == "and": berry_id = ITEM_PINAPBERRY else: berry_id = ITEM_RAZZBERRY if self.pinap_operator == "or": if (self.use_pinap_on_vip and is_vip) or (pokemon.level <= self.pinap_on_level_below): berry_id = ITEM_PINAPBERRY berry_count = self.inventory.get(berry_id).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 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 ideal_catch_rate_before_throw = 1 if self.pinap_ignore_threshold and berry_id == ITEM_PINAPBERRY else ideal_catch_rate_before_throw used_berry = False original_catch_rate_by_ball = catch_rate_by_ball if DEBUG_ON: print "Pokemon Level: " + str(pokemon.level) + " Berries count: " + str(berry_count) + " Berries ID: " + str(berry_id) + " Catch rate: " + str(ideal_catch_rate_before_throw) 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] # If pinap berry is not enough, use razz berry if berry_count == 0 and berry_id == ITEM_PINAPBERRY: berry_id = ITEM_RAZZBERRY ideal_catch_rate_before_throw = self.vip_berry_threshold if is_vip else self.berry_threshold berry_count = self.inventory.get(berry_id).count # check if we've got berries to spare berries_to_spare = berry_count > 0 if is_vip else berry_count > num_next_balls + 30 changed_ball = False # Golden Razz: Use golden razz if (self.use_golden_razz_on_vip_only==is_vip) or (self.use_golden_razz_on_vip_only == False): # Golden Razz: Use golden razz when catch rate is low, keep some for raid if (self.inventory.get(ITEM_GOLDEN_RAZZ_BERRY).count > self.golden_razz_to_keep and catch_rate_by_ball[current_ball] < self.golden_razz_threshold): berry_id = ITEM_GOLDEN_RAZZ_BERRY berry_count = self.inventory.get(berry_id).count new_catch_rate_by_ball = self._use_berry(berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) self.inventory.get(berry_id).remove(1) berry_count -= 1 used_berry = True # SMART_PINAP: Use pinap when high catch rate, but spare some for VIP with high catch rate if self.smart_pinap_enabled and ( (not is_vip and self.inventory.get(ITEM_PINAPBERRY).count > self.smart_pinap_to_keep and catch_rate_by_ball[current_ball] > self.smart_pinap_threshold) or (is_vip and self.inventory.get(ITEM_PINAPBERRY).count > 0 and catch_rate_by_ball[current_ball] >= self.vip_berry_threshold) ) and not used_berry: berry_id = ITEM_PINAPBERRY berry_count = self.inventory.get(berry_id).count new_catch_rate_by_ball = self._use_berry(berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball) self.inventory.get(berry_id).remove(1) berry_count -= 1 used_berry = True # use a berry if we are under our ideal rate and have berries to spare 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(berry_id).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(berry_id).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 request = self.bot.api.create_request() request.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'] ) response_dict = request.call() 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} Shiny: {shiny}) 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), 'shiny': pokemon.shiny, '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} Shiny: {shiny}) 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), 'shiny': pokemon.shiny, '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='Candy gained: {gained_candy}. You now have {quantity} {type} candy!', data = { 'gained_candy': str(candy_gain), '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 _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 transfer_pokemon(self, pokemons, skip_delay=False): 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: request = self.bot.api.create_request() request.release_pokemon(pokemon_ids=pokemon_ids) response_dict = request.call() 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): request = self.bot.api.create_request() request.release_pokemon(pokemon_id=pokemon.unique_id) response_dict = request.call() 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)) if not skip_delay: action_delay(self.config_action_wait_min, self.config_action_wait_max) return True
def _use_berry(self, berry_id, berry_count, encounter_id, catch_rate_by_ball, current_ball): # Delay to simulate selecting berry action_delay(self.catchsim_berry_wait_min, self.catchsim_berry_wait_max) new_catch_rate_by_ball = [] self.emit_event( 'pokemon_catch_rate', level='debug', formatted='Catch rate of {catch_rate} with {ball_name} is low. Throwing {berry_name} (have {berry_count})', data={ 'catch_rate': self._pct(catch_rate_by_ball[current_ball]), 'ball_name': self.inventory.get(current_ball).name, 'berry_name': self.inventory.get(berry_id).name, 'berry_count': berry_count } ) response_dict = self.api.use_item_capture( item_id=berry_id, encounter_id=encounter_id, spawn_point_id=self.spawn_point_guid ) responses = response_dict['responses'] if response_dict and response_dict['status_code'] == 1: # update catch rates using multiplier if 'item_capture_mult' in responses['USE_ITEM_CAPTURE']: for rate in catch_rate_by_ball: new_catch_rate_by_ball.append(rate * responses['USE_ITEM_CAPTURE']['item_capture_mult']) self.emit_event( 'threw_berry', formatted="Threw a {berry_name}! Catch rate with {ball_name} is now: {new_catch_rate}", data={ 'berry_name': self.inventory.get(berry_id).name, 'ball_name': self.inventory.get(current_ball).name, 'new_catch_rate': self._pct(new_catch_rate_by_ball[current_ball]) } ) # softban? else: new_catch_rate_by_ball = catch_rate_by_ball self.bot.softban = True self.emit_event( 'softban', level='warning', formatted='Failed to use berry. You may be softbanned.' ) # unknown status code else: new_catch_rate_by_ball = catch_rate_by_ball self.emit_event( 'threw_berry_failed', formatted='Unknown response when throwing berry: {status_code}.', data={ 'status_code': response_dict['status_code'] } ) return new_catch_rate_by_ball
def _heal_pokemon(self, pokemon): if pokemon.hp == 0: self.logger.info("Can't heal a dead %s" % pokemon.name) return False # normal = inventory.items().get(Item.ITEM_POTION.value).count # super_p = inventory.items().get(Item.ITEM_SUPER_POTION.value).count # hyper = inventory.items().get(Item.ITEM_HYPER_POTION.value).count max_p = inventory.items().get(Item.ITEM_MAX_POTION.value).count # Figure out how much healing needs to be done. def hp_to_restore(pokemon): pokemon = inventory.pokemons().get_from_unique_id( pokemon.unique_id) return pokemon.hp_max - pokemon.hp if hp_to_restore(pokemon) > 200 and max_p > 0: # We should use a MAX Potion self._use_potion(Item.ITEM_MAX_POTION.value, pokemon) pokemon.hp = pokemon.hp_max return True # Okay, now we see to heal as effective as possible potions = [103, 102, 101] heals = [200, 50, 20] for item_id, max_heal in zip(potions, heals): if inventory.items().get(item_id).count > 0: while hp_to_restore(pokemon) > max_heal: if inventory.items().get(item_id).count == 0: break action_delay(2, 3) # More than 200 to restore, use a hyper first if self._use_potion(item_id, pokemon): pokemon.hp += max_heal if pokemon.hp > pokemon.hp_max: pokemon.hp = pokemon.hp_max else: break # return WorkerResult.ERROR # Now we use the least potion_id = 101 # Normals first while hp_to_restore(pokemon) > 0: action_delay(2, 4) if inventory.items().get(potion_id).count > 0: if potion_id == 104: self.logger.info("Using MAX potion to heal a %s" % pokemon.name) if self._use_potion(potion_id, pokemon): if potion_id == 104: pokemon.hp = pokemon.hp_max else: pokemon.hp += heals[potion_id - 101] if pokemon.hp > pokemon.hp_max: pokemon.hp = pokemon.hp_max else: if potion_id < 104: self.logger.info( "Failed with potion %s. Trying next." % potion_id) potion_id += 1 else: self.logger.info("Failed with MAX potion. Done.") break elif potion_id < 104: potion_id += 1 else: self.logger.info("Can't heal a %s" % pokemon.name) break
def work(self): forts = self.get_forts_in_range() with self.bot.database as conn: c = conn.cursor() c.execute("SELECT DISTINCT COUNT(pokestop) FROM pokestop_log WHERE dated >= datetime('now','-1 day')") if c.fetchone()[0] >= self.config.get('daily_spin_limit', 2000): if self.exit_on_limit_reached: self.emit_event('spin_limit', formatted='WARNING! You have reached your daily spin limit') sys.exit(2) if datetime.now() >= self.next_update: self.emit_event('spin_limit', formatted='WARNING! You have reached your daily spin limit') self._compute_next_update() return WorkerResult.SUCCESS if not self.should_run() or len(forts) == 0: return WorkerResult.SUCCESS fort = forts[0] if fort['id'] in self.streak_forts: self.fort_spins = 1 self.streak_forts = [fort['id']] elif self.fort_spins >= 10: self.fort_spins = 1 self.streak_forts = [fort['id']] else: self.fort_spins += 1 lat = fort['latitude'] lng = fort['longitude'] details = fort_details(self.bot, fort['id'], lat, lng) fort_name = details.get('name', 'Unknown') check_fort_modifier = details.get('modifiers', {}) if self.use_lure and check_fort_modifier: # check_fort_modifier_id = check_fort_modifier[0].get('item_id') self.emit_event('lure_info', formatted='A lure is already in fort, skip deploying lure') if self.use_lure and not check_fort_modifier: # check lures availiblity lure_count = inventory.items().get(501).count if lure_count > 1: # Only use lures when there's more than one request = self.bot.api.create_request() request.add_fort_modifier( modifier_type=501, fort_id = fort['id'], player_latitude = f2i(self.bot.position[0]), player_longitude = f2i(self.bot.position[1]) ) response_dict = request.call() if ('responses' in response_dict) and ('ADD_FORT_MODIFIER' in response_dict['responses']): add_modifier_deatils = response_dict['responses']['ADD_FORT_MODIFIER'] add_modifier_result = add_modifier_deatils.get('result', -1) if (add_modifier_result == LURE_REQUEST_RESULT_SUCCESS): self.emit_event('lure_success', formatted='You have successfully placed a lure') if (add_modifier_result == LURE_REQUEST_FORT_ALREADY_HAS_MODIFIER): self.emit_event('lure_failed', formatted='A lure has being placed before you try to do so') if (add_modifier_result == LURE_REQUEST_TOO_FAR_AWAY): self.emit_event('lure_failed', formatted='Pokestop out of range') if (add_modifier_result == LURE_REQUEST_NO_ITEM_IN_INVENTORY): self.emit_event('lure_not_enough', formatted='Not enough lure in inventory') if (add_modifier_result == LURE_REQUEST_POI_INACCESSIBLE): self.emit_event('lure_info', formatted='Unkown Error') else: self.emit_event('lure_not_enough', formatted='Not enough lure in inventory') request = self.bot.api.create_request() request.fort_search( fort_id=fort['id'], fort_latitude=lat, fort_longitude=lng, player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1]) ) response_dict = request.call() if ('responses' in response_dict) and ('FORT_SEARCH' in response_dict['responses']): spin_details = response_dict['responses']['FORT_SEARCH'] spin_result = spin_details.get('result', -1) if (spin_result == SPIN_REQUEST_RESULT_SUCCESS) or (spin_result == SPIN_REQUEST_RESULT_INVENTORY_FULL): self.bot.softban = False experience_awarded = spin_details.get('experience_awarded', 0) items_awarded = self.get_items_awarded_from_fort_spinned(response_dict) egg_awarded = spin_details.get('pokemon_data_egg', None) gym_badge_awarded = spin_details.get('awarded_gym_badge', None) chain_hack_sequence_number = spin_details.get('chain_hack_sequence_number', 0) if egg_awarded is not None: items_awarded[u'Egg'] = egg_awarded['egg_km_walked_target'] # if gym_badge_awarded is not None: # self.logger.info("Gained a Gym Badge! %s" % gym_badge_awarded) # # if chain_hack_sequence_number > 0: # self.logger.info("Chain hack sequence: %s" % chain_hack_sequence_number) if experience_awarded or items_awarded: awards = ', '.join(["{}x {}".format(items_awarded[x], x) for x in items_awarded if x != u'Egg']) if egg_awarded is not None: awards += u', {} Egg'.format(egg_awarded['egg_km_walked_target']) self.fort_spins = chain_hack_sequence_number if "type" in fort and fort["type"] == 1: # It's a Pokestop stop_kind = "pokestop" else: # It's a gym stop_kind = "gym" self.emit_event( 'spun_pokestop', formatted="Spun {stop_kind} {pokestop} ({spin_amount_now} streak). Experience awarded: {exp}. Items awarded: {items}", data={ 'stop_kind': stop_kind, 'pokestop': fort_name, 'exp': experience_awarded, 'spin_amount_now': chain_hack_sequence_number, 'items': awards } ) #time.sleep(10) else: self.emit_event( 'pokestop_empty', formatted='Found nothing in pokestop {pokestop}.', data={'pokestop': fort_name} ) with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='pokestop_log'") result = c.fetchone() while True: if result[0] == 1: conn.execute('''INSERT INTO pokestop_log (pokestop, exp, items) VALUES (?, ?, ?)''', (fort_name, str(experience_awarded), str(items_awarded))) break else: self.emit_event('pokestop_log', sender=self, level='info', formatted="pokestop_log table not found, skipping log") break pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) self.bot.recent_forts = self.bot.recent_forts[1:] + [fort['id']] elif spin_result == SPIN_REQUEST_RESULT_OUT_OF_RANGE: self.emit_event( 'pokestop_out_of_range', formatted="Pokestop {pokestop} out of range.", data={'pokestop': fort_name} ) elif spin_result == SPIN_REQUEST_RESULT_IN_COOLDOWN_PERIOD: pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') if pokestop_cooldown: self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) seconds_since_epoch = time.time() minutes_left = format_time( (pokestop_cooldown / 1000) - seconds_since_epoch ) self.emit_event( 'pokestop_on_cooldown', formatted="Pokestop {pokestop} on cooldown. Time left: {minutes_left}.", data={'pokestop': fort_name, 'minutes_left': minutes_left} ) elif spin_result == SPIN_REQUEST_RESULT_POI_INACCESSIBLE: self.logger.info("Pokestop not accessable at this time.") self.bot.fort_timeouts[fort["id"]] = (time.time() + 300) * 1000 # Don't spin for 5m else: self.emit_event( 'unknown_spin_result', formatted="Unknown spint result {status_code}", data={'status_code': str(spin_result)} ) if 'chain_hack_sequence_number' in response_dict['responses'][ 'FORT_SEARCH']: action_delay(self.spin_wait_min, self.spin_wait_max) return response_dict['responses']['FORT_SEARCH'][ 'chain_hack_sequence_number'] else: self.emit_event( 'pokestop_searching_too_often', formatted="Possibly searching too often, take a rest." ) if spin_result == 1 and not items_awarded and not experience_awarded and not pokestop_cooldown: self.bot.softban = True self.emit_event( 'softban', formatted='Probably got softban.' ) with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='softban_log'") result = c.fetchone() if result[0] == 1: source = str("SpinFort") status = str("Possible Softban") conn.execute('''INSERT INTO softban_log (status, source) VALUES (?, ?)''', (status, source)) else: self.emit_event('softban_log', sender=self, level='info', formatted="softban_log table not found, skipping log") self.bot.fort_timeouts[fort["id"]] = (time.time() + 300) * 1000 # Don't spin for 5m return WorkerResult.ERROR action_delay(self.spin_wait_min, self.spin_wait_max) if len(forts) > 1: return WorkerResult.RUNNING return WorkerResult.SUCCESS
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 work(self): forts = self.get_forts_in_range() if not self.should_run() or len(forts) == 0: return WorkerResult.SUCCESS fort = forts[0] lat = fort['latitude'] lng = fort['longitude'] details = fort_details(self.bot, fort['id'], lat, lng) fort_name = details.get('name', 'Unknown') response_dict = self.bot.api.fort_search( fort_id=fort['id'], fort_latitude=lat, fort_longitude=lng, player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1])) if ('responses' in response_dict) and ('FORT_SEARCH' in response_dict['responses']): spin_details = response_dict['responses']['FORT_SEARCH'] spin_result = spin_details.get('result', -1) if (spin_result == SPIN_REQUEST_RESULT_SUCCESS) or ( spin_result == SPIN_REQUEST_RESULT_INVENTORY_FULL): self.bot.softban = False experience_awarded = spin_details.get('experience_awarded', 0) items_awarded = self.get_items_awarded_from_fort_spinned( response_dict) if experience_awarded or items_awarded: self.emit_event( 'spun_pokestop', formatted= "Spun pokestop {pokestop}. Experience awarded: {exp}. Items awarded: {items}", data={ 'pokestop': fort_name, 'exp': experience_awarded, 'items': items_awarded }) else: self.emit_event( 'pokestop_empty', formatted='Found nothing in pokestop {pokestop}.', data={'pokestop': fort_name}) pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) self.bot.recent_forts = self.bot.recent_forts[1:] + [ fort['id'] ] elif spin_result == SPIN_REQUEST_RESULT_OUT_OF_RANGE: self.emit_event('pokestop_out_of_range', formatted="Pokestop {pokestop} out of range.", data={'pokestop': fort_name}) elif spin_result == SPIN_REQUEST_RESULT_IN_COOLDOWN_PERIOD: pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') if pokestop_cooldown: self.bot.fort_timeouts.update( {fort["id"]: pokestop_cooldown}) seconds_since_epoch = time.time() minutes_left = format_time((pokestop_cooldown / 1000) - seconds_since_epoch) self.emit_event( 'pokestop_on_cooldown', formatted= "Pokestop {pokestop} on cooldown. Time left: {minutes_left}.", data={ 'pokestop': fort_name, 'minutes_left': minutes_left }) else: self.emit_event('unknown_spin_result', formatted="Unknown spint result {status_code}", data={'status_code': str(spin_result)}) if 'chain_hack_sequence_number' in response_dict['responses'][ 'FORT_SEARCH']: action_delay(self.spin_wait_min, self.spin_wait_max) return response_dict['responses']['FORT_SEARCH'][ 'chain_hack_sequence_number'] else: self.emit_event( 'pokestop_searching_too_often', formatted="Possibly searching too often, take a rest.") if spin_result == 1 and not items_awarded and not experience_awarded and not pokestop_cooldown: self.bot.softban = True self.emit_event('softban', formatted='Probably got softban.') else: self.bot.fort_timeouts[fort["id"]] = ( time.time() + 300) * 1000 # Don't spin for 5m return WorkerResult.ERROR action_delay(self.spin_wait_min, self.spin_wait_max) if len(forts) > 1: return WorkerResult.RUNNING return WorkerResult.SUCCESS
def work(self): forts = self.get_forts_in_range() with self.bot.database as conn: c = conn.cursor() c.execute("SELECT DISTINCT COUNT(pokestop) FROM pokestop_log WHERE dated >= datetime('now','-1 day')") if c.fetchone()[0] >= self.config.get('daily_spin_limit', 2000): if self.exit_on_limit_reached: self.emit_event('spin_limit', formatted='WARNING! You have reached your daily spin limit') sys.exit(2) if datetime.now() >= self.next_update: self.emit_event('spin_limit', formatted='WARNING! You have reached your daily spin limit') self._compute_next_update() return WorkerResult.SUCCESS if not self.should_run() or len(forts) == 0: return WorkerResult.SUCCESS fort = forts[0] lat = fort['latitude'] lng = fort['longitude'] details = fort_details(self.bot, fort['id'], lat, lng) fort_name = details.get('name', 'Unknown') response_dict = self.bot.api.fort_search( fort_id=fort['id'], fort_latitude=lat, fort_longitude=lng, player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1]) ) if ('responses' in response_dict) and ('FORT_SEARCH' in response_dict['responses']): spin_details = response_dict['responses']['FORT_SEARCH'] spin_result = spin_details.get('result', -1) if (spin_result == SPIN_REQUEST_RESULT_SUCCESS) or (spin_result == SPIN_REQUEST_RESULT_INVENTORY_FULL): self.bot.softban = False experience_awarded = spin_details.get('experience_awarded', 0) items_awarded = self.get_items_awarded_from_fort_spinned(response_dict) egg_awarded = spin_details.get('pokemon_data_egg', None) if egg_awarded is not None: items_awarded[u'Egg'] = egg_awarded['egg_km_walked_target'] if experience_awarded or items_awarded: awards = ', '.join(["{}x {}".format(items_awarded[x], x) for x in items_awarded if x != u'Egg']) if egg_awarded is not None: awards += u', {} Egg'.format(egg_awarded['egg_km_walked_target']) self.emit_event( 'spun_pokestop', formatted="Spun pokestop {pokestop}. Experience awarded: {exp}. Items awarded: {items}", data={ 'pokestop': fort_name, 'exp': experience_awarded, 'items': awards } ) else: self.emit_event( 'pokestop_empty', formatted='Found nothing in pokestop {pokestop}.', data={'pokestop': fort_name} ) with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='pokestop_log'") result = c.fetchone() while True: if result[0] == 1: conn.execute('''INSERT INTO pokestop_log (pokestop, exp, items) VALUES (?, ?, ?)''', (fort_name, str(experience_awarded), str(items_awarded))) break else: self.emit_event('pokestop_log', sender=self, level='info', formatted="pokestop_log table not found, skipping log") break pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) self.bot.recent_forts = self.bot.recent_forts[1:] + [fort['id']] elif spin_result == SPIN_REQUEST_RESULT_OUT_OF_RANGE: self.emit_event( 'pokestop_out_of_range', formatted="Pokestop {pokestop} out of range.", data={'pokestop': fort_name} ) elif spin_result == SPIN_REQUEST_RESULT_IN_COOLDOWN_PERIOD: pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') if pokestop_cooldown: self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) seconds_since_epoch = time.time() minutes_left = format_time( (pokestop_cooldown / 1000) - seconds_since_epoch ) self.emit_event( 'pokestop_on_cooldown', formatted="Pokestop {pokestop} on cooldown. Time left: {minutes_left}.", data={'pokestop': fort_name, 'minutes_left': minutes_left} ) else: self.emit_event( 'unknown_spin_result', formatted="Unknown spint result {status_code}", data={'status_code': str(spin_result)} ) if 'chain_hack_sequence_number' in response_dict['responses'][ 'FORT_SEARCH']: action_delay(self.spin_wait_min, self.spin_wait_max) return response_dict['responses']['FORT_SEARCH'][ 'chain_hack_sequence_number'] else: self.emit_event( 'pokestop_searching_too_often', formatted="Possibly searching too often, take a rest." ) if spin_result == 1 and not items_awarded and not experience_awarded and not pokestop_cooldown: self.bot.softban = True self.emit_event( 'softban', formatted='Probably got softban.' ) with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='softban_log'") result = c.fetchone() if result[0] == 1: source = str("PokemonCatchWorker") status = str("Possible Softban") conn.execute('''INSERT INTO softban_log (status, source) VALUES (?, ?)''', (status, source)) else: self.emit_event('softban_log', sender=self, level='info', formatted="softban_log table not found, skipping log") self.bot.fort_timeouts[fort["id"]] = (time.time() + 300) * 1000 # Don't spin for 5m return WorkerResult.ERROR action_delay(self.spin_wait_min, self.spin_wait_max) if len(forts) > 1: return WorkerResult.RUNNING return WorkerResult.SUCCESS
def _heal_pokemon(self, pokemon): if pokemon.hp == 0: self.logger.info("Can't heal a dead %s" % pokemon.name) return False # normal = inventory.items().get(Item.ITEM_POTION.value).count # super_p = inventory.items().get(Item.ITEM_SUPER_POTION.value).count # hyper = inventory.items().get(Item.ITEM_HYPER_POTION.value).count max_p = inventory.items().get(Item.ITEM_MAX_POTION.value).count # Figure out how much healing needs to be done. def hp_to_restore(pokemon): pokemon = inventory.pokemons().get_from_unique_id(pokemon.unique_id) return pokemon.hp_max - pokemon.hp if hp_to_restore(pokemon) > 200 and max_p > 0: # We should use a MAX Potion self._use_potion(Item.ITEM_MAX_POTION.value, pokemon) pokemon.hp = pokemon.hp_max return True # Okay, now we see to heal as effective as possible potions = [103, 102, 101] heals = [200, 50, 20] for item_id, max_heal in zip(potions, heals): if inventory.items().get(item_id).count > 0: while hp_to_restore(pokemon) > max_heal: if inventory.items().get(item_id).count == 0: break action_delay(2, 3) # More than 200 to restore, use a hyper first if self._use_potion(item_id, pokemon): pokemon.hp += max_heal if pokemon.hp > pokemon.hp_max: pokemon.hp = pokemon.hp_max else: break # return WorkerResult.ERROR # Now we use the least potion_id = 101 # Normals first while hp_to_restore(pokemon) > 0: action_delay(2, 4) if inventory.items().get(potion_id).count > 0: if potion_id == 104: self.logger.info("Using MAX potion to heal a %s" % pokemon.name) if self._use_potion(potion_id, pokemon): if potion_id == 104: pokemon.hp = pokemon.hp_max else: pokemon.hp += heals[potion_id - 101] if pokemon.hp > pokemon.hp_max: pokemon.hp = pokemon.hp_max else: if potion_id < 104: self.logger.info("Failed with potion %s. Trying next." % potion_id) potion_id += 1 else: self.logger.info("Failed with MAX potion. Done.") break elif potion_id < 104: potion_id += 1 else: self.logger.info("Can't heal a %s" % pokemon.name) 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_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 work(self): forts = self.get_forts_in_range() with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT DISTINCT COUNT(pokestop) FROM pokestop_log WHERE dated >= datetime('now','-1 day')" ) if c.fetchone()[0] >= self.config.get('daily_spin_limit', 2000): if self.exit_on_limit_reached: self.emit_event( 'spin_limit', formatted='WARNING! You have reached your daily spin limit' ) sys.exit(2) if datetime.now() >= self.next_update: self.emit_event( 'spin_limit', formatted='WARNING! You have reached your daily spin limit' ) self._compute_next_update() return WorkerResult.SUCCESS if not self.should_run() or len(forts) == 0: return WorkerResult.SUCCESS fort = forts[0] if fort['id'] in self.streak_forts: self.fort_spins = 1 self.streak_forts = [fort['id']] elif self.fort_spins >= 10: self.fort_spins = 1 self.streak_forts = [fort['id']] else: self.fort_spins += 1 lat = fort['latitude'] lng = fort['longitude'] details = fort_details(self.bot, fort['id'], lat, lng) fort_name = details.get('name', 'Unknown') check_fort_modifier = details.get('modifiers', {}) if self.use_lure and check_fort_modifier: # check_fort_modifier_id = check_fort_modifier[0].get('item_id') self.emit_event( 'lure_info', formatted='A lure is already in fort, skip deploying lure') if self.use_lure and not check_fort_modifier: # check lures availiblity lure_count = inventory.items().get(501).count if lure_count > 1: # Only use lures when there's more than one request = self.bot.api.create_request() request.add_fort_modifier( modifier_type=501, fort_id=fort['id'], player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1])) response_dict = request.call() if ('responses' in response_dict) and ('ADD_FORT_MODIFIER' in response_dict['responses']): add_modifier_deatils = response_dict['responses'][ 'ADD_FORT_MODIFIER'] add_modifier_result = add_modifier_deatils.get( 'result', -1) if (add_modifier_result == LURE_REQUEST_RESULT_SUCCESS): self.emit_event( 'lure_success', formatted='You have successfully placed a lure') if (add_modifier_result == LURE_REQUEST_FORT_ALREADY_HAS_MODIFIER): self.emit_event( 'lure_failed', formatted= 'A lure has being placed before you try to do so') if (add_modifier_result == LURE_REQUEST_TOO_FAR_AWAY): self.emit_event('lure_failed', formatted='Pokestop out of range') if (add_modifier_result == LURE_REQUEST_NO_ITEM_IN_INVENTORY): self.emit_event( 'lure_not_enough', formatted='Not enough lure in inventory') if (add_modifier_result == LURE_REQUEST_POI_INACCESSIBLE): self.emit_event('lure_info', formatted='Unkown Error') else: self.emit_event('lure_not_enough', formatted='Not enough lure in inventory') request = self.bot.api.create_request() request.fort_search(fort_id=fort['id'], fort_latitude=lat, fort_longitude=lng, player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1])) response_dict = request.call() if ('responses' in response_dict) and ('FORT_SEARCH' in response_dict['responses']): spin_details = response_dict['responses']['FORT_SEARCH'] spin_result = spin_details.get('result', -1) if (spin_result == SPIN_REQUEST_RESULT_SUCCESS) or ( spin_result == SPIN_REQUEST_RESULT_INVENTORY_FULL): self.bot.softban = False experience_awarded = spin_details.get('experience_awarded', 0) items_awarded = self.get_items_awarded_from_fort_spinned( response_dict) egg_awarded = spin_details.get('pokemon_data_egg', None) gym_badge_awarded = spin_details.get('awarded_gym_badge', None) chain_hack_sequence_number = spin_details.get( 'chain_hack_sequence_number', 0) if egg_awarded is not None: items_awarded[u'Egg'] = egg_awarded['egg_km_walked_target'] # if gym_badge_awarded is not None: # self.logger.info("Gained a Gym Badge! %s" % gym_badge_awarded) # # if chain_hack_sequence_number > 0: # self.logger.info("Chain hack sequence: %s" % chain_hack_sequence_number) if experience_awarded or items_awarded: awards = ', '.join([ "{}x {}".format(items_awarded[x], x) for x in items_awarded if x != u'Egg' ]) if egg_awarded is not None: awards += u', {} Egg'.format( egg_awarded['egg_km_walked_target']) self.fort_spins = chain_hack_sequence_number if "type" in fort and fort["type"] == 1: # It's a Pokestop stop_kind = "pokestop" else: # It's a gym stop_kind = "gym" self.emit_event( 'spun_pokestop', formatted= "Spun {stop_kind} {pokestop} ({spin_amount_now} streak). Experience awarded: {exp}. Items awarded: {items}", data={ 'stop_kind': stop_kind, 'pokestop': fort_name, 'exp': experience_awarded, 'spin_amount_now': chain_hack_sequence_number, 'items': awards }) #time.sleep(10) else: self.emit_event( 'pokestop_empty', formatted='Found nothing in pokestop {pokestop}.', data={'pokestop': fort_name}) with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='pokestop_log'" ) result = c.fetchone() while True: if result[0] == 1: conn.execute( '''INSERT INTO pokestop_log (pokestop, exp, items) VALUES (?, ?, ?)''', (fort_name, str(experience_awarded), str(items_awarded))) break else: self.emit_event( 'pokestop_log', sender=self, level='info', formatted= "pokestop_log table not found, skipping log") break pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) self.bot.recent_forts = self.bot.recent_forts[1:] + [ fort['id'] ] elif spin_result == SPIN_REQUEST_RESULT_OUT_OF_RANGE: self.emit_event('pokestop_out_of_range', formatted="Pokestop {pokestop} out of range.", data={'pokestop': fort_name}) elif spin_result == SPIN_REQUEST_RESULT_IN_COOLDOWN_PERIOD: pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') if pokestop_cooldown: self.bot.fort_timeouts.update( {fort["id"]: pokestop_cooldown}) seconds_since_epoch = time.time() minutes_left = format_time((pokestop_cooldown / 1000) - seconds_since_epoch) self.emit_event( 'pokestop_on_cooldown', formatted= "Pokestop {pokestop} on cooldown. Time left: {minutes_left}.", data={ 'pokestop': fort_name, 'minutes_left': minutes_left }) elif spin_result == SPIN_REQUEST_RESULT_POI_INACCESSIBLE: self.logger.info("Pokestop not accessable at this time.") self.bot.fort_timeouts[fort["id"]] = ( time.time() + 300) * 1000 # Don't spin for 5m else: self.emit_event('unknown_spin_result', formatted="Unknown spint result {status_code}", data={'status_code': str(spin_result)}) if 'chain_hack_sequence_number' in response_dict['responses'][ 'FORT_SEARCH']: action_delay(self.spin_wait_min, self.spin_wait_max) return response_dict['responses']['FORT_SEARCH'][ 'chain_hack_sequence_number'] else: self.emit_event( 'pokestop_searching_too_often', formatted="Possibly searching too often, take a rest.") if spin_result == 1 and not items_awarded and not experience_awarded and not pokestop_cooldown: self.bot.softban = True self.emit_event('softban', formatted='Probably got softban.') with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='softban_log'" ) result = c.fetchone() if result[0] == 1: source = str("SpinFort") status = str("Possible Softban") conn.execute( '''INSERT INTO softban_log (status, source) VALUES (?, ?)''', (status, source)) else: self.emit_event( 'softban_log', sender=self, level='info', formatted= "softban_log table not found, skipping log") self.bot.fort_timeouts[fort["id"]] = ( time.time() + 300) * 1000 # Don't spin for 5m return WorkerResult.ERROR action_delay(self.spin_wait_min, self.spin_wait_max) if len(forts) > 1: return WorkerResult.RUNNING return WorkerResult.SUCCESS