Repository: PokemonGoF/PokemonGo-Bot

Issue:
[dev] Bot loops around min_ball in MovetoMapPokemon task
### Expected Behavior

The bot will only start sniping after it has a minimum number of balls, as defined by `min_ball`.
### Actual Behavior

Bot will start sniping as soon as it has even one pokeball, and is forced to flee because it runs out of balls. 
### Config:

```
{
    "documentation": "https://github.com/PokemonGoF/PokemonGo-Bot/tree/master/docs",

    "auth_service": "google",
    "username": "",
    "password": "",

    "enable_social": true,

    "": "",

    "websocket_server": true,

    "heartbeat_threshold": 10,

    "gmapkey": "",

    "tasks": [{
        "type": "HandleSoftBan"
    }, {
        "type": "SleepSchedule",
        "config": {
            "enabled": true,
            "time": "03:00",
            "duration": "6:00",
            "time_random_offset": "00:31",
            "duration_random_offset": "00:27",
            "wake_up_at_location": ""
        }
    }, {
        "type": "RandomPause",
        "config": {
            "enabled": true,
            "min_duration": "00:00:10",
            "max_duration": "00:01:00",
            "min_interval": "00:05:00",
            "max_interval": "00:15:00"
        }
    }, {
        "type": "RandomPause",
        "config": {
            "enabled": true,
            "min_duration": "00:10:00",
            "max_duration": "00:30:00",
            "min_interval": "00:45:00",
            "max_interval": "02:00:00"
        }
    }, {
        "type": "CompleteTutorial",
        "config": {
            "enabled": true,
            "// set a name": "",
            "// nickname": ""
        }
    }, {
        "type": "CollectLevelUpReward"
    }, {
        "type": "UpdateLiveStats",
        "config": {
            "enabled": true,
            "min_interval": 10,
            "stats": ["uptime", "level", "level_completion", "pokemon_stats", "stardust_earned", "xp_earned", "xp_per_hour", "stops_visited"],
            "terminal_log": true,
            "terminal_title": true
        }
    }, {
        "type": "UpdateLiveInventory",
        "config": {
            "enabled": true,
            "min_interval": 120,
            "show_all_multiple_lines": false,
            "items": ["space_info", "pokeballs", "greatballs", "ultraballs", "razzberries", "luckyegg"]
        }
    }, {
        "type": "IncubateEggs",
        "config": {
            "longer_eggs_first": true,
            "min_interval": 120,
            "infinite": [2, 5, 10],
            "breakable": [2, 10]
        }
    }, {
        "type": "EvolvePokemon",
        "config": {
            "enabled": true,
            "evolve_all": "Pidgey, Weedle, Caterpie, Rattata, Drowzee, Meowth, Spearow, Ekans, Zubat, Doduo, Goldeen, Krabby, Horsea, Koffing, Cubone, Psyduck",
            "first_evolve_by": "iv",
            "evolve_above_cp": 400,
            "evolve_above_iv": 0.9,
            "logic": "or",
            "min_evolve_speed": 20,
            "max_evolve_speed": 35,
            "use_lucky_egg": false
        }
    }, {
        "type": "TransferPokemon",
        "config": {
            "enabled": true,
            "min_free_slot": 10,
            "transfer_wait_min": 3,
            "transfer_wait_max": 5
        }
    }, {
        "type": "NicknamePokemon",
        "config": {
            "enabled": true,
            "locale": "en",
            "dont_nickname_favorite": true,
            "nickname_template": "{ivcp_pct1}{attack_pct1} {name}"
        }
    }, {
        "type": "RecycleItems",
        "config": {
            "min_empty_space": 15,
            "max_balls_keep": 275,
            "max_potions_keep": 0,
            "max_berries_keep": 50,
            "max_revives_keep": 0,
            "item_filter": {
                "Pokeball": {
                    "keep": 100
                },
                "Greatball": {
                    "keep": 75
                },
                "Ultraball": {
                    "keep": 100
                },
                "Potion": {
                    "keep": 0
                },
                "Super Potion": {
                    "keep": 0
                },
                "Hyper Potion": {
                    "keep": 0
                },
                "Revive": {
                    "keep": 0
                },
                "Razz Berry": {
                    "keep": 50
                }
            },
            "recycle_wait_min": 3,
            "recycle_wait_max": 10
        }
    }, {
        "type": "CatchPokemon",
        "config": {
            "catch_visible_pokemon": true,
            "catch_lured_pokemon": true,
            "min_ultraball_to_keep": 50,
            "berry_threshold": 0.35,
            "vip_berry_threshold": 0.9,
            "treat_unseen_as_vip": true,
            "catch_throw_parameters": {
                "excellent_rate": 0.1,
                "great_rate": 0.5,
                "nice_rate": 0.3,
                "normal_rate": 0.1,
                "spin_success_rate": 0.6,
                "hit_rate": 0.75
            },
            "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": "MoveToMapPokemon",
        "config": {
            "address": "http://localhost:5000",
            "max_distance": 1500,
            "min_ball": 50,
            "prioritize_vips": true,
            "snipe": true,
            "snipe_high_prio_only": true,
            "snipe_high_prio_threshold": 399,
            "update_map": true,
            "mode": "priority",
            "map_path": "raw_data",
            "walker": "StepWalker",
            "max_extra_dist_fort": 10,
            "catch": {
                "Mewtwo": 1000,
                "Mew": 1000,

                "Articuno": 1000,
                "Zapdos": 1000,
                "Moltres": 1000,

                "Dratini": 1000,
                "Dragonair": 1000,
                "Dragonite": 1000,

                "Snorlax": 1000,
                "Lapras": 1000,

                "Charmander": 950,
                "Charmeleon": 949,
                "Charizard": 948,

                "Bulbasaur": 930,
                "Ivysaur": 929,
                "Venusaur": 928,

                "Squirtle": 910,
                "Wartortle": 909,
                "Blastoise": 908,

                "Pikachu": 940,
                "Raichu": 939,

                "Eevee": 900,
                "Vaporeon": 500,
                "Jolteon": 500,
                "Flareon": 500,

                "Chansey": 800,

                "Electabuzz": 300,
                "Magmar": 300,
                "Ditto": 300,

                "Porygon": 200,
                "Scyther": 200,
                "Jynx": 200,

                "Seel": 500,
                "Dewgong": 300,

                "Growlithe": 750,
                "Arcanine": 650,

                "Magikarp": 700,
                "Gyarados": 600,

                "Vulpix": 650,
                "Ninetales": 600,

                "Grimer": 650,
                "Muk": 600,

                "Exeggcute": 625,
                "Exeggcutor": 425,

                "Omanyte": 600,
                "Omastar": 500,

                "Kabuto": 600,
                "Kabutops": 500,

                "Slowpoke": 600,
                "Slowbro": 400,

                "Rhyhorn": 550,
                "Rhydon": 450,

                "Nidoran M": 600,
                "Nidorino": 500,
                "Nidoking": 400,

                "Nidoran F": 500,
                "Nidorina": 400,
                "Nidoqueen": 300,

                "Staryu": 500,
                "Starmie": 400,

                "Gastly": 500,
                "Haunter": 400,
                "Gengar": 300,

                "Geodude": 500,
                "Graveler": 400,
                "Golem": 300,

                "Machop": 550,
                "Machoke": 450,
                "Machamp": 350,

                "Abra": 500,
                "Kadabra": 400,
                "Alakazam": 300,

                "Poliwag": 400,
                "Poliwhirl": 300,
                "Poliwrath": 200,

                "Bellsprout": 400,
                "Weepinbell": 300,
                "Victreebel": 200,

                "Oddish": 300,
                "Gloom": 200,
                "Vileplume": 100,

                "Sandshrew": 200,
                "Sandslash": 100,

                "Farfetch'd": 300,
                "Kangaskhan": 300,
                "Mr. Mime": 300,
                "Tauros": 300,

                "Electabuzz": 300,
                "Magmar": 300,
                "Ditto": 300,

                "Porygon": 200,
                "Scyther": 300,
                "Jynx": 200,

                "Seel": 350,
                "Dewgong": 200,

                "Shellder": 200,
                "Cloyster": 100,

                "Drowzee": 10,
                "Hypno": 50,


                "Paras": 100,
                "Parasect": 50,

                "Tentacool": 200,
                "Tentacruel": 100,

                "Mankey": 150,
                "Primeape": 50,

                "Clefairy": 100,
                "Clefable": 50,

                "Jigglypuff": 100,
                "Wigglytuff": 50,

                "Venonat": 100,
                "Venomoth": 50,

                "Diglett": 200,
                "Dugtrio": 150,

                "Meowth": 150,
                "Persian": 100,

                "Psyduck": 150,
                "Golduck": 100,


                "Pinsir": 150,

                "Ponyta": 200,
                "Rapidash": 100,

                "Magnemite": 150,
                "Magneton": 100,

                "Krabby": 150,
                "Kingler": 100,

                "Voltorb": 200,
                "Electrode": 100,

                "Cubone": 250,
                "Marowak": 200,

                "Hitmonlee": 200,
                "Hitmonchan": 200,
                "Lickitung": 200,

                "Koffing": 200,
                "Weezing": 100,

                "Tangela": 100,

                "Horsea": 250,
                "Seadra": 100,

                "Goldeen": 250,
                "Seaking": 100,


                "Caterpie": 10,
                "Metapod": 10,
                "Butterfree": 10,

                "Weedle": 10,
                "Kakuna": 10,
                "Beedrill": 10,

                "Pidgey": 10,
                "Pidgeotto": 10,
                "Pidgeot": 10,

                "Oddish": 100,
                "Gloom": 200,
                "Vileplume": 600,

                "Onix": 10,

                "Rattata": 10,
                "Raticate": 10,

                "Spearow": 10,
                "Fearow": 10,

                "Ekans": 10,
                "Arbok": 10,

                "Sandshrew": 10,
                "Sandslash": 10,

                "Zubat": 10,
                "Golbat": 10,

                "Doduo": 10,
                "Dodrio": 10
            }
        }
    }, {
        "type": "SpinFort",
        "config": {
            "spin_wait_min": 1,
            "spin_wait_max": 3
        }
    }, {
        "type": "FollowPath",
        "config": {
            "enabled": true,
            "walker": "PolylineWalker",
            "path_mode": "loop",
            "path_start_mode": "closest",
            "path_file": "configs/path1.json",
            "number_lap": 10,
            "timer_restart_min": "00:10:00",
            "timer_restart_max": "00:20:00"
        }
    }],
    "map_object_cache_time": 5,
    "forts": {
        "avoid_circles": true,
        "max_circle_size": 50,
        "cache_recent_forts": true
    },
    "logging_color": true,

    "pokemon_bag": {
        "show_at_start": false,
        "show_count": true,
        "pokemon_info": ["cp", "iv_pct", "moveset", "dps"]
    },

    "location_cache": true,
    "distance_unit": "km",

    "walk_max": 11,
    "walk_min": 6,
    "walk_random": true,
    "walk_offset_percent_max": 0.4,

    "alt_min": 70,
    "alt_max": 150,

    "gps_default_altitude": 76.0,
    "replicate_gps_xy_noise": true,
    "replicate_gps_z_noise": true,
    "gps_xy_noise_range": 0.000125,
    "gps_z_noise_range": 12.5,

    "action_wait_min": 2,
    "action_wait_max": 8,

    "debug": false,
    "test": false,
    "health_record": false,

    "daily_catch_limit": 800,

    "reconnecting_timeout": 15,
    "catch": {
        "any": {
            "always_catch": true
        }
    },

    "release": {
        "any": {
            "keep_best_custom": "iv, moveset.attack.perfection, iv_atack, hp_max",
            "amount": 2
        },

        "Snorlax": {
            "keep_best_iv": 9
        },
        "Lapras": {
            "keep_best_iv": 9
        },
        "Gyarados": {
            "keep_best_iv": 9
        },

        "Dratini": {
            "keep_best_custom": "iv, moveset.attack.perfection",
            "amount": 2
        },
        "Dragonair": {
            "keep_best_custom": "iv, moveset.attack.perfection",
            "amount": 2
        },
        "Dragonite": {
            "keep_best_custom": "iv, moveset.attack.perfection",
            "amount": 3
        },

        "Vaporeon": {
            "keep_best_custom": "iv, moveset.attack.perfection",
            "amount": 3
        },
        "Flareon": {
            "keep_best_custom": "iv, moveset.attack.perfection",
            "amount": 3
        },
        "Jolteon": {
            "keep_best_custom": "iv, moveset.attack.perfection",
            "amount": 3
        }

    },
    "vips": {
        "any": {
            "catch_above_cp": 1200,
            "catch_above_iv": 0.9,
            "catch_above_ncp": 0.9,
            "logic": "or"
        },

        "Mew": {},
        "Mewtwo": {},

        "Moltres": {},
        "Zapdos": {},
        "Articuno": {},

        "Dragonite": {},
        "Dragonair": {},
        "Dratini": {},

        "Snorlax": {},
        "Lapras": {},

        "Growlithe": {},
        "Arcanine": {},

        "Gyarados": {},

        "Exeggutor": {},
        "Muk": {},

        "Eevee": {},
        "Vaporeon": {},

        "Bulbasaur": {},
        "Ivysaur": {},
        "Venusaur": {},

        "Charmander": {},
        "Charmeleon": {},
        "Charizard": {},

        "Squirtle": {},
        "Wartortle": {},
        "Blastoise": {},

        "Pikachu": {},
        "Raichu": {}

    }
}
```
### Log

```
# No balls here, so just deferred to FollowPath for a bit

2016-08-24 11:02:42,579 [UpdateLiveStats] [INFO] [log_stats] Uptime : 0:15:35 | Level 22 | 130,515 / 175,000 XP (74%) | Encountered 18 pokemon, 15 caught, 0 released, 0 evolved, 0 never seen before | Earned 1,500 Stardust | +2,925 XP | 11,259 XP/h | Visited 13 stops
2016-08-24 11:02:42,579 [UpdateLiveInventory] [INFO] [show_inventory] Items: 38/350 | Pokeballs: 0 | GreatBalls: 0 | UltraBalls: 0 | RazzBerries: 1 | LuckyEgg: 4
...

# Got 3 pokeballs from a pokestop, and switched back on, despite 3 < 50

2016-08-24 11:04:02,118 [  SpinFort] [INFO] [spun_pokestop] Spun pokestop Toronto Coach Terminal. Experience awarded: 50. Items awarded: {u'Pokeball': 3}
2016-08-24 11:04:04,267 [FollowPath] [INFO] [position_update] Walking from (43.655997233663975, -79.383849318655, 112.34542691743124) to (43.65603, -79.38385, 76.0), distance left: (3.64423389715 m) ..
2016-08-24 11:04:06,208 [UpdateLiveStats] [INFO] [log_stats] Uptime : 0:17:00 | Level 22 | 130,735 / 175,000 XP (74%) | Encountered 19 pokemon, 16 caught, 0 released, 0 evolved, 0 never seen before | Earned 1,600 Stardust | +3,145 XP | 11,102 XP/h | Visited 15 stops
2016-08-24 11:04:07,481 [MoveToMapPokemon] [INFO] [move_to_map_pokemon_teleport_to] Teleporting to Growlithe. (6037.04km)
2016-08-24 11:04:07,481 [MoveToMapPokemon] [INFO] [move_to_map_pokemon_encounter] Encountered Pokemon: Growlithe
2016-08-24 11:04:09,626 [MoveToMapPokemon] [INFO] [move_to_map_pokemon_teleport_back] Teleporting back to previous location (43.656, -79.38384)
2016-08-24 11:04:11,692 [PokemonCatchWorker] [INFO] [pokemon_appeared] A wild Growlithe appeared! [CP 379] [NCP 0.28] [Potential 0.49] [A/D/S 13/1/8]
2016-08-24 11:04:14,695 [PokemonCatchWorker] [INFO] [vip_pokemon] This is a VIP pokemon. Catch!!!
2016-08-24 11:04:17,344 [PokemonCatchWorker] [INFO] [threw_berry] Threw a Razz Berry! Catch rate with Pokeball is now: 40.62
2016-08-24 11:04:22,596 [PokemonCatchWorker] [INFO] [threw_pokeball] Great throw! Used Pokeball, with chance 40.62 (2 left)
2016-08-24 11:04:22,770 [PokemonCatchWorker] [INFO] [pokemon_caught] Captured Growlithe! [CP 379] [NCP 0.28] [Potential 0.49] [13/1/8] [+150 exp]
2016-08-24 11:04:22,775 [PokemonCatchWorker] [INFO] [gained_candy] You now have 12 Growlithe candy!
2016-08-24 11:04:28,242 [FollowPath] [INFO] [position_update] Walking from (43.65592416029464, -79.38381279395433, 144.68777536823313) to (43.65608, -79.38387, 76.0), distance left: (17.9292754186 m) ..
2016-08-24 11:04:30,660 [UpdateLiveStats] [INFO] [log_stats] Uptime : 0:17:23 | Level 22 | 130,885 / 175,000 XP (74%) | Encountered 20 pokemon, 17 caught, 0 released, 0 evolved, 0 never seen before | Earned 1,700 Stardust | +3,295 XP | 11,373 XP/h | Visited 15 stops
2016-08-24 11:04:32,920 [NicknamePokemon] [INFO] [rename_pokemon] Pokemon Growlithe renamed to 57 Growlithe
2016-08-24 11:04:33,384 [MoveToMapPokemon] [INFO] [move_to_map_pokemon_teleport_to] Teleporting to Magikarp. (6637.52km)
2016-08-24 11:04:33,385 [MoveToMapPokemon] [INFO] [move_to_map_pokemon_encounter] Encountered Pokemon: Magikarp
2016-08-24 11:04:35,866 [MoveToMapPokemon] [INFO] [move_to_map_pokemon_teleport_back] Teleporting back to previous location (43.656, -79.38384)
2016-08-24 11:04:37,869 [PokemonCatchWorker] [INFO] [pokemon_appeared] A wild Magikarp appeared! [CP 96] [NCP 0.37] [Potential 0.6] [A/D/S 14/7/6]
2016-08-24 11:04:44,252 [PokemonCatchWorker] [INFO] [threw_pokeball] Nice Curveball throw! Used Pokeball, with chance 54.12 (1 left)
2016-08-24 11:04:44,449 [PokemonCatchWorker] [INFO] [pokemon_capture_failed] Pokeball thrown to Magikarp missed.. trying again!
2016-08-24 11:04:54,088 [PokemonCatchWorker] [INFO] [threw_pokeball] Great Curveball throw! Used Pokeball, with chance 54.12 (0 left)
2016-08-24 11:04:54,255 [PokemonCatchWorker] [INFO] [pokemon_capture_failed] Pokeball thrown to Magikarp missed.. trying again!
2016-08-24 11:04:57,858 [PokemonCatchWorker] [INFO] [no_pokeballs] No pokeballs left! Fleeing...
016-08-24 11:04:33,385 [MoveToMapPokemon] [INFO] [move_to_map_pokemon_encounter] Encountered Pokemon: Magikarp
2016-08-24 11:04:35,866 [MoveToMapPokemon] [INFO] [move_to_map_pokemon_teleport_back] Teleporting back to previous location (43.656, -79.38384)
2016-08-24 11:04:37,869 [PokemonCatchWorker] [INFO] [pokemon_appeared] A wild Magikarp appeared! [CP 96] [NCP 0.37] [Potential 0.6] [A/D/S 14/7/6]
2016-08-24 11:04:44,252 [PokemonCatchWorker] [INFO] [threw_pokeball] Nice Curveball throw! Used Pokeball, with chance 54.12 (1 left)
2016-08-24 11:04:44,449 [PokemonCatchWorker] [INFO] [pokemon_capture_failed] Pokeball thrown to Magikarp missed.. trying again!
2016-08-24 11:04:54,088 [PokemonCatchWorker] [INFO] [threw_pokeball] Great Curveball throw! Used Pokeball, with chance 54.12 (0 left)
2016-08-24 11:04:54,255 [PokemonCatchWorker] [INFO] [pokemon_capture_failed] Pokeball thrown to Magikarp missed.. trying again!

# Ran out of balls and fled

2016-08-24 11:04:57,858 [PokemonCatchWorker] [INFO] [no_pokeballs] No pokeballs left! Fleeing...
```
### Steps to Reproduce

In the `MoveToMapPokemon` task, you can set `"min_ball"` to whatever and it just seems to ignore it. 

OS: OSX 10.10.5 
Branch: dev
Git Commit: bda706aa1c4932265af19bc08363ac780d691864
Python Version: Python 2.7.12



Discussion:
Not sure why we check pokeballs three times in the work function. I'm looking into the fix, but I want to make sure I know what's going on in this file first. 


Resolving patch:
diff --git a/pokemongo_bot/cell_workers/move_to_map_pokemon.py b/pokemongo_bot/cell_workers/move_to_map_pokemon.py
--- a/pokemongo_bot/cell_workers/move_to_map_pokemon.py
+++ b/pokemongo_bot/cell_workers/move_to_map_pokemon.py
@@ -286,7 +286,7 @@ def work(self):
         superballs_quantity = inventory.items().get(GREATBALL_ID).count
         ultraballs_quantity = inventory.items().get(ULTRABALL_ID).count
 
-        if (pokeballs_quantity + superballs_quantity + ultraballs_quantity) < 1:
+        if (pokeballs_quantity + superballs_quantity + ultraballs_quantity) < self.min_ball:
             return WorkerResult.SUCCESS
 
         self.update_map_location()
@@ -305,11 +305,6 @@ def work(self):
 
         pokemon = pokemon_list[0]
 
-        if pokeballs_quantity < 1:
-            if superballs_quantity < 1:
-                if ultraballs_quantity < 1:
-                    return WorkerResult.SUCCESS
-
         if self.config['snipe']:
             if self.snipe_high_prio_only:
                 if self.snipe_high_prio_threshold < pokemon['priority']:
@@ -317,6 +312,12 @@ def work(self):
             else:
                 return self.snipe(pokemon)
 
+        # check for pokeballs (excluding masterball)
+        # checking again as we may have lost some if we sniped
+        pokeballs_quantity = inventory.items().get(POKEBALL_ID).count
+        superballs_quantity = inventory.items().get(GREATBALL_ID).count
+        ultraballs_quantity = inventory.items().get(ULTRABALL_ID).count
+
         if pokeballs_quantity + superballs_quantity + ultraballs_quantity < self.min_ball:
             return WorkerResult.SUCCESS
 


Test patch: