diff --git a/.gitignore b/.gitignore index cfba4942e0..3c504a3774 100644 --- a/.gitignore +++ b/.gitignore @@ -101,6 +101,7 @@ share/ # PyCharm IDE settings .idea/ *.iml +out/ # Personal load details src/ diff --git a/pokemongo_bot/cell_workers/move_to_fort.py b/pokemongo_bot/cell_workers/move_to_fort.py index 2be287e86c..4d0ff4896f 100644 --- a/pokemongo_bot/cell_workers/move_to_fort.py +++ b/pokemongo_bot/cell_workers/move_to_fort.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +from pokemongo_bot import inventory from pokemongo_bot.constants import Constants from pokemongo_bot.step_walker import StepWalker from pokemongo_bot.worker_result import WorkerResult @@ -18,7 +19,7 @@ def initialize(self): self.ignore_item_count = self.config.get("ignore_item_count", False) def should_run(self): - has_space_for_loot = self.bot.has_space_for_loot() + has_space_for_loot = inventory.Items.has_space_for_loot() if not has_space_for_loot and not self.ignore_item_count: self.emit_event( 'inventory_full', diff --git a/pokemongo_bot/cell_workers/recycle_items.py b/pokemongo_bot/cell_workers/recycle_items.py index 9fa2518e35..e48dff3cd8 100644 --- a/pokemongo_bot/cell_workers/recycle_items.py +++ b/pokemongo_bot/cell_workers/recycle_items.py @@ -67,7 +67,7 @@ def should_run(self): :return: True if the recycling process should be run; otherwise, False. :rtype: bool """ - if inventory.items().get_space_left() < (DEFAULT_MIN_EMPTY_SPACE if self.min_empty_space is None else self.min_empty_space): + if inventory.Items.get_space_left() < (DEFAULT_MIN_EMPTY_SPACE if self.min_empty_space is None else self.min_empty_space): return True return False diff --git a/pokemongo_bot/cell_workers/spin_fort.py b/pokemongo_bot/cell_workers/spin_fort.py index 0ba09ca633..eee88525c5 100644 --- a/pokemongo_bot/cell_workers/spin_fort.py +++ b/pokemongo_bot/cell_workers/spin_fort.py @@ -6,6 +6,7 @@ import time from pgoapi.utilities import f2i +from pokemongo_bot import inventory from pokemongo_bot.constants import Constants from pokemongo_bot.human_behaviour import sleep @@ -14,6 +15,11 @@ from pokemongo_bot.base_dir import _base_dir from utils import distance, format_time, fort_details +SPIN_REQUEST_RESULT_SUCCESS = 1 +SPIN_REQUEST_RESULT_OUT_OF_RANGE = 2 +SPIN_REQUEST_RESULT_IN_COOLDOWN_PERIOD = 3 +SPIN_REQUEST_RESULT_INVENTORY_FULL = 4 + class SpinFort(BaseTask): SUPPORTED_TASK_API_VERSION = 1 @@ -22,12 +28,13 @@ def initialize(self): self.ignore_item_count = self.config.get("ignore_item_count", False) def should_run(self): - if not self.bot.has_space_for_loot() and not self.ignore_item_count: + has_space_for_loot = inventory.Items.has_space_for_loot() + if not has_space_for_loot and not self.ignore_item_count: self.emit_event( 'inventory_full', formatted="Inventory is full. You might want to change your config to recycle more items if this message appears consistently." ) - return self.ignore_item_count or self.bot.has_space_for_loot() + return self.ignore_item_count or has_space_for_loot def work(self): forts = self.get_forts_in_range() @@ -50,25 +57,16 @@ def work(self): player_latitude=f2i(self.bot.position[0]), player_longitude=f2i(self.bot.position[1]) ) - if 'responses' in response_dict and \ - 'FORT_SEARCH' in response_dict['responses']: + if 'responses' in response_dict and 'FORT_SEARCH' in response_dict['responses']: spin_details = response_dict['responses']['FORT_SEARCH'] spin_result = spin_details.get('result', -1) - if spin_result == 1: + if spin_result == SPIN_REQUEST_RESULT_SUCCESS: self.bot.softban = False experience_awarded = spin_details.get('experience_awarded', 0) - items_awarded = spin_details.get('items_awarded', {}) - if items_awarded: - self.bot.latest_inventory = None - tmp_count_items = {} - for item in items_awarded: - item_id = item['item_id'] - item_name = self.bot.item_list[str(item_id)] - if not item_name in tmp_count_items: - tmp_count_items[item_name] = item['item_count'] - else: - tmp_count_items[item_name] += item['item_count'] + + + items_awarded = self.get_items_awarded_from_fort_spinned(response_dict) if experience_awarded or items_awarded: self.emit_event( @@ -77,7 +75,7 @@ def work(self): data={ 'pokestop': fort_name, 'exp': experience_awarded, - 'items': tmp_count_items + 'items': items_awarded } ) else: @@ -90,13 +88,13 @@ def work(self): 'cooldown_complete_timestamp_ms') self.bot.fort_timeouts.update({fort["id"]: pokestop_cooldown}) self.bot.recent_forts = self.bot.recent_forts[1:] + [fort['id']] - elif spin_result == 2: + elif spin_result == SPIN_REQUEST_RESULT_OUT_OF_RANGE: self.emit_event( 'pokestop_out_of_range', formatted="Pokestop {pokestop} out of range.", data={'pokestop': fort_name} ) - elif spin_result == 3: + elif spin_result == SPIN_REQUEST_RESULT_IN_COOLDOWN_PERIOD: pokestop_cooldown = spin_details.get( 'cooldown_complete_timestamp_ms') if pokestop_cooldown: @@ -110,7 +108,7 @@ def work(self): formatted="Pokestop {pokestop} on cooldown. Time left: {minutes_left}.", data={'pokestop': fort_name, 'minutes_left': minutes_left} ) - elif spin_result == 4: + elif spin_result == SPIN_REQUEST_RESULT_INVENTORY_FULL: if not self.ignore_item_count: self.emit_event( 'inventory_full', @@ -165,3 +163,27 @@ def get_forts_in_range(self): ) <= Constants.MAX_DISTANCE_FORT_IS_REACHABLE, forts) return forts + + def get_items_awarded_from_fort_spinned(self, response_dict): + items_awarded = response_dict['responses']['FORT_SEARCH'].get('items_awarded', {}) + if items_awarded: + tmp_count_items = {} + for item_awarded in items_awarded: + + item_awarded_id = item_awarded['item_id'] + item_awarded_name = inventory.Items.name_for(item_awarded_id) + item_awarded_count = item_awarded['item_count'] + + if not item_awarded_name in tmp_count_items: + tmp_count_items[item_awarded_name] = item_awarded_count + else: + tmp_count_items[item_awarded_name] += item_awarded_count + + self._update_inventory(item_awarded) + + return tmp_count_items + + # TODO : Refactor this class, hide the inventory update right after the api call + def _update_inventory(self, item_awarded): + inventory.items().get(item_awarded['item_id']).add(item_awarded['item_count']) + diff --git a/pokemongo_bot/inventory.py b/pokemongo_bot/inventory.py index f314687a13..ccac6f43be 100644 --- a/pokemongo_bot/inventory.py +++ b/pokemongo_bot/inventory.py @@ -106,6 +106,25 @@ def captured(self, pokemon_id): return False return self._data[pokemon_id]['times_captured'] > 0 +class Item(object): + def __init__(self, item_id, item_count): + self.id = item_id + self.name = Items.name_for(self.id) + self.count = item_count + + def remove(self, amount): + if self.count < amount: + raise Exception('Tried to remove more {} than you have'.format(self.name)) + self.count -= amount + + def add(self, amount): + if amount < 0: + raise Exception('Must add positive amount of {}'.format(self.name)) + self.count += amount + + def __str__(self): + return self.name + " : " + str(self.count) + class Items(_BaseInventoryComponent): TYPE = 'item' @@ -140,11 +159,23 @@ def get_space_used(cls): def get_space_left(cls): """ Compute the space left in item inventory. - :return: The space left in item inventory. + :return: The space left in item inventory. 0 if the player has more item than his item inventory can carry. :rtype: int """ _inventory.retrieve_item_inventory_size() - return _inventory.item_inventory_size - cls.get_space_used() + space_left = _inventory.item_inventory_size - cls.get_space_used() + # Space left should never be negative. Returning 0 if the computed value is negative. + return space_left if space_left >= 0 else 0 + + @classmethod + def has_space_for_loot(cls): + """ + Returns a value indicating whether or not the item inventory has enough space to loot a fort + :return: True if the item inventory has enough space; otherwise, False. + :rtype: bool + """ + max_number_of_items_looted_at_stop = 5 + return cls.get_space_left() >= max_number_of_items_looted_at_stop class Pokemons(_BaseInventoryComponent): @@ -479,23 +510,6 @@ def add(self, amount): self.quantity += amount -class Item(object): - def __init__(self, item_id, item_count): - self.id = item_id - self.name = Items.name_for(self.id) - self.count = item_count - - def remove(self, amount): - if self.count < amount: - raise Exception('Tried to remove more {} than you have'.format(self.name)) - self.count -= amount - - def add(self, amount): - if amount < 0: - raise Exception('Must add positive amount of {}'.format(self.name)) - self.count += amount - - class Egg(object): def __init__(self, data): self._data = data @@ -1004,6 +1018,7 @@ def refresh(self): user_web_inventory = os.path.join(_base_dir, 'web', 'inventory-%s.json' % (self.bot.config.username)) with open(user_web_inventory, 'w') as outfile: json.dump(inventory, outfile) + def retrieve_item_inventory_size(self): """ Retrieves the item inventory size @@ -1087,12 +1102,10 @@ def init_inventory(bot): def refresh_inventory(): _inventory.refresh() - def get_item_inventory_size(): _inventory.retrieve_item_inventory_size() return _inventory.item_inventory_size - def pokedex(): return _inventory.pokedex @@ -1110,6 +1123,11 @@ def pokemons(refresh=False): def items(): + """ + Access to the cached item inventory + :return: Instance of the cached item inventory + :rtype: Items + """ return _inventory.items