From fb220e7fe966007031e12406bafc987770c38b32 Mon Sep 17 00:00:00 2001 From: net8q Date: Wed, 17 Aug 2016 21:26:20 +0200 Subject: [PATCH] Check for tutorial completion * Use empty default username for nickname On gmail accounts, it would be suspect to have @gmail.com in nickname Nickname is not set if user does not set one in config * Fix typo * Fix result key name * Moved to own task * Add example in config * Rebased to latest dev on top of : Fixing live stats crash on first run (#4088) in order for the bot to reach the task without crashing * damn thos DOS line endings * fix json --- configs/config.json.cluster.example | 10 +- configs/config.json.example | 390 +++++++++--------- configs/config.json.map.example | 10 +- configs/config.json.optimizer.example | 10 +- configs/config.json.path.example | 10 +- configs/config.json.pokemon.example | 10 +- pokemongo_bot/cell_workers/__init__.py | 1 + .../cell_workers/complete_tutorial.py | 136 ++++++ 8 files changed, 381 insertions(+), 196 deletions(-) create mode 100644 pokemongo_bot/cell_workers/complete_tutorial.py diff --git a/configs/config.json.cluster.example b/configs/config.json.cluster.example index ae3c3ad857..7bec9873cc 100644 --- a/configs/config.json.cluster.example +++ b/configs/config.json.cluster.example @@ -22,7 +22,15 @@ } }, { - "type": "CollectLevelUpReward" + "type": "CompleteTutorial", + "config": { + "enabled": false, + "// set a name": "", + "nickname": "" + } + }, + { + "type": "CollectLevelUpReward" }, { "type": "IncubateEggs", diff --git a/configs/config.json.example b/configs/config.json.example index 3e51a45b4a..55d99e85cf 100644 --- a/configs/config.json.example +++ b/configs/config.json.example @@ -1,191 +1,199 @@ -{ - "auth_service": "google", - "username": "YOUR_USERNAME", - "password": "YOUR_PASSWORD", - "location": "SOME_LOCATION", - "gmapkey": "GOOGLE_MAPS_API_KEY", - "encrypt_location": "", - "websocket_server": false, - "heartbeat_threshold": 10, - "tasks": [ - { - "type": "HandleSoftBan" - }, - { - "type": "SleepSchedule", - "config": { - "enabled": false, - "time": "22:54", - "duration":"7:46", - "time_random_offset": "00:24", - "duration_random_offset": "00:43" - } - }, - { - "type": "CollectLevelUpReward" - }, - { - "type": "IncubateEggs", - "config": { - "longer_eggs_first": true - } - }, - { - "type": "UpdateLiveStats", - "config": { - "enabled": false, - "min_interval": 10, - "stats": ["username", "uptime", "stardust_earned", "xp_earned", "xp_per_hour", "stops_visited"], - "terminal_log": true, - "terminal_title": true - } - }, - { - "type": "TransferPokemon", - "config": { - "transfer_wait_min": 1, - "transfer_wait_max": 4 - } - }, - { - "type": "NicknamePokemon", - "config": { - "enabled": false, - "nickname_template": "{iv_pct}_{iv_ads}" - } - }, - { - "type": "EvolvePokemon", - "config": { - "evolve_all": "none", - "first_evolve_by": "cp", - "evolve_above_cp": 500, - "evolve_above_iv": 0.8, - "logic": "or", - "evolve_speed": 20, - "use_lucky_egg": false - } - }, - { - "type": "RecycleItems", - "config": { - "min_empty_space": 15, - "max_balls_keep": 150, - "max_potions_keep": 50, - "max_berries_keep": 70, - "max_revives_keep": 70, - "item_filter": { - "Pokeball": { "keep" : 100 }, - "Potion": { "keep" : 10 }, - "Super Potion": { "keep" : 20 }, - "Hyper Potion": { "keep" : 30 }, - "Revive": { "keep" : 30 }, - "Razz Berry": { "keep" : 100 } - }, - "recycle_wait_min": 1, - "recycle_wait_max": 4 - } - }, - { - "type": "CatchPokemon", - "config": { - "catch_visible_pokemon": true, - "catch_lured_pokemon": true, - "min_ultraball_to_keep": 5, - "catch_throw_parameters": { - "excellent_rate": 0.1, - "great_rate": 0.5, - "nice_rate": 0.3, - "normal_rate": 0.1, - "spin_success_rate" : 0.6 - }, - "catch_simulation": { - "flee_count": 3, - "flee_duration": 2, - "catch_wait_min": 2, - "catch_wait_max": 6, - "berry_wait_min": 2, - "berry_wait_max": 3, - "changeball_wait_min": 2, - "changeball_wait_max": 3 - } - } - }, - { - "type": "SpinFort", - "config": { - "spin_wait_min": 2, - "spin_wait_max": 3 - } - }, - { - "type": "MoveToFort", - "config": { - "lure_attraction": true, - "lure_max_distance": 2000 - } - }, - { - "type": "FollowSpiral", - "config": { - "diameter": 4, - "step_size": 70 - } - } - ], - "map_object_cache_time": 5, - "forts": { - "avoid_circles": true, - "max_circle_size": 50, - "cache_recent_forts": true - }, - "walk_max": 4.16, - "walk_min": 2.16, - "debug": false, - "test": false, - "health_record": true, - "location_cache": true, - "distance_unit": "km", - "reconnecting_timeout": 15, - "logging_color": true, - "catch": { - "any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or"}, - "// Example of always catching Rattata:": {}, - "// Rattata": { "always_catch" : true } - }, - "release": { - "any": {"release_below_cp": 0, "release_below_iv": 0, "logic": "or"}, - "// Example of always releasing Rattata:": {}, - "// Rattata": {"always_release": true}, - "// Example of keeping 3 stronger (based on CP) Pidgey:": {}, - "// Pidgey": {"keep_best_cp": 3}, - "// Example of keeping 2 stronger (based on IV) Zubat:": {}, - "// Zubat": {"keep_best_iv": 2}, - "// Also, it is working with any": {}, - "// any": {"keep_best_iv": 3}, - "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {}, - "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3} - }, - "vips" : { - "Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {}, - "any": {"catch_above_cp": 1200, "catch_above_iv": 0.9, "logic": "or" }, - "Lapras": {}, - "Moltres": {}, - "Zapdos": {}, - "Articuno": {}, - - "// S-Tier pokemons (if pokemon can be evolved into tier, list the representative)": {}, - "Mewtwo": {}, - "Dragonite": {}, - "Snorlax": {}, - "// Mew evolves to Mewtwo": {}, - "Mew": {}, - "Arcanine": {}, - "Vaporeon": {}, - "Gyarados": {}, - "Exeggutor": {}, - "Muk": {}, - "Weezing": {}, - "Flareon": {} - } -} +{ + "auth_service": "google", + "username": "YOUR_USERNAME", + "password": "YOUR_PASSWORD", + "location": "SOME_LOCATION", + "gmapkey": "GOOGLE_MAPS_API_KEY", + "encrypt_location": "", + "websocket_server": false, + "heartbeat_threshold": 10, + "tasks": [ + { + "type": "HandleSoftBan" + }, + { + "type": "SleepSchedule", + "config": { + "enabled": false, + "time": "22:54", + "duration":"7:46", + "time_random_offset": "00:24", + "duration_random_offset": "00:43" + } + }, + { + "type": "CompleteTutorial", + "config": { + "enabled": false, + "// set a name": "", + "nickname": "" + } + }, + { + "type": "CollectLevelUpReward" + }, + { + "type": "IncubateEggs", + "config": { + "longer_eggs_first": true + } + }, + { + "type": "UpdateLiveStats", + "config": { + "enabled": false, + "min_interval": 10, + "stats": ["username", "uptime", "stardust_earned", "xp_earned", "xp_per_hour", "stops_visited"], + "terminal_log": true, + "terminal_title": true + } + }, + { + "type": "TransferPokemon", + "config": { + "transfer_wait_min": 1, + "transfer_wait_max": 4 + } + }, + { + "type": "NicknamePokemon", + "config": { + "enabled": false, + "nickname_template": "{iv_pct}_{iv_ads}" + } + }, + { + "type": "EvolvePokemon", + "config": { + "evolve_all": "none", + "first_evolve_by": "cp", + "evolve_above_cp": 500, + "evolve_above_iv": 0.8, + "logic": "or", + "evolve_speed": 20, + "use_lucky_egg": false + } + }, + { + "type": "RecycleItems", + "config": { + "min_empty_space": 15, + "max_balls_keep": 150, + "max_potions_keep": 50, + "max_berries_keep": 70, + "max_revives_keep": 70, + "item_filter": { + "Pokeball": { "keep" : 100 }, + "Potion": { "keep" : 10 }, + "Super Potion": { "keep" : 20 }, + "Hyper Potion": { "keep" : 30 }, + "Revive": { "keep" : 30 }, + "Razz Berry": { "keep" : 100 } + }, + "recycle_wait_min": 1, + "recycle_wait_max": 4 + } + }, + { + "type": "CatchPokemon", + "config": { + "catch_visible_pokemon": true, + "catch_lured_pokemon": true, + "min_ultraball_to_keep": 5, + "catch_throw_parameters": { + "excellent_rate": 0.1, + "great_rate": 0.5, + "nice_rate": 0.3, + "normal_rate": 0.1, + "spin_success_rate" : 0.6 + }, + "catch_simulation": { + "flee_count": 3, + "flee_duration": 2, + "catch_wait_min": 2, + "catch_wait_max": 6, + "berry_wait_min": 2, + "berry_wait_max": 3, + "changeball_wait_min": 2, + "changeball_wait_max": 3 + } + } + }, + { + "type": "SpinFort", + "config": { + "spin_wait_min": 2, + "spin_wait_max": 3 + } + }, + { + "type": "MoveToFort", + "config": { + "lure_attraction": true, + "lure_max_distance": 2000 + } + }, + { + "type": "FollowSpiral", + "config": { + "diameter": 4, + "step_size": 70 + } + } + ], + "map_object_cache_time": 5, + "forts": { + "avoid_circles": true, + "max_circle_size": 50, + "cache_recent_forts": true + }, + "walk_max": 4.16, + "walk_min": 2.16, + "debug": false, + "test": false, + "health_record": true, + "location_cache": true, + "distance_unit": "km", + "reconnecting_timeout": 15, + "logging_color": true, + "catch": { + "any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or"}, + "// Example of always catching Rattata:": {}, + "// Rattata": { "always_catch" : true } + }, + "release": { + "any": {"release_below_cp": 0, "release_below_iv": 0, "logic": "or"}, + "// Example of always releasing Rattata:": {}, + "// Rattata": {"always_release": true}, + "// Example of keeping 3 stronger (based on CP) Pidgey:": {}, + "// Pidgey": {"keep_best_cp": 3}, + "// Example of keeping 2 stronger (based on IV) Zubat:": {}, + "// Zubat": {"keep_best_iv": 2}, + "// Also, it is working with any": {}, + "// any": {"keep_best_iv": 3}, + "// Example of keeping the 2 strongest (based on CP) and 3 best (based on IV) Zubat:": {}, + "// Zubat": {"keep_best_cp": 2, "keep_best_iv": 3} + }, + "vips" : { + "Any pokemon put here directly force to use Berry & Best Ball to capture, to secure the capture rate!": {}, + "any": {"catch_above_cp": 1200, "catch_above_iv": 0.9, "logic": "or" }, + "Lapras": {}, + "Moltres": {}, + "Zapdos": {}, + "Articuno": {}, + + "// S-Tier pokemons (if pokemon can be evolved into tier, list the representative)": {}, + "Mewtwo": {}, + "Dragonite": {}, + "Snorlax": {}, + "// Mew evolves to Mewtwo": {}, + "Mew": {}, + "Arcanine": {}, + "Vaporeon": {}, + "Gyarados": {}, + "Exeggutor": {}, + "Muk": {}, + "Weezing": {}, + "Flareon": {} + } +} diff --git a/configs/config.json.map.example b/configs/config.json.map.example index ba0716eefd..74022566a8 100644 --- a/configs/config.json.map.example +++ b/configs/config.json.map.example @@ -22,7 +22,15 @@ } }, { - "type": "CollectLevelUpReward" + "type": "CompleteTutorial", + "config": { + "enabled": false, + "// set a name": "", + "nickname": "" + } + }, + { + "type": "CollectLevelUpReward" }, { "type": "IncubateEggs", diff --git a/configs/config.json.optimizer.example b/configs/config.json.optimizer.example index 1dd826428f..c06719ad27 100644 --- a/configs/config.json.optimizer.example +++ b/configs/config.json.optimizer.example @@ -22,7 +22,15 @@ } }, { - "type": "CollectLevelUpReward" + "type": "CompleteTutorial", + "config": { + "enabled": false, + "// set a name": "", + "nickname": "" + } + }, + { + "type": "CollectLevelUpReward" }, { "type": "IncubateEggs", diff --git a/configs/config.json.path.example b/configs/config.json.path.example index 9f8f10cbde..6593166664 100644 --- a/configs/config.json.path.example +++ b/configs/config.json.path.example @@ -22,7 +22,15 @@ } }, { - "type": "CollectLevelUpReward" + "type": "CompleteTutorial", + "config": { + "enabled": false, + "// set a name": "", + "nickname": "" + } + }, + { + "type": "CollectLevelUpReward" }, { "type": "IncubateEggs", diff --git a/configs/config.json.pokemon.example b/configs/config.json.pokemon.example index 56eaf60b6a..35e44127f7 100644 --- a/configs/config.json.pokemon.example +++ b/configs/config.json.pokemon.example @@ -22,7 +22,15 @@ } }, { - "type": "CollectLevelUpReward" + "type": "CompleteTutorial", + "config": { + "enabled": false, + "// set a name": "", + "nickname": "" + } + }, + { + "type": "CollectLevelUpReward" }, { "type": "IncubateEggs", diff --git a/pokemongo_bot/cell_workers/__init__.py b/pokemongo_bot/cell_workers/__init__.py index 217eebbebf..b8cb0fe0ab 100644 --- a/pokemongo_bot/cell_workers/__init__.py +++ b/pokemongo_bot/cell_workers/__init__.py @@ -20,3 +20,4 @@ from sleep_schedule import SleepSchedule from update_live_stats import UpdateLiveStats from catch_pokemon import CatchPokemon +from complete_tutorial import CompleteTutorial diff --git a/pokemongo_bot/cell_workers/complete_tutorial.py b/pokemongo_bot/cell_workers/complete_tutorial.py new file mode 100644 index 0000000000..1706bb6908 --- /dev/null +++ b/pokemongo_bot/cell_workers/complete_tutorial.py @@ -0,0 +1,136 @@ +import random + +from pokemongo_bot import logger +from pokemongo_bot.base_task import BaseTask +from pokemongo_bot.worker_result import WorkerResult +from pokemongo_bot.human_behaviour import sleep + + + +class CompleteTutorial(BaseTask): + + SUPPORTED_TASK_API_VERSION = 1 + + def initialize(self): + self.api = self.bot.api + self.nickname = self.config.get('nickname','') + self.team = self.config.get('team',0) + + def should_run(self): + return True + + def work(self): + + if not self.should_run(): + return WorkerResult.SUCCESS + + if self._check_tutorial_state(): + return WorkerResult.SUCCESS + else: + return WorkerResult.ERROR + + def _check_tutorial_state(self): + self._player=self.bot.player_data + + tutorial_state = self._player.get('tutorial_state', []) + # LEGAL_SCREEN = 0 + if not 0 in tutorial_state: + sleep(2) + if self._set_tutorial_state(0): + self.logger.info('Completed legal screen') + tutorial_state = self._player.get('tutorial_state', []) + else: + return False + + # AVATAR_SELECTION = 1 + if not 1 in tutorial_state: + # TODO : choose avatar ? + sleep(3) + if self._set_tutorial_state(1): + self.logger.info('Completed avatar selection') + tutorial_state = self._player.get('tutorial_state', []) + else: + return False + + # POKEMON_CAPTURE = 3 + if not 3 in tutorial_state: + sleep(10) + if self._encounter_tutorial(): + self.logger.info('Completed first capture') + else: + self.logger.error('Error during first capture') + return False + + # NAME_SELECTION = 4 + if not 4 in tutorial_state: + if not self.nickname: + self.logger.info("No nickname defined in config") + return False + + self.logger.info(u'Trying to set {} as nickname'.format(self.nickname)) + sleep(5) + if self._set_nickname(self.nickname): + self._set_tutorial_state(4) + tutorial_state = self._player.get('tutorial_state', []) + else: + self.logger.error('Error trying to set nickname') + return False + + # FIRST_TIME_EXPERIENCE_COMPLETE = 7 + if not 7 in tutorial_state: + if self._set_tutorial_state(7): + self.logger.info('Completed first time experience') + else: + return False + + return True + + def _encounter_tutorial(self): + # You just need to call the API with the pokemon you choose + # Probably can't get MewTwo as first pokemon though + first_pokemon_id = random.choice([1, 4, 7]) + response_dict = self.api.encounter_tutorial_complete( + pokemon_id=first_pokemon_id) + try: + if response_dict['responses']['ENCOUNTER_TUTORIAL_COMPLETE']['result'] == 1: + return True + else: + self.logger.error("Error during encouter tutorial") + return False + except KeyError: + self.logger.error("KeyError during encouter tutorial") + return False + + def _set_nickname(self, nickname): + response_dict = self.api.claim_codename(codename=nickname) + try: + result = response_dict['responses']['CLAIM_CODENAME']['status'] + if result == 1: + self.logger.info(u'Name changed to {}'.format(nickname)) + return True + else: + # Would be nice to get the text directly from the proto Enum + error_codes = { + 0: 'UNSET', + 1: 'SUCCESS', + 2: 'CODENAME_NOT_AVAILABLE', + 3: 'CODENAME_NOT_VALID', + 4: 'CURRENT_OWNER', + 5: 'CODENAME_CHANGE_NOT_ALLOWED' + } + self.logger.error( + u'Error while changing nickname : {}'.format(error_codes[result])) + return False + except KeyError: + return False + + def _set_tutorial_state(self, completed): + response_dict = self.api.mark_tutorial_complete(tutorials_completed=[ + completed], send_marketing_emails=False, send_push_notifications=False) + try: + self._player = response_dict['responses'][ + 'MARK_TUTORIAL_COMPLETE']['player_data'] + return response_dict['responses']['MARK_TUTORIAL_COMPLETE']['success'] + except KeyError: + self.logger.error("KeyError while setting tutorial state") + return False