def work(self): if not self.next_point: self.next_point = next(self.points) point = self.next_point step_walker = StepWalker(self.bot, point['lat'], point['lng']) if step_walker.step(): self.next_point = None return [point['lat'], point['lng']]
def work(self): last_lat, last_lng, last_alt = self.bot.api.get_position() point = self.points[self.ptr] self.cnt += 1 dist = distance( last_lat, last_lng, point['lat'], point['lng'] ) alt = uniform(self.bot.config.alt_min, self.bot.config.alt_max) if self.bot.config.walk_max > 0: step_walker = StepWalker( self.bot, point['lat'], point['lng'] ) if self.cnt == 1: self.emit_event( 'position_update', formatted="Walking from {last_position} to {current_position} ({distance} {distance_unit})", data={ 'last_position': (last_lat, last_lng, last_alt), 'current_position': (point['lat'], point['lng'], alt), 'distance': dist, 'distance_unit': 'm' } ) if step_walker.step(): step_walker = None else: self.bot.api.set_position(point['lat'], point['lng'], alt) self.emit_event( 'position_update', formatted="Teleported from {last_position} to {current_position} ({distance} {distance_unit})", data={ 'last_position': (last_lat, last_lng, last_alt), 'current_position': (point['lat'], point['lng'], alt), 'distance': dist, 'distance_unit': 'm' } ) if dist <= 1 or (self.bot.config.walk_min > 0 and step_walker == None): if self.ptr + self.direction >= len(self.points) or self.ptr + self.direction <= -1: self.direction *= -1 if len(self.points) != 1: self.ptr += self.direction else: self.ptr = 0 self.cnt = 0 return [point['lat'], point['lng']]
def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None return WorkerResult.SUCCESS now = time.time() pokemons = self.get_nearby_pokemons() if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons) if len(worth_pokemons) > 0: self.destination = worth_pokemons[0] self.lost_counter = 0 self.logger.info("New destination at %(distance).2f meters: %(name)s", self.destination) self.no_log_until = now + 60 if self.destination["s2_cell_id"] != self.search_cell_id: self.search_points = self.get_search_points(self.destination["s2_cell_id"]) self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_cell_id = self.destination["s2_cell_id"] self.search_points = self.search_points[1:] + self.search_points[:1] else: if self.no_log_until < now: self.logger.info("There is no nearby pokemon worth hunting down [%s]", ", ".join(p["name"] for p in pokemons)) self.no_log_until = now + 120 self.last_cell_id = None return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.destination = None else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) self.no_log_until = now + 30 return WorkerResult.RUNNING
def work(self): last_lat = self.bot.api._position_lat last_lng = self.bot.api._position_lng last_alt = self.bot.api._position_alt point = self.points[self.ptr] lat = float(point['lat']) lng = float(point['lng']) alt = uniform(self.bot.config.alt_min, self.bot.config.alt_max) if 'alt' in point: alt = float(point['alt']) if self.bot.config.walk_max > 0: step_walker = StepWalker(self.bot, lat, lng) is_at_destination = False if step_walker.step(): is_at_destination = True else: self.bot.api.set_position(lat, lng, alt) dist = distance(last_lat, last_lng, lat, lng) self.emit_event( 'position_update', formatted= "Walking from {last_position} to {current_position}, distance left: ({distance} {distance_unit}) ..", data={ 'last_position': (last_lat, last_lng, last_alt), 'current_position': (lat, lng, alt), 'distance': dist, 'distance_unit': 'm' }) if dist <= 1 or (self.bot.config.walk_min > 0 and is_at_destination): if (self.ptr + 1) == len(self.points): self.ptr = 0 if self.path_mode == 'linear': self.points = list(reversed(self.points)) if self.number_lap_max >= 0: self.number_lap += 1 self.emit_event( 'path_lap_update', formatted= "number lap : {number_lap} / {number_lap_max}", data={ 'number_lap': str(self.number_lap), 'number_lap_max': str(self.number_lap_max) }) if self.number_lap >= self.number_lap_max: self.endLaps() else: self.ptr += 1 return [lat, lng]
def walker_factory(name, bot, dest_lat, dest_lng, *args, **kwargs): ''' Charlie and the Walker Factory ''' if 'StepWalker' == name: ret = StepWalker(bot, dest_lat, dest_lng) elif 'PolylineWalker' == name: try: ret = PolylineWalker(bot, dest_lat, dest_lng) except: ret = StepWalker(bot, dest_lat, dest_lng) return ret
def work(self): last_lat, last_lng, last_alt = self.bot.api.get_position() point = self.points[self.ptr] self.cnt += 1 dist = distance(last_lat, last_lng, point['lat'], point['lng']) alt = uniform(self.bot.config.alt_min, self.bot.config.alt_max) if self.bot.config.walk_max > 0: step_walker = StepWalker(self.bot, point['lat'], point['lng']) if self.cnt == 1: self.emit_event( 'position_update', formatted= "Walking from {last_position} to {current_position} ({distance} {distance_unit})", data={ 'last_position': (last_lat, last_lng, last_alt), 'current_position': (point['lat'], point['lng'], alt), 'distance': dist, 'distance_unit': 'm' }) if step_walker.step(): step_walker = None else: self.bot.api.set_position(point['lat'], point['lng'], alt) self.emit_event( 'position_update', formatted= "Teleported from {last_position} to {current_position} ({distance} {distance_unit})", data={ 'last_position': (last_lat, last_lng, last_alt), 'current_position': (point['lat'], point['lng'], alt), 'distance': dist, 'distance_unit': 'm' }) if dist <= 1 or (self.bot.config.walk_min > 0 and step_walker == None): if self.ptr + self.direction >= len( self.points) or self.ptr + self.direction <= -1: self.direction *= -1 if len(self.points) != 1: self.ptr += self.direction else: self.ptr = 0 self.cnt = 0 return [point['lat'], point['lng']]
def test_small_distance_same_spot(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 1 self.bot.config.walk_min = 1 sw = StepWalker(self.bot, 0, 0, precision=0.0) self.assertEqual(sw.dest_lat, 0, 'dest_lat should be 0') self.assertEqual(sw.dest_lng, 0, 'dest_lng should be 0') @mock.patch('random.uniform') def run_step(mock_random): mock_random.return_value = 0.0 return sw.step() moveInprecision = run_step() self.assertTrue(moveInprecision, 'step should return True') distance = Geodesic.WGS84.Inverse(0.0, 0.0, self.bot.position[0], self.bot.position[1])["s12"] self.assertTrue(0.0 <= distance <= (sw.precision + sw.epsilon)) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def test_normalized_distance_times_2(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 2 self.bot.config.walk_min = 2 sw = StepWalker(self.bot, 0.1, 0.1, precision=0.0) self.assertTrue(sw.dest_lat > 0) self.assertTrue(sw.dest_lng > 0) @mock.patch('random.uniform') def run_step(mock_random): mock_random.return_value = 0.0 return sw.step() stayInPlace = run_step() self.assertFalse(stayInPlace) self.assertAlmostEqual(self.bot.position[0], NORMALIZED_LAT_LNG_DISTANCE[0] * 2, places=6) self.assertAlmostEqual(self.bot.position[1], NORMALIZED_LAT_LNG_DISTANCE[1] * 2, places=6) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def test_teleport(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 4 self.bot.config.walk_min = 2 sw = StepWalker(self.bot, 10, 10, precision=0.0) self.assertEqual(sw.dest_lat, 10) self.assertEqual(sw.dest_lng, 10) @mock.patch('random.uniform') def run_step(mock_random): mock_random.return_value = 0.0 return sw.step(speed=float("inf")) finishedWalking = run_step() self.assertTrue(finishedWalking, 'step should return True') total_distance = Geodesic.WGS84.Inverse(0.0, 0.0, 10, 10)["s12"] distance = Geodesic.WGS84.Inverse(0.0, 0.0, self.bot.position[0], self.bot.position[1])["s12"] self.assertTrue(0.0 <= abs(total_distance - distance) <= (sw.precision + sw.epsilon)) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def test_small_distance_small_step(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 1 self.bot.config.walk_min = 1 # distance from origin 0,0 to 1e-6, 1e-6 is 0.157253373328 meters total_distance = Geodesic.WGS84.Inverse(0.0, 0.0, 1e-6, 1e-6)["s12"] # we take a precision bigger then the total value... sw = StepWalker(self.bot, 1e-6, 1e-6, precision=0.2) self.assertEqual(sw.dest_lat, 1e-6) self.assertEqual(sw.dest_lng, 1e-6) @mock.patch('random.uniform') def run_step(mock_random): mock_random.return_value = 0.0 return sw.step() moveInprecistion = run_step() self.assertTrue(moveInprecistion, 'step should return True') distance = Geodesic.WGS84.Inverse(0.0, 0.0, self.bot.position[0], self.bot.position[1])["s12"] self.assertTrue(0.0 <= abs(total_distance - distance) <= (sw.precision + sw.epsilon)) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def test_small_distance_same_spot(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 1 self.bot.config.walk_min = 1 sw = StepWalker(self.bot, 0, 0) self.assertEqual(sw.dLat, 0, 'dLat should be 0') self.assertEqual(sw.dLng, 0, 'dLng should be 0') self.assertTrue(sw.step(), 'step should return True') self.assertTrue(self.lat == self.bot.position[0]) self.assertTrue(self.lng == self.bot.position[1]) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def test_normalized_distance_times_2(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 2 self.bot.config.walk_min = 2 sw = StepWalker(self.bot, 0.1, 0.1, precision=0.0) self.assertTrue(sw.dLat > 0) self.assertTrue(sw.dLng > 0) stayInPlace = sw.step() self.assertFalse(stayInPlace) self.assertTrue(float_equal(self.lat, NORMALIZED_LAT_LNG_DISTANCE[0] * 2)) self.assertTrue(float_equal(self.lng, NORMALIZED_LAT_LNG_DISTANCE[1] * 2)) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def test_normalized_distance(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 1 self.bot.config.walk_min = 1 sw = StepWalker(self.bot, 0.1, 0.1) self.assertGreater(sw.dLat, 0) self.assertGreater(sw.dLng, 0) stayInPlace = sw.step() self.assertFalse(stayInPlace) self.assertTrue(float_equal(self.lat, NORMALIZED_LAT_LNG_DISTANCE_STEP)) self.assertTrue(float_equal(self.lng, NORMALIZED_LAT_LNG_DISTANCE_STEP)) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def test_small_distance_small_step(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 1 self.bot.config.walk_min = 1 sw = StepWalker(self.bot, 1e-5, 1e-5) self.assertEqual(sw.dLat, 0) self.assertEqual(sw.dLng, 0) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def test_big_distances(self): walk_max = self.bot.config.walk_max walk_min = self.bot.config.walk_min self.bot.config.walk_max = 1 self.bot.config.walk_min = 1 sw = StepWalker(self.bot, 10, 10, precision=0.0) self.assertEqual(sw.dest_lat, 10) self.assertEqual(sw.dest_lng, 10) @mock.patch('random.uniform') def run_step(mock_random): mock_random.return_value = 0.0 return sw.step() finishedWalking = run_step() self.assertFalse(finishedWalking, 'step should return False') self.assertAlmostEqual(self.bot.position[0], NORMALIZED_LAT_LNG_DISTANCE[0], places=6) self.bot.config.walk_max = walk_max self.bot.config.walk_min = walk_min
def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.bot.catch_disabled: # When catching is disabled, drop the target. if self.destination is not None: self.destination = None self.last_cell_id = None if not hasattr(self.bot, "hunter_disabled_global_warning") or \ (hasattr(self.bot, "hunter_disabled_global_warning") and not self.bot.hunter_disabled_global_warning): self.logger.info("All catching tasks are currently disabled until {}. Pokemon Hunter will resume when catching tasks are re-enabled".format(self.bot.catch_resume_at.strftime("%H:%M:%S"))) self.bot.hunter_disabled_global_warning = True return WorkerResult.SUCCESS else: self.bot.hunter_disabled_global_warning = False if self.bot.softban: # At softban, drop target if self.destination is not None: self.destination = None self.last_cell_id = None self.hunting_trash = False if not hasattr(self.bot, "softban_global_warning") or \ (hasattr(self.bot, "softban_global_warning") and not self.bot.softban_global_warning): self.logger.info("Possible softban! Not trying to catch Pokemon.") self.bot.softban_global_warning = True return WorkerResult.SUCCESS else: self.bot.softban_global_warning = False if self.config_disabled_while_camping and hasattr(self.bot, 'camping_forts') and self.bot.camping_forts: return WorkerResult.SUCCESS if not self.config_lock_on_target: self.bot.hunter_locked_target = None if self.no_hunt_until != None and self.no_hunt_until > time.time(): # No hunting now, cooling down return WorkerResult.SUCCESS else: # Resume hunting self.no_hunt_until = None if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None self.hunting_trash = False return WorkerResult.SUCCESS if hasattr(self.bot,"hunter_locked_target"): if self.destination is not None and self.bot.hunter_locked_target is not None: if self.destination is not self.bot.hunter_locked_target: self.logger.info("Locked on to a different target than destination??") self.bot.hunter_locked_target = None if self.destination is not None: if self.destination_caught(): self.logger.info("We found a %(name)s while hunting.", self.destination) # self.recent_tries.append(self.destination['pokemon_id']) self.previous_destination = self.destination self.destination = None self.hunting_trash = False self.bot.hunter_locked_target = None self.lost_counter = 0 self.lost_map_counter = 0 if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS else: self.logger.info("Electing new target....") if self.destination_vanished(): self.logger.info("Darn, target got away!") # self.recent_tries.append(self.destination['pokemon_id']) self.previous_destination = self.destination self.destination = None self.hunting_trash = False self.bot.hunter_locked_target = None self.lost_counter = 0 self.lost_map_counter = 0 if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS else: self.logger.info("Electing new target....") now = time.time() pokemons = self.get_nearby_pokemons() pokemons = filter(lambda x: x["pokemon_id"] not in self.recent_tries, pokemons) trash_mons = ["Caterpie", "Weedle", "Pidgey", "Pidgeotto", "Pidgeot", "Kakuna", "Beedrill", "Metapod", "Butterfree"] if self.destination is not None: target_mons = filter(lambda x: x["name"] is self.destination["name"], pokemons) if self.no_log_until < now: # self.logger.info("Targets on sightings: %s" % len(target_mons)) if len(pokemons) > 0: if len(target_mons) < 1: # Target off sightings; must be getting close # Drops of at about 120 meters to target... distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters if (distance > 125 and self.lost_map_counter > 4) or self.lost_map_counter > 10: # If > 120 meter => must be gone? # Searching for 10 times, give up... self.logger.info("It seems %(name)s is no longer there!", self.destination) self.destination = None self.hunting_trash = False self.bot.hunter_locked_target = None self.lost_map_counter = 0 self.lost_counter = 0 if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS else: self.logger.info("Electing new target....") else: self.lost_map_counter += 1 else: self.lost_map_counter = 0 else: self.logger.info("No sightings available at the moment...") if self.config_hunt_for_trash and self.hunting_trash is False and (self.destination is None or not self._is_vip_pokemon(self.destination) ): # Okay, we should hunt for trash if the bag is almost full pokemons.sort(key=lambda p: p["distance"]) possible_targets = filter(lambda x: x["name"] in trash_mons, pokemons) if self.pokemon_slots_left() <= self.config_trash_hunt_open_slots: if self.no_log_until < now: self.logger.info("Less than %s slots left to fill, starting hunt for trash" % self.config_trash_hunt_open_slots) if len(possible_targets) is 0: self.logger.info("No trash pokemon around...") for pokemon in possible_targets: if self.destination is not None: self.logger.info("Trash hunt takes priority! Changing target...") self.hunting_trash = True self.destination = pokemon self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("Hunting for trash at %(distance).2f meters: %(name)s", self.destination) self.set_target() # We have a target return WorkerResult.RUNNING if self.config_hunt_for_trash and self.hunting_trash: if self.pokemon_slots_left() > self.config_trash_hunt_open_slots: self.logger.info("No longer trying to fill the bag. Electing new target....") self.hunting_trash = False self.destination = None # Closer target? if self.no_log_until < now: # Don't check every tick! if self.destination is not None and len(pokemons) > 0: pokemons.sort(key=lambda p: p["distance"]) possible_targets = filter(lambda x: x["name"] in trash_mons, pokemons) # Check for a closer target self.destination["distance"] = self.get_distance(self.bot.position, self.destination) for pokemon in possible_targets: if pokemon is not self.destination: if round(pokemon["distance"], 2) >= round(self.destination["distance"], 2): # further away! break self.logger.info("Found a closer target: %s < %s" % (pokemon["distance"], self.destination["distance"])) if self.destination is not None: self.logger.info("Closer trash hunt takes priority! Changing target...") self.hunting_trash = True self.destination = pokemon self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("New target at %(distance).2f meters: %(name)s", self.destination) self.set_target() # We have a target return WorkerResult.RUNNING if self.destination is None: # Use this time for shadowban check if self.shadowban_detection: if not self.check_rare_pokemons(pokemons): self.no_rare_counts += 1 self.logger.info("[Shadow Ban Detection] I cannot find any rares/uncommon pokemons. Count: " + format(self.no_rare_counts)) else: # Reset to zero self.logger.info("[Shadow Ban Detection] Rares/uncommon pokemons are spotted") self.no_rare_counts = 0 if self.no_rare_counts > 3: # If more than 3 times we can't find any rares, we alert user of possible shadow bans self.emit_event( 'shadowban_alert', formatted="\033[91m[Shadow Ban Alert]\033[0m More than 3 occassions we could not find any rare pokemons." ) if self.no_rare_counts == 4: # Record in database once per run try: with self.bot.database as conn: c = conn.cursor() c.execute("SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name='shadowban_log'") result = c.fetchone() while True: if result[0] == 1: conn.execute('''INSERT INTO shadowban_log (username) VALUES (?)''', (str(self.bot.config.username),)) break else: self.emit_event( 'shadowban_log', sender=self, level='info', formatted="shadow_log table not found, skipping log" ) user_data_shadowban = os.path.join(_base_dir, 'data', 'shadowban-%s.json' % self.bot.config.username) with open(user_data_shadowban, 'ab') as outfile: json.dump(OrderedDict({ 'datetime': str(datetime.now()), 'username': self.bot.config.username }), outfile) outfile.write('\n') except IOError as e: self.logger.info('[x] Error while opening location file: %s' % e) if self.exit_if_shadowbanned: sys.exit(0) worth_pokemons = self.get_worth_pokemons(pokemons, self.config_hunt_closest_first) if len(worth_pokemons) > 0: # Pick a random target from the list # random.shuffle(worth_pokemons) if self.config_hunt_closest_first: # Priotize closer pokemon worth_pokemons.sort(key=lambda p: p["distance"]) else: random.shuffle(worth_pokemons) # Prevents the bot from looping the same Pokemon self.destination = worth_pokemons[0] if self.previous_destination is not None: # Check if we are hunting the same target again... if self.previous_destination["pokemon_id"] == self.destination["pokemon_id"]: # Hunting the same pokemon again? if "fort_id" in self.previous_destination and "fort_id" in self.destination and \ self.previous_destination["fort_id"] == self.destination["fort_id"]: # Hunting the same target again? if len(worth_pokemons) > 1: self.destination = worth_pokemons[1] else: # Checking if it's the same distance... self.previous_destination["distance"] = self.get_distance(self.bot.start_position, self.previous_destination) self.destination["distance"] = self.get_distance(self.bot.start_position, self.destination) if round(self.previous_destination["distance"], 2) == round(self.destination["distance"], 2): self.logger.info("Likely we are trying the same Pokemon again") if len(worth_pokemons) > 1: self.destination = worth_pokemons[1] if self.previous_destination == self.destination: # We already caught that Pokemon! if len(worth_pokemons) > 1: self.destination = worth_pokemons[1] self.set_target() self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("New destination at %(distance).2f meters: %(name)s", self.destination) if self._is_vip_pokemon(self.destination) and self.config_lock_on_target: self.logger.info("This is a VIP Pokemon! Locking on to target!") self.bot.hunter_locked_target = self.destination elif self._is_family_of_vip(self.destination) and self.config_treat_family_of_vip_as_vip and self.config_lock_on_target: self.logger.info("This Pokemon is family of a VIP! Locking target!") self.bot.hunter_locked_target = self.destination elif self._is_needed_pokedex(self.destination): self.logger.info("I need a %(name)s to complete the Pokedex! I have %(candies)s candies.", self.destination) if self.config_lock_on_target and not self.config_lock_vip_only: self.bot.hunter_locked_target = self.destination else: self.bot.hunter_locked_target = None self.no_log_until = now + 60 # We have a target return WorkerResult.SUCCESS else: if self.no_log_until < now: # Show like "Pidgey (12), Zubat(2)" names = Counter((p["name"] for p in pokemons)) sorted(names) # unicode object, no lower? , key=str.lower) if len(names) > 0: self.logger.info("There is no nearby pokemon worth hunting down [%s]", ", ".join('{}({})'.format(key, val) for key, val in names.items())) else: self.logger.info("No sightings available at the moment...") self.no_log_until = now + 120 self.destination = None if self.config_enable_cooldown: wait = uniform(120, 360) self.no_hunt_until = now + wait self.logger.info("Will look again around {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) self.last_cell_id = None return WorkerResult.SUCCESS # Make sure a VIP is treated that way if self.config_lock_on_target and self.bot.hunter_locked_target is None and self.destination is not None: if self._is_vip_pokemon(self.destination): self.bot.hunter_locked_target = self.destination #Check if we are treating Family of VIP as VIP if self.config_treat_family_of_vip_as_vip and self.destination is not None: if self._is_family_of_vip(self.destination): # We're hunting for family, so we need to check if we find a VIP if self.no_log_until < now: # Not every tick please possible_targets = filter(lambda p: self._is_vip_pokemon(p), pokemons) # Update the distance to targets for p in possible_targets: p["distance"] = self.get_distance(self.bot.position, p) possible_targets.sort(key=lambda p: p["distance"]) if len(possible_targets) > 0: # Check if it's not the same mon... if possible_targets[0]["name"] != self.destination["name"]: self.logger.info("We found a real VIP while hunting for %(name)s", self.destination) self.destination = possible_targets[0] self.bot.hunter_locked_target = self.destination self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("New VIP target at %(distance).2f meters: %(name)s", self.destination) self.set_target() # We have a target return WorkerResult.RUNNING # Now we check if there is a VIP target closer by if self.destination is not None and self.bot.hunter_locked_target is self.destination: # Hunting a VIP, checking for closer VIP target if self.no_log_until < now: # Not every tick please possible_targets = filter(lambda p: self._is_vip_pokemon(p), pokemons) # Update the distance to targets for p in possible_targets: p["distance"] = self.get_distance(self.bot.position, p) possible_targets.sort(key=lambda p: p["distance"]) # Check for a closer target self.destination["distance"] = self.get_distance(self.bot.position, self.destination) for pokemon in possible_targets: if pokemon is not self.destination: if round(pokemon["distance"], 2) >= round(self.destination["distance"], 2): # further away! break with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(pokemon) FROM catch_log where pokemon = '{}' and datetime(dated, 'localtime') > Datetime('{}')".format(pokemon["name"], self.hunt_started_at.strftime("%Y-%m-%d %H:%M:%S"))) # Now check if there is 1 or more caught amount = c.fetchone()[0] if amount > 0: # We caught this pokemon recently, skip it continue if self.config_treat_family_of_vip_as_vip and self._is_family_of_vip(pokemon): if self._is_vip_pokemon(self.destination): self.logger.info("Seeing a familymember of a VIP at %(distance).2f meters: %(name)s", pokemon) self.logger.info("Not hunting down because we are locked to a real VIP: %(name)s", self.destination) continue else: self.logger.info("Closer (is distance) familymember of VIP found!") self.logger.info("Found a closer VIP target: %s < %s" % (pokemon["distance"], self.destination["distance"])) if self.destination is not None: self.logger.info("Closer VIP hunt takes priority! Changing target...") self.destination = pokemon self.bot.hunter_locked_target = self.destination self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("New VIP target at %(distance).2f meters: %(name)s", self.destination) self.set_target() # We have a target return WorkerResult.RUNNING # Check if there is a VIP around to hunt if (self.destination is not None and self.config_lock_on_target and self.config_lock_vip_only and self.bot.hunter_locked_target is None): worth_pokemons = self.get_worth_pokemons(pokemons) # We have a none VIP target set, check for VIP targets! if len(worth_pokemons) > 0: for pokemon in worth_pokemons: if self._is_vip_pokemon(pokemon): self.hunting_trash = False self.destination = pokemon self.lost_counter = 0 self.hunt_started_at = datetime.now() self.set_target() if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination self.logger.info("Spotted a VIP Pokemon! Looking for a %(name)s at %(distance).2f.", self.destination) return WorkerResult.SUCCESS if self.destination is None: if self.no_log_until < now: self.logger.info("Nothing to hunt.") return WorkerResult.SUCCESS if self.config_lock_on_target and not self.config_lock_vip_only: if self.bot.hunter_locked_target == None: self.logger.info("We found a %(name)s while hunting. Aborting the current search.", self.destination) self.previous_destination = self.destination self.destination = None self.hunting_trash = False if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS # Determin if we are allowed to run to a VIP different_target = False if self.destination is not None: if self.previous_destination is None: self.previous_destination = self.destination elif self.previous_destination is not self.destination: different_target = True self.previous_destination = self.destination if self.config_run_to_vip and self._is_vip_pokemon(self.destination): if self.runs_to_vips > 3: self.logger.info("Ran to 3 Pokemon in a row. Cooling down...") self.runs_to_vips = 0 speed = None else: speed = self.bot.config.walk_max if different_target: self.runs_to_vips += 1 else: speed = None if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None self.hunting_trash = False elif self.walker.step(speed): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.logger.info("I haven't found %(name)s", self.destination) self.bot.hunter_locked_target = None self.destination = None self.hunting_trash = False if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) else: self.logger.info("Now searching for %(name)s", self.destination) if self.search_points == []: self.walker = StepWalker(self.bot, self.destination['latitude'], self.destination['longitude']) else: self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters if round(distance, 2) == self.distance_to_target: # Hmm, not moved toward the Pokemon? self.distance_counter += 1 else: self.distance_counter = 0 if self.distance_counter is 3: # Try another walker self.logger.info("Having difficulty walking to target, changing walker!") self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.distance_counter += 1 if self.distance_counter >= 6: # Ignore last 3 if len(self.recent_tries) > 3: self.recent_tries.pop() self.recent_tries.append(self.destination['pokemon_id']) self.logger.info("I cant move toward %(name)s! Aborting search.", self.destination) self.hunting_trash = False self.bot.hunter_locked_target = None self.destination = None if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.ERROR else: unit = self.bot.config.distance_unit # Unit to use when printing formatted distance if speed is not None: self.emit_event( 'moving_to_hunter_target', formatted="Running towards VIP target {target_name} - {distance}", data={ 'target_name': u"{}".format(self.destination["name"]), 'distance': format_dist(distance, unit), } ) else: self.emit_event( 'moving_to_hunter_target', formatted="Moving towards target {target_name} - {distance}", data={ 'target_name': u"{}".format(self.destination["name"]), 'distance': format_dist(distance, unit), } ) # self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) # record the new distance... self.distance_to_target = round(distance, 2) if self.config_lock_on_target and not self.config_lock_vip_only: # Just to ensure we stay on target self.bot.hunter_locked_target = self.destination self.no_log_until = now + 5 return WorkerResult.RUNNING
def test_big_distances(self): # FIXME currently the StepWalker acts like it won't move if big distances gives as input # see args below # with self.assertRaises(RuntimeError): sw = StepWalker(self.bot, 10, 10) sw.step() # equals True i.e act like the distance is too short for a step
def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.config_disabled_while_camping and hasattr( self.bot, 'camping_forts') and self.bot.camping_forts: return WorkerResult.SUCCESS if not self.config_lock_on_target: self.bot.hunter_locked_target = None if self.no_hunt_until != None and self.no_hunt_until > time.time(): # No hunting now, cooling down return WorkerResult.SUCCESS else: # Resume hunting self.no_hunt_until = None if self.bot.catch_disabled: if not hasattr(self.bot,"hunter_disabled_global_warning") or \ (hasattr(self.bot,"hunter_disabled_global_warning") and not self.bot.hunter_disabled_global_warning): self.logger.info( "All catching tasks are currently disabled until {}. Pokemon Hunter will resume when catching tasks are re-enabled" .format(self.bot.catch_resume_at.strftime("%H:%M:%S"))) self.bot.hunter_disabled_global_warning = True return WorkerResult.SUCCESS else: self.bot.hunter_disabled_global_warning = False if self.bot.softban: if not hasattr(self.bot, "softban_global_warning") or \ (hasattr(self.bot, "softban_global_warning") and not self.bot.softban_global_warning): self.logger.info( "Possible softban! Not trying to catch Pokemon.") self.bot.softban_global_warning = True return WorkerResult.SUCCESS else: self.bot.softban_global_warning = False if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None return WorkerResult.SUCCESS if self.destination is not None: if self.destination_caught(): self.logger.info( "We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS now = time.time() pokemons = self.get_nearby_pokemons() pokemons = filter(lambda x: x["pokemon_id"] not in self.recent_tries, pokemons) if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons) if len(worth_pokemons) > 0: # Pick a random target from the list random.shuffle(worth_pokemons) # Prevents the bot from looping the same Pokemon self.destination = worth_pokemons[0] self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info( "New destination at %(distance).2f meters: %(name)s", self.destination) if self._is_vip_pokemon(self.destination): self.logger.info("This is a VIP Pokemon! Starting hunt.") if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination elif self._is_needed_pokedex(self.destination): self.logger.info( "I need a %(name)s to complete the Pokedex! I have %(candies)s candies.", self.destination) if self.config_lock_on_target and not self.config_lock_vip_only: self.bot.hunter_locked_target = self.destination else: self.bot.hunter_locked_target = None self.no_log_until = now + 60 if self.destination["s2_cell_id"] != self.search_cell_id: self.search_points = self.get_search_points( self.destination["s2_cell_id"]) self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_cell_id = self.destination["s2_cell_id"] self.search_points = self.search_points[ 1:] + self.search_points[:1] else: if self.no_log_until < now: # Show like "Pidgey (12), Zubat(2)" names = Counter((p["name"] for p in pokemons)) sorted(names) # unicode object, no lower? , key=str.lower) self.logger.info( "There is no nearby pokemon worth hunting down [%s]", ", ".join('{}({})'.format(key, val) for key, val in names.items())) self.no_log_until = now + 120 self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Will look again around {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) self.last_cell_id = None return WorkerResult.SUCCESS if self.config_lock_on_target and not self.config_lock_vip_only: if self.bot.hunter_locked_target == None: self.logger.info( "We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.logger.info("I haven't found %(name)s", self.destination) self.bot.hunter_locked_target = None self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[ 1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle( self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters if round(distance, 2) == self.distance_to_target: # Hmm, not moved toward the Pokemon? self.distance_counter += 1 else: self.distance_counter = 0 if self.distance_counter >= 3: # Ignore last 3 if len(self.recent_tries) > 3: self.recent_tries.pop() self.recent_tries.append(self.destination['pokemon_id']) self.logger.info( "I cant move toward %(name)s! Aborting search.", self.destination) self.bot.hunter_locked_target = None self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.ERROR else: self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) # record the new distance... self.distance_to_target = round(distance, 2) if self.config_lock_on_target and not self.config_lock_vip_only: # Just to ensure we stay on target self.bot.hunter_locked_target = self.destination self.no_log_until = now + 30 return WorkerResult.RUNNING
def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.config_disabled_while_camping and hasattr(self.bot, 'camping_forts') and self.bot.camping_forts: return WorkerResult.SUCCESS if not self.config_lock_on_target: self.bot.hunter_locked_target = None if self.no_hunt_until != None and self.no_hunt_until > time.time(): # No hunting now, cooling down return WorkerResult.SUCCESS else: # Resume hunting self.no_hunt_until = None if self.bot.catch_disabled: if not hasattr(self.bot,"hunter_disabled_global_warning") or \ (hasattr(self.bot,"hunter_disabled_global_warning") and not self.bot.hunter_disabled_global_warning): self.logger.info("All catching tasks are currently disabled until {}. Pokemon Hunter will resume when catching tasks are re-enabled".format(self.bot.catch_resume_at.strftime("%H:%M:%S"))) self.bot.hunter_disabled_global_warning = True return WorkerResult.SUCCESS else: self.bot.hunter_disabled_global_warning = False if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None return WorkerResult.SUCCESS if self.destination is not None: if self.destination_caught(): self.logger.info("We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS now = time.time() pokemons = self.get_nearby_pokemons() pokemons = filter(lambda x: x["pokemon_id"] not in self.recent_tries, pokemons) if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons) if len(worth_pokemons) > 0: # Pick a random target from the list random.shuffle(worth_pokemons) # Prevents the bot from looping the same Pokemon self.destination = worth_pokemons[0] self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("New destination at %(distance).2f meters: %(name)s", self.destination) if self._is_vip_pokemon(self.destination): self.logger.info("This is a VIP Pokemon! Starting hunt.") if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination elif self._is_needed_pokedex(self.destination): self.logger.info("I need a %(name)s to complete the Pokedex! I have %(candies)s candies.", self.destination) if self.config_lock_on_target and not self.config_lock_vip_only: self.bot.hunter_locked_target = self.destination else: self.bot.hunter_locked_target = None self.no_log_until = now + 60 if self.destination["s2_cell_id"] != self.search_cell_id: self.search_points = self.get_search_points(self.destination["s2_cell_id"]) self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_cell_id = self.destination["s2_cell_id"] self.search_points = self.search_points[1:] + self.search_points[:1] else: if self.no_log_until < now: # Show like "Pidgey (12), Zubat(2)" names = Counter((p["name"] for p in pokemons)) sorted(names) # unicode object, no lower? , key=str.lower) self.logger.info("There is no nearby pokemon worth hunting down [%s]", ", ".join('{}({})'.format(key, val) for key, val in names.items())) self.no_log_until = now + 120 self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Will look again around {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) self.last_cell_id = None return WorkerResult.SUCCESS if self.config_lock_on_target and not self.config_lock_vip_only: if self.bot.hunter_locked_target == None: self.logger.info("We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.logger.info("I haven't found %(name)s", self.destination) self.bot.hunter_locked_target = None self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters if round(distance, 2) == self.distance_to_target: # Hmm, not moved toward the Pokemon? self.distance_counter += 1 else: self.distance_counter = 0 if self.distance_counter >= 3: # Ignore last 3 if len(self.recent_tries) > 3: self.recent_tries.pop() self.recent_tries.append(self.destination['pokemon_id']) self.logger.info("I cant move toward %(name)s! Aborting search.", self.destination) self.bot.hunter_locked_target = None self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.ERROR else: self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) # record the new distance... self.distance_to_target = round(distance, 2) if self.config_lock_on_target and not self.config_lock_vip_only: # Just to ensure we stay on target self.bot.hunter_locked_target = self.destination self.no_log_until = now + 30 return WorkerResult.RUNNING
class PokemonHunter(BaseTask): SUPPORTED_TASK_API_VERSION = 1 def __init__(self, bot, config): super(PokemonHunter, self).__init__(bot, config) def initialize(self): self.notified_second_gen = [] self.destination = None self.walker = None self.search_cell_id = None self.search_points = [] self.lost_counter = 0 self.no_log_until = 0 self.distance_to_target = 0 self.distance_counter = 0 self.recent_tries = [] self.no_hunt_until = None self.hunt_started_at = None self.config_max_distance = self.config.get("max_distance", 2000) self.config_hunt_all = self.config.get("hunt_all", False) self.config_hunt_vip = self.config.get("hunt_vip", True) self.config_hunt_pokedex = self.config.get("hunt_pokedex", True) # Lock on Target; ignore all other Pokémon until we found our target. self.config_lock_on_target = self.config.get("lock_on_target", False) # Lock only VIP Pokemon (unseen / VIP) self.config_lock_vip_only = self.config.get("lock_vip_only", True) # If we are camping forts, disable hunting (see CampFort) self.config_disabled_while_camping = self.config.get("disabled_while_camping", True) # Hunt unseens as VIP? self.config_treat_unseen_as_vip = self.config.get("treat_unseen_as_vip", True) self.bot.hunter_locked_target = None def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.config_disabled_while_camping and hasattr(self.bot, 'camping_forts') and self.bot.camping_forts: return WorkerResult.SUCCESS if not self.config_lock_on_target: self.bot.hunter_locked_target = None if self.no_hunt_until != None and self.no_hunt_until > time.time(): # No hunting now, cooling down return WorkerResult.SUCCESS else: # Resume hunting self.no_hunt_until = None if self.bot.catch_disabled: if not hasattr(self.bot,"hunter_disabled_global_warning") or \ (hasattr(self.bot,"hunter_disabled_global_warning") and not self.bot.hunter_disabled_global_warning): self.logger.info("All catching tasks are currently disabled until {}. Pokemon Hunter will resume when catching tasks are re-enabled".format(self.bot.catch_resume_at.strftime("%H:%M:%S"))) self.bot.hunter_disabled_global_warning = True return WorkerResult.SUCCESS else: self.bot.hunter_disabled_global_warning = False if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None return WorkerResult.SUCCESS if self.destination is not None: if self.destination_caught(): self.logger.info("We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS now = time.time() pokemons = self.get_nearby_pokemons() pokemons = filter(lambda x: x["pokemon_id"] not in self.recent_tries, pokemons) if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons) if len(worth_pokemons) > 0: # Pick a random target from the list random.shuffle(worth_pokemons) # Prevents the bot from looping the same Pokemon self.destination = worth_pokemons[0] self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("New destination at %(distance).2f meters: %(name)s", self.destination) if self._is_vip_pokemon(self.destination): self.logger.info("This is a VIP Pokemon! Starting hunt.") if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination elif self._is_needed_pokedex(self.destination): self.logger.info("I need a %(name)s to complete the Pokedex! I have %(candies)s candies.", self.destination) if self.config_lock_on_target and not self.config_lock_vip_only: self.bot.hunter_locked_target = self.destination else: self.bot.hunter_locked_target = None self.no_log_until = now + 60 if self.destination["s2_cell_id"] != self.search_cell_id: self.search_points = self.get_search_points(self.destination["s2_cell_id"]) self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_cell_id = self.destination["s2_cell_id"] self.search_points = self.search_points[1:] + self.search_points[:1] else: if self.no_log_until < now: # Show like "Pidgey (12), Zubat(2)" names = Counter((p["name"] for p in pokemons)) sorted(names) # unicode object, no lower? , key=str.lower) self.logger.info("There is no nearby pokemon worth hunting down [%s]", ", ".join('{}({})'.format(key, val) for key, val in names.items())) self.no_log_until = now + 120 self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Will look again around {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) self.last_cell_id = None return WorkerResult.SUCCESS if self.config_lock_on_target and not self.config_lock_vip_only: if self.bot.hunter_locked_target == None: self.logger.info("We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.logger.info("I haven't found %(name)s", self.destination) self.bot.hunter_locked_target = None self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters if round(distance, 2) == self.distance_to_target: # Hmm, not moved toward the Pokemon? self.distance_counter += 1 else: self.distance_counter = 0 if self.distance_counter >= 3: # Ignore last 3 if len(self.recent_tries) > 3: self.recent_tries.pop() self.recent_tries.append(self.destination['pokemon_id']) self.logger.info("I cant move toward %(name)s! Aborting search.", self.destination) self.bot.hunter_locked_target = None self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.ERROR else: self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) # record the new distance... self.distance_to_target = round(distance, 2) if self.config_lock_on_target and not self.config_lock_vip_only: # Just to ensure we stay on target self.bot.hunter_locked_target = self.destination self.no_log_until = now + 30 return WorkerResult.RUNNING def get_pokeball_count(self): return sum([inventory.items().get(ball.value).count for ball in [Item.ITEM_POKE_BALL, Item.ITEM_GREAT_BALL, Item.ITEM_ULTRA_BALL]]) def get_nearby_pokemons(self): radius = self.config_max_distance pokemons = [p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius] for pokemon in pokemons: pokemon["distance"] = self.get_distance(self.bot.position, p) pokemon["name"] = inventory.pokemons().name_for(pokemon["pokemon_id"]) pokemon["candies"] = inventory.candies().get(pokemon["pokemon_id"]).quantity pokemons.sort(key=lambda p: p["distance"]) return pokemons def _is_vip_pokemon(self, pokemon): # having just a name present in the list makes them vip # Not seen pokemons also will become vip if it's not disabled in config if self.bot.config.vips.get(pokemon["name"]) == {} or (self.config_treat_unseen_as_vip and not inventory.pokedex().seen(pokemon["pokemon_id"])): return True def _is_needed_pokedex(self, pokemon): candies = inventory.candies().get(pokemon["pokemon_id"]).quantity if candies > 150: # We have enough candies, pass on hunting this Pokemon return False # get family ids, gets ALL ids, also for previous evo! # We could see a Ivysaur on the map, and need a Bulbasaur # Then we have no need for a Ivysaur. If we see a Bulbasaur and need # a Ivysaur, then we DO need this pokemon. got_current_evo = False ids = [] for fid in self.get_family_ids(pokemon): if got_current_evo: ids += [fid] else: if fid == pokemon["pokemon_id"]: ids += [fid] got_current_evo = True # Check if we need this, or a next EVO in the Pokedex if any(not inventory.pokedex().seen(fid) for fid in ids): return True def get_worth_pokemons(self, pokemons): if self.config_hunt_all: worth_pokemons = pokemons else: worth_pokemons = [] if self.config_hunt_vip: worth_pokemons += [p for p in pokemons if p["name"] in self.bot.config.vips] if self.config_hunt_pokedex: worth_pokemons += [p for p in pokemons if (p not in worth_pokemons) and self._is_needed_pokedex(p)] worth_pokemons.sort(key=lambda p: inventory.candies().get(p["pokemon_id"]).quantity) return worth_pokemons def get_family_ids(self, pokemon): family_id = inventory.pokemons().data_for(pokemon["pokemon_id"]).first_evolution_id ids = [family_id] ids += inventory.pokemons().data_for(family_id).next_evolutions_all[:] return ids def get_distance(self, location, pokemon): return great_circle(location, (pokemon["latitude"], pokemon["longitude"])).meters def get_search_points(self, cell_id): points = [] # For cell level 15 for c in Cell(CellId(cell_id)).subdivide(): for cc in c.subdivide(): latlng = LatLng.from_point(cc.get_center()) point = (latlng.lat().degrees, latlng.lng().degrees) points.append(point) points[0], points[1] = points[1], points[0] points[14], points[15] = points[15], points[14] point = points.pop(2) points.insert(7, point) point = points.pop(13) points.insert(8, point) closest = min(points, key=lambda p: great_circle(self.bot.position, p).meters) index = points.index(closest) return points[index:] + points[:index] def destination_caught(self): # self.logger.info("Searching for a {} since {}".format(self.destination["name"], self.hunt_started_at.strftime("%Y-%m-%d %H:%M:%S"))) with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(pokemon) FROM catch_log where pokemon = '{}' and datetime(dated, 'localtime') > Datetime('{}')".format(self.destination["name"], self.hunt_started_at.strftime("%Y-%m-%d %H:%M:%S"))) # Now check if there is 1 or more caught amount = c.fetchone()[0] caught = amount > 0 if caught: self.logger.info("We caught {} {}(s) since {}".format(amount, self.destination["name"], self.hunt_started_at.strftime("%Y-%m-%d %H:%M:%S"))) return caught
def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.bot.catch_disabled: if not hasattr(self.bot,"hunter_disabled_global_warning") or \ (hasattr(self.bot,"hunter_disabled_global_warning") and not self.bot.hunter_disabled_global_warning): self.logger.info( "All catching tasks are currently disabled until {}. Pokemon Hunter will resume when catching tasks are re-enabled" .format(self.bot.catch_resume_at.strftime("%H:%M:%S"))) self.bot.hunter_disabled_global_warning = True return WorkerResult.SUCCESS else: self.bot.hunter_disabled_global_warning = False if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None return WorkerResult.SUCCESS now = time.time() pokemons = self.get_nearby_pokemons() if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons) if len(worth_pokemons) > 0: self.destination = worth_pokemons[0] self.lost_counter = 0 self.logger.info( "New destination at %(distance).2f meters: %(name)s", self.destination) self.no_log_until = now + 60 if self.destination["s2_cell_id"] != self.search_cell_id: self.search_points = self.get_search_points( self.destination["s2_cell_id"]) self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_cell_id = self.destination["s2_cell_id"] self.search_points = self.search_points[ 1:] + self.search_points[:1] else: if self.no_log_until < now: self.logger.info( "There is no nearby pokemon worth hunting down [%s]", ", ".join(p["name"] for p in pokemons)) self.no_log_until = now + 120 self.last_cell_id = None return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.destination = None else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[ 1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle( self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) self.no_log_until = now + 30 return WorkerResult.RUNNING
class PokemonHunter(BaseTask): SUPPORTED_TASK_API_VERSION = 1 def __init__(self, bot, config): super(PokemonHunter, self).__init__(bot, config) def initialize(self): self.destination = None self.walker = None self.search_cell_id = None self.search_points = [] self.lost_counter = 0 self.no_log_until = 0 self.config_max_distance = self.config.get("max_distance", 2000) self.config_hunt_all = self.config.get("hunt_all", False) self.config_hunt_vip = self.config.get("hunt_vip", True) self.config_hunt_pokedex = self.config.get("hunt_pokedex", True) def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None return WorkerResult.SUCCESS now = time.time() pokemons = self.get_nearby_pokemons() if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons) if len(worth_pokemons) > 0: self.destination = worth_pokemons[0] self.lost_counter = 0 self.logger.info("New destination at %(distance).2f meters: %(name)s", self.destination) self.no_log_until = now + 60 if self.destination["s2_cell_id"] != self.search_cell_id: self.search_points = self.get_search_points(self.destination["s2_cell_id"]) self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_cell_id = self.destination["s2_cell_id"] self.search_points = self.search_points[1:] + self.search_points[:1] else: if self.no_log_until < now: self.logger.info("There is no nearby pokemon worth hunting down [%s]", ", ".join(p["name"] for p in pokemons)) self.no_log_until = now + 120 self.last_cell_id = None return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.destination = None else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) self.no_log_until = now + 30 return WorkerResult.RUNNING def get_pokeball_count(self): return sum([inventory.items().get(ball.value).count for ball in [Item.ITEM_POKE_BALL, Item.ITEM_GREAT_BALL, Item.ITEM_ULTRA_BALL]]) def get_nearby_pokemons(self): radius = self.config_max_distance pokemons = [p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius] for pokemon in pokemons: pokemon["distance"] = self.get_distance(self.bot.position, p) pokemon["name"] = inventory.pokemons().name_for(pokemon["pokemon_id"]) pokemons.sort(key=lambda p: p["distance"]) return pokemons def get_worth_pokemons(self, pokemons): if self.config_hunt_all: worth_pokemons = pokemons else: worth_pokemons = [] if self.config_hunt_vip: worth_pokemons += [p for p in pokemons if p["name"] in self.bot.config.vips] if self.config_hunt_pokedex: worth_pokemons += [p for p in pokemons if (p not in worth_pokemons) and any(not inventory.pokedex().seen(fid) for fid in self.get_family_ids(p))] worth_pokemons.sort(key=lambda p: inventory.candies().get(p["pokemon_id"]).quantity) return worth_pokemons def get_family_ids(self, pokemon): family_id = inventory.pokemons().data_for(pokemon["pokemon_id"]).first_evolution_id ids = [family_id] ids += inventory.pokemons().data_for(family_id).next_evolutions_all[:] return ids def get_distance(self, location, pokemon): return great_circle(location, (pokemon["latitude"], pokemon["longitude"])).meters def get_search_points(self, cell_id): points = [] # For cell level 15 for c in Cell(CellId(cell_id)).subdivide(): for cc in c.subdivide(): latlng = LatLng.from_point(cc.get_center()) point = (latlng.lat().degrees, latlng.lng().degrees) points.append(point) points[0], points[1] = points[1], points[0] points[14], points[15] = points[15], points[14] point = points.pop(2) points.insert(7, point) point = points.pop(13) points.insert(8, point) closest = min(points, key=lambda p: great_circle(self.bot.position, p).meters) index = points.index(closest) return points[index:] + points[:index]
class PokemonHunter(BaseTask): SUPPORTED_TASK_API_VERSION = 1 def __init__(self, bot, config): super(PokemonHunter, self).__init__(bot, config) def initialize(self): self.notified_second_gen = [] self.destination = None self.walker = None self.search_cell_id = None self.search_points = [] self.lost_counter = 0 self.no_log_until = 0 self.distance_to_target = 0 self.distance_counter = 0 self.recent_tries = [] self.no_hunt_until = None self.hunt_started_at = None self.config_max_distance = self.config.get("max_distance", 2000) self.config_hunt_all = self.config.get("hunt_all", False) self.config_hunt_vip = self.config.get("hunt_vip", True) self.config_hunt_pokedex = self.config.get("hunt_pokedex", True) # Lock on Target; ignore all other Pokémon until we found our target. self.config_lock_on_target = self.config.get("lock_on_target", False) # Lock only VIP Pokemon (unseen / VIP) self.config_lock_vip_only = self.config.get("lock_vip_only", True) # If we are camping forts, disable hunting (see CampFort) self.config_disabled_while_camping = self.config.get( "disabled_while_camping", True) # Hunt unseens as VIP? self.config_treat_unseen_as_vip = self.config.get( "treat_unseen_as_vip", True) self.bot.hunter_locked_target = None def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.config_disabled_while_camping and hasattr( self.bot, 'camping_forts') and self.bot.camping_forts: return WorkerResult.SUCCESS if not self.config_lock_on_target: self.bot.hunter_locked_target = None if self.no_hunt_until != None and self.no_hunt_until > time.time(): # No hunting now, cooling down return WorkerResult.SUCCESS else: # Resume hunting self.no_hunt_until = None if self.bot.catch_disabled: if not hasattr(self.bot,"hunter_disabled_global_warning") or \ (hasattr(self.bot,"hunter_disabled_global_warning") and not self.bot.hunter_disabled_global_warning): self.logger.info( "All catching tasks are currently disabled until {}. Pokemon Hunter will resume when catching tasks are re-enabled" .format(self.bot.catch_resume_at.strftime("%H:%M:%S"))) self.bot.hunter_disabled_global_warning = True return WorkerResult.SUCCESS else: self.bot.hunter_disabled_global_warning = False if self.bot.softban: if not hasattr(self.bot, "softban_global_warning") or \ (hasattr(self.bot, "softban_global_warning") and not self.bot.softban_global_warning): self.logger.info( "Possible softban! Not trying to catch Pokemon.") self.bot.softban_global_warning = True return WorkerResult.SUCCESS else: self.bot.softban_global_warning = False if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None return WorkerResult.SUCCESS if self.destination is not None: if self.destination_caught(): self.logger.info( "We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS now = time.time() pokemons = self.get_nearby_pokemons() pokemons = filter(lambda x: x["pokemon_id"] not in self.recent_tries, pokemons) if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons) if len(worth_pokemons) > 0: # Pick a random target from the list random.shuffle(worth_pokemons) # Prevents the bot from looping the same Pokemon self.destination = worth_pokemons[0] self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info( "New destination at %(distance).2f meters: %(name)s", self.destination) if self._is_vip_pokemon(self.destination): self.logger.info("This is a VIP Pokemon! Starting hunt.") if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination elif self._is_needed_pokedex(self.destination): self.logger.info( "I need a %(name)s to complete the Pokedex! I have %(candies)s candies.", self.destination) if self.config_lock_on_target and not self.config_lock_vip_only: self.bot.hunter_locked_target = self.destination else: self.bot.hunter_locked_target = None self.no_log_until = now + 60 if self.destination["s2_cell_id"] != self.search_cell_id: self.search_points = self.get_search_points( self.destination["s2_cell_id"]) self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_cell_id = self.destination["s2_cell_id"] self.search_points = self.search_points[ 1:] + self.search_points[:1] else: if self.no_log_until < now: # Show like "Pidgey (12), Zubat(2)" names = Counter((p["name"] for p in pokemons)) sorted(names) # unicode object, no lower? , key=str.lower) self.logger.info( "There is no nearby pokemon worth hunting down [%s]", ", ".join('{}({})'.format(key, val) for key, val in names.items())) self.no_log_until = now + 120 self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Will look again around {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) self.last_cell_id = None return WorkerResult.SUCCESS if self.config_lock_on_target and not self.config_lock_vip_only: if self.bot.hunter_locked_target == None: self.logger.info( "We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.logger.info("I haven't found %(name)s", self.destination) self.bot.hunter_locked_target = None self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[ 1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle( self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters if round(distance, 2) == self.distance_to_target: # Hmm, not moved toward the Pokemon? self.distance_counter += 1 else: self.distance_counter = 0 if self.distance_counter >= 3: # Ignore last 3 if len(self.recent_tries) > 3: self.recent_tries.pop() self.recent_tries.append(self.destination['pokemon_id']) self.logger.info( "I cant move toward %(name)s! Aborting search.", self.destination) self.bot.hunter_locked_target = None self.destination = None wait = uniform(120, 600) self.no_hunt_until = now + wait self.logger.info("Hunting on cooldown until {}.".format( (datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.ERROR else: self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) # record the new distance... self.distance_to_target = round(distance, 2) if self.config_lock_on_target and not self.config_lock_vip_only: # Just to ensure we stay on target self.bot.hunter_locked_target = self.destination self.no_log_until = now + 30 return WorkerResult.RUNNING def get_pokeball_count(self): return sum([ inventory.items().get(ball.value).count for ball in [Item.ITEM_POKE_BALL, Item.ITEM_GREAT_BALL, Item.ITEM_ULTRA_BALL] ]) def get_nearby_pokemons(self): radius = self.config_max_distance pokemons = [ p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius ] for pokemon in pokemons: pokemon["distance"] = self.get_distance(self.bot.position, p) pokemon["name"] = inventory.pokemons().name_for( pokemon["pokemon_id"]) pokemon["candies"] = inventory.candies().get( pokemon["pokemon_id"]).quantity pokemons.sort(key=lambda p: p["distance"]) return pokemons def _is_vip_pokemon(self, pokemon): # having just a name present in the list makes them vip # Not seen pokemons also will become vip if it's not disabled in config if self.bot.config.vips.get(pokemon["name"]) == {} or ( self.config_treat_unseen_as_vip and not inventory.pokedex().seen(pokemon["pokemon_id"])): return True def _is_needed_pokedex(self, pokemon): candies = inventory.candies().get(pokemon["pokemon_id"]).quantity if candies > 150: # We have enough candies, pass on hunting this Pokemon return False # get family ids, gets ALL ids, also for previous evo! # We could see a Ivysaur on the map, and need a Bulbasaur # Then we have no need for a Ivysaur. If we see a Bulbasaur and need # a Ivysaur, then we DO need this pokemon. got_current_evo = False ids = [] for fid in self.get_family_ids(pokemon): if got_current_evo: ids += [fid] else: if fid == pokemon["pokemon_id"]: ids += [fid] got_current_evo = True # Check if we need this, or a next EVO in the Pokedex if any(not inventory.pokedex().seen(fid) for fid in ids): return True def get_worth_pokemons(self, pokemons): if self.config_hunt_all: worth_pokemons = pokemons else: worth_pokemons = [] if self.config_hunt_vip: worth_pokemons += [ p for p in pokemons if p["name"] in self.bot.config.vips ] if self.config_hunt_pokedex: worth_pokemons += [ p for p in pokemons if (p not in worth_pokemons) and self._is_needed_pokedex(p) ] worth_pokemons.sort( key=lambda p: inventory.candies().get(p["pokemon_id"]).quantity) return worth_pokemons def get_family_ids(self, pokemon): family_id = inventory.pokemons().data_for( pokemon["pokemon_id"]).first_evolution_id ids = [family_id] ids += inventory.pokemons().data_for(family_id).next_evolutions_all[:] return ids def get_distance(self, location, pokemon): return great_circle(location, (pokemon["latitude"], pokemon["longitude"])).meters def get_search_points(self, cell_id): points = [] # For cell level 15 for c in Cell(CellId(cell_id)).subdivide(): for cc in c.subdivide(): latlng = LatLng.from_point(cc.get_center()) point = (latlng.lat().degrees, latlng.lng().degrees) points.append(point) points[0], points[1] = points[1], points[0] points[14], points[15] = points[15], points[14] point = points.pop(2) points.insert(7, point) point = points.pop(13) points.insert(8, point) closest = min(points, key=lambda p: great_circle(self.bot.position, p).meters) index = points.index(closest) return points[index:] + points[:index] def destination_caught(self): # self.logger.info("Searching for a {} since {}".format(self.destination["name"], self.hunt_started_at.strftime("%Y-%m-%d %H:%M:%S"))) with self.bot.database as conn: c = conn.cursor() c.execute( "SELECT COUNT(pokemon) FROM catch_log where pokemon = '{}' and datetime(dated, 'localtime') > Datetime('{}')" .format(self.destination["name"], self.hunt_started_at.strftime("%Y-%m-%d %H:%M:%S"))) # Now check if there is 1 or more caught amount = c.fetchone()[0] caught = amount > 0 if caught: self.logger.info("We caught {} {}(s) since {}".format( amount, self.destination["name"], self.hunt_started_at.strftime("%Y-%m-%d %H:%M:%S"))) return caught
def work(self): forts = self.bot.get_forts() log_lure_avail_str = '' log_lured_str = '' if self.lured: lured_forts = [x for x in forts if 'active_fort_modifier' in x] if len(lured_forts) > 0: log_lured_str = 'lured ' self.dest = find_biggest_cluster(self.radius, lured_forts, '9QM=') else: log_lure_avail_str = 'No lured pokestops in vicinity. Search for normal ones instead. ' self.dest = find_biggest_cluster(self.radius, forts) else: self.dest = find_biggest_cluster(self.radius, forts) if self.dest is not None: lat = self.dest['latitude'] lng = self.dest['longitude'] cnt = self.dest['num_points'] if not self.is_at_destination: msg = log_lure_avail_str + ( "Move to cluster: {num_points} {forts} " "pokestops will be in range of {radius}. Walking {distance}m." ) self.emit_event('found_cluster', formatted=msg, data={ 'num_points': cnt, 'forts': log_lured_str, 'radius': str(self.radius), 'distance': str( round( distance(self.bot.position[0], self.bot.position[1], lat, lng), 2)) }) self.announced = False step_walker = StepWalker(self.bot, lat, lng) self.is_at_destination = False if step_walker.step(): self.is_at_destination = True elif not self.announced: self.emit_event( 'arrived_at_cluster', formatted= "Arrived at cluster. {num_points} {forts} pokestops are in a range of {radius}m radius.", data={ 'num_points': cnt, 'forts': log_lured_str, 'radius': self.radius }) self.announced = True else: lat = self.bot.position[0] lng = self.bot.position[1] return [lat, lng]
def work(self): forts = self.bot.get_forts() log_lure_avail_str = '' log_lured_str = '' if self.lured: lured_forts = [x for x in forts if 'active_fort_modifier' in x] if len(lured_forts) > 0: log_lured_str = 'lured ' self.dest = find_biggest_cluster(self.radius, lured_forts, '9QM=') else: log_lure_avail_str = 'No lured pokestops in vicinity. Search for normal ones instead. ' self.dest = find_biggest_cluster(self.radius, forts) else: self.dest = find_biggest_cluster(self.radius, forts) if self.dest is not None: lat = self.dest['latitude'] lng = self.dest['longitude'] cnt = self.dest['num_points'] if not self.is_at_destination: msg = log_lure_avail_str + ( "Move to cluster: {num_points} {forts} " "pokestops will be in range of {radius}. Walking {distance}m." ) self.emit_event( 'found_cluster', formatted=msg, data={ 'num_points': cnt, 'forts': log_lured_str, 'radius': str(self.radius), 'distance': str(round(distance(self.bot.position[0], self.bot.position[1], lat, lng), 2)) } ) self.announced = False if self.bot.config.walk_max > 0: step_walker = StepWalker( self.bot, lat, lng ) self.is_at_destination = False if step_walker.step(): self.is_at_destination = True else: alt = uniform(self.bot.config.alt_min, self.bot.config.alt_max) self.bot.api.set_position(lat, lng, alt) elif not self.announced: self.emit_event( 'arrived_at_cluster', formatted="Arrived at cluster. {num_points} {forts} pokestops are in a range of {radius}m radius.", data={ 'num_points': cnt, 'forts': log_lured_str, 'radius': self.radius } ) self.announced = True else: lat = self.bot.position[0] lng = self.bot.position[1] return [lat, lng]
def work(self): last_lat = self.bot.api._position_lat last_lng = self.bot.api._position_lng last_alt = self.bot.api._position_alt point = self.points[self.ptr] lat = float(point['lat']) lng = float(point['lng']) alt = uniform(self.bot.config.alt_min, self.bot.config.alt_max) if 'alt' in point: alt = float(point['alt']) if self.bot.config.walk_max > 0: step_walker = StepWalker( self.bot, lat, lng ) is_at_destination = False if step_walker.step(): is_at_destination = True else: self.bot.api.set_position(lat, lng, alt) dist = distance( last_lat, last_lng, lat, lng ) self.emit_event( 'position_update', formatted="Walking from {last_position} to {current_position}, distance left: ({distance} {distance_unit}) ..", data={ 'last_position': (last_lat, last_lng, last_alt), 'current_position': (lat, lng, alt), 'distance': dist, 'distance_unit': 'm' } ) if dist <= 1 or (self.bot.config.walk_min > 0 and is_at_destination): if (self.ptr + 1) == len(self.points): self.ptr = 0 if self.path_mode == 'linear': self.points = list(reversed(self.points)) if self.number_lap_max >= 0: self.number_lap+=1 self.emit_event( 'path_lap_update', formatted="number lap : {number_lap} / {number_lap_max}", data={ 'number_lap': str(self.number_lap), 'number_lap_max': str(self.number_lap_max) } ) if self.number_lap >= self.number_lap_max: self.endLaps() else: self.ptr += 1 return [lat, lng]
def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.bot.catch_disabled: # When catching is disabled, drop the target. if self.destination is not None: self.destination = None self.last_cell_id = None if not hasattr(self.bot, "hunter_disabled_global_warning") or \ (hasattr(self.bot, "hunter_disabled_global_warning") and not self.bot.hunter_disabled_global_warning): self.logger.info("All catching tasks are currently disabled until {}. Pokemon Hunter will resume when catching tasks are re-enabled".format(self.bot.catch_resume_at.strftime("%H:%M:%S"))) self.bot.hunter_disabled_global_warning = True return WorkerResult.SUCCESS else: self.bot.hunter_disabled_global_warning = False if self.bot.softban: # At softban, drop target if self.destination is not None: self.destination = None self.last_cell_id = None self.hunting_trash = False if not hasattr(self.bot, "softban_global_warning") or \ (hasattr(self.bot, "softban_global_warning") and not self.bot.softban_global_warning): self.logger.info("Possible softban! Not trying to catch Pokemon.") self.bot.softban_global_warning = True return WorkerResult.SUCCESS else: self.bot.softban_global_warning = False if self.config_disabled_while_camping and hasattr(self.bot, 'camping_forts') and self.bot.camping_forts: return WorkerResult.SUCCESS if not self.config_lock_on_target: self.bot.hunter_locked_target = None if self.no_hunt_until != None and self.no_hunt_until > time.time(): # No hunting now, cooling down return WorkerResult.SUCCESS else: # Resume hunting self.no_hunt_until = None if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None self.hunting_trash = False return WorkerResult.SUCCESS if self.destination is not None: if self.destination_caught(): self.logger.info("We found a %(name)s while hunting.", self.destination) self.recent_tries.append(self.destination['pokemon_id']) self.destination = None self.hunting_trash = False if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS else: self.logger.info("Electing new target....") if self.destination_vanished(): self.logger.info("Darn, target got away!") self.recent_tries.append(self.destination['pokemon_id']) self.destination = None self.hunting_trash = False if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS else: self.logger.info("Electing new target....") now = time.time() pokemons = self.get_nearby_pokemons() pokemons = filter(lambda x: x["pokemon_id"] not in self.recent_tries, pokemons) if self.config_hunt_for_trash and self.hunting_trash is False and (self.destination is None or self._is_vip_pokemon(self.destination) is False ): # Okay, we should hunt for trash if the bag is almost full trash_mons = ["Caterpie", "Weedle", "Pidgey", "Pidgeotto", "Pidgeot", "Kakuna", "Beedrill", "Metapod", "Butterfree"] if self.pokemon_slots_left() <= self.config_trash_hunt_open_slots: if self.no_log_until < now: self.logger.info("Less than %s slots left to fill, starting hunt for trash" % elf.config_trash_hunt_open_slots) for pokemon in pokemons: if pokemon["name"] in trash_mons: self.hunting_trash = True self.destination = pokemon self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("Hunting for trash at %(distance).2f meters: %(name)s", self.destination) self.set_target() # We have a target return WorkerResult.SUCCESS if self.config_hunt_for_trash and self.hunting_trash: if self.pokemon_slots_left() > 20: self.logger.info("No longer trying to fill the bag. Electing new target....") self.hunting_trash = False self.destination = None if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons, self.config_hunt_closest_first) if len(worth_pokemons) > 0: # Pick a random target from the list # random.shuffle(worth_pokemons) # Priotize closer pokemon worth_pokemons.sort(key=lambda p: p["distance"]) # Prevents the bot from looping the same Pokemon self.destination = worth_pokemons[0] self.set_target() self.lost_counter = 0 self.hunt_started_at = datetime.now() self.logger.info("New destination at %(distance).2f meters: %(name)s", self.destination) if self._is_vip_pokemon(self.destination): self.logger.info("This is a VIP Pokemon! Starting hunt.") if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination elif self._is_needed_pokedex(self.destination): self.logger.info("I need a %(name)s to complete the Pokedex! I have %(candies)s candies.", self.destination) if self.config_lock_on_target and not self.config_lock_vip_only: self.bot.hunter_locked_target = self.destination else: self.bot.hunter_locked_target = None self.no_log_until = now + 60 # We have a target return WorkerResult.SUCCESS else: if self.no_log_until < now: # Show like "Pidgey (12), Zubat(2)" names = Counter((p["name"] for p in pokemons)) sorted(names) # unicode object, no lower? , key=str.lower) self.logger.info("There is no nearby pokemon worth hunting down [%s]", ", ".join('{}({})'.format(key, val) for key, val in names.items())) self.no_log_until = now + 120 self.destination = None if self.config_enable_cooldown: wait = uniform(120, 360) self.no_hunt_until = now + wait self.logger.info("Will look again around {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) self.last_cell_id = None return WorkerResult.SUCCESS # Make sure a VIP is treated that way if self.config_lock_on_target and self.destination is not None: if self._is_vip_pokemon(self.destination) and self.bot.hunter_locked_target is None: self.bot.hunter_locked_target = self.destination # Check if there is a VIP around to hunt if (self.destination is not None and self.config_lock_on_target and self.config_lock_vip_only and self.bot.hunter_locked_target is None): worth_pokemons = self.get_worth_pokemons(pokemons) # We have a none VIP target set, check for VIP targets! if len(worth_pokemons) > 0: for pokemon in worth_pokemons: if self._is_vip_pokemon(pokemon): self.hunting_trash = False self.destination = pokemon self.lost_counter = 0 self.hunt_started_at = datetime.now() self.set_target() if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination self.logger.info("Found a VIP Pokemon! Looking for a %(name)s at %(distance).2f.", self.destination) return WorkerResult.SUCCESS pass if self.destination is None: if self.no_log_until < now: self.logger.info("Nothing to hunt.") return WorkerResult.SUCCESS if self.config_lock_on_target and not self.config_lock_vip_only: if self.bot.hunter_locked_target == None: self.logger.info("We found a %(name)s while hunting. Aborting the current search.", self.destination) self.destination = None self.hunting_trash = False if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None self.hunting_trash = False elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.logger.info("I haven't found %(name)s", self.destination) self.bot.hunter_locked_target = None self.destination = None self.hunting_trash = False if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters if round(distance, 2) == self.distance_to_target: # Hmm, not moved toward the Pokemon? self.distance_counter += 1 else: self.distance_counter = 0 if self.distance_counter >= 3: # Ignore last 3 if len(self.recent_tries) > 3: self.recent_tries.pop() self.recent_tries.append(self.destination['pokemon_id']) self.logger.info("I cant move toward %(name)s! Aborting search.", self.destination) self.hunting_trash = False self.bot.hunter_locked_target = None self.destination = None if self.config_enable_cooldown: wait = uniform(120, 600) self.no_hunt_until = time.time() + wait self.logger.info("Hunting on cooldown until {}.".format((datetime.now() + timedelta(seconds=wait)).strftime("%H:%M:%S"))) return WorkerResult.ERROR else: self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) # record the new distance... self.distance_to_target = round(distance, 2) if self.config_lock_on_target and not self.config_lock_vip_only: # Just to ensure we stay on target self.bot.hunter_locked_target = self.destination self.no_log_until = now + 30 return WorkerResult.RUNNING
def work(self): if not self.enabled: return WorkerResult.SUCCESS if self.bot.catch_disabled: if not hasattr(self.bot,"hunter_disabled_global_warning") or \ (hasattr(self.bot,"hunter_disabled_global_warning") and not self.bot.hunter_disabled_global_warning): self.logger.info("All catching tasks are currently disabled until {}. Pokemon Hunter will resume when catching tasks are re-enabled".format(self.bot.catch_resume_at.strftime("%H:%M:%S"))) self.bot.hunter_disabled_global_warning = True return WorkerResult.SUCCESS else: self.bot.hunter_disabled_global_warning = False if self.get_pokeball_count() <= 0: self.destination = None self.last_cell_id = None return WorkerResult.SUCCESS now = time.time() pokemons = self.get_nearby_pokemons() if self.destination is None: worth_pokemons = self.get_worth_pokemons(pokemons) if len(worth_pokemons) > 0: self.destination = worth_pokemons[0] self.lost_counter = 0 self.logger.info("New destination at %(distance).2f meters: %(name)s", self.destination) self.no_log_until = now + 60 if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination if self.destination["s2_cell_id"] != self.search_cell_id: self.search_points = self.get_search_points(self.destination["s2_cell_id"]) self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_cell_id = self.destination["s2_cell_id"] self.search_points = self.search_points[1:] + self.search_points[:1] else: if self.no_log_until < now: self.logger.info("There is no nearby pokemon worth hunting down [%s]", ", ".join(p["name"] for p in pokemons)) self.no_log_until = now + 120 self.last_cell_id = None return WorkerResult.SUCCESS if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]): self.destination = None elif self.walker.step(): if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons): self.lost_counter += 1 else: self.lost_counter = 0 if self.lost_counter >= 3: self.logger.info("I haven't found %(name)s", self.destination) self.bot.hunter_locked_target = None self.destination = None else: self.logger.info("Now searching for %(name)s", self.destination) self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1]) self.search_points = self.search_points[1:] + self.search_points[:1] elif self.no_log_until < now: distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"]) if self.config_lock_on_target: self.bot.hunter_locked_target = self.destination self.no_log_until = now + 30 return WorkerResult.RUNNING