Skip to content
This repository has been archived by the owner on Jul 22, 2019. It is now read-only.

Feature: Sniping (with PogoLocationFeeder) #1036

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
6 changes: 6 additions & 0 deletions config.properties.template
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ use_lucky_egg=1
# Port where the socketserver should listen, 0 = do not listen
gui_port_socket=8001

# Allow sniping (Recommended value: false)
want_sniping false

# Port where the sniping information is sent to
sniping_port=16969

# Export player/pokemondata on Profile Update. Options are:
# *empty* Don't export (default)
# CSV Correct USA/UK CSV format ("," as delimiter and "." as decimal separator)
Expand Down
1 change: 1 addition & 0 deletions json-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"useLuckyEgg" : 1,
"export" : "",
"guiPortSocket" : 8001,
"snipingPort": 16969,
"initialMapSize" : 9,
"waitChance" : 0.0,
"waitTimeMin" : 0,
Expand Down
10 changes: 8 additions & 2 deletions src/main/kotlin/ink/abb/pogo/scraper/Bot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,15 @@ class Bot(val api: PokemonGo, val settings: Settings) {
"Have ${it.pokemonId.name} (${it.nickname}) with ${it.cp} CP and IV $IV% \r\n ${it.getStatsFormatted()}"
}.forEach { Log.normal(it) }

val keepalive = GetMapRandomDirection()
val keepalive = GetMapRandomDirection(isForSniping=false)
val drop = DropUselessItems()
val profile = UpdateProfile()
val catch = CatchOneNearbyPokemon()
val release = ReleasePokemon()
val evolve = EvolvePokemon()
val hatchEggs = HatchEggs()
val export = Export()
val sniper = SnipeListener()

if (settings.export.length > 0)
task(export)
Expand Down Expand Up @@ -156,7 +157,6 @@ class Bot(val api: PokemonGo, val settings: Settings) {
task(drop)
if (settings.autotransfer)
task(release)

}

runLoop(500, "PokestopLoop") {
Expand All @@ -166,6 +166,8 @@ class Bot(val api: PokemonGo, val settings: Settings) {
task(WalkToStartPokestop(process.startPokestop as Pokestop))
}



Log.setContext(ctx)

if (settings.guiPortSocket > 0) {
Expand All @@ -178,6 +180,10 @@ class Bot(val api: PokemonGo, val settings: Settings) {
Log.green("Open the map on http://ui.pogobot.club/")
}

if (settings.wantSniping && settings.snipingPort > 0) {
task(sniper)
Log.normal("Listening for snipe info on port ${settings.snipingPort}")
}

if (settings.timerWalkToStartPokestop > 0)
runLoop(TimeUnit.SECONDS.toMillis(settings.timerWalkToStartPokestop), "BotWalkBackLoop") {
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/ink/abb/pogo/scraper/Context.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ data class Context(

val walking: AtomicBoolean = AtomicBoolean(false),

val pauseWalking: AtomicBoolean = AtomicBoolean(false)
val pauseWalking: AtomicBoolean = AtomicBoolean(false),
val pauseForSniping: AtomicBoolean = AtomicBoolean(false)

)
7 changes: 7 additions & 0 deletions src/main/kotlin/ink/abb/pogo/scraper/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ class SettingsParser(val properties: Properties) {

guiPortSocket = getPropertyIfSet("Port where the socketserver should listen", "gui_port_socket", defaults.guiPortSocket, String::toInt),

wantSniping = getPropertyIfSet("Enable or disable the sniping feature", "want_sniping", defaults.wantSniping, String::toBoolean),

snipingPort = getPropertyIfSet("Port where the sniping information will be sent to", "sniping_port", defaults.snipingPort, String::toInt),

initialMapSize = getPropertyIfSet("Initial map size (S2 tiles) to fetch", "initial_map_size", defaults.initialMapSize, String::toInt),

waitChance = getPropertyIfSet("Chance to wait on a pokestop", "wait_chance", defaults.waitChance, String::toDouble),
Expand Down Expand Up @@ -256,6 +260,9 @@ data class Settings(

val guiPortSocket: Int = 8001,

val wantSniping: Boolean = false,
val snipingPort: Int = 16969,

var initialMapSize: Int = 9,

val version: String = Settings.version,
Expand Down
19 changes: 18 additions & 1 deletion src/main/kotlin/ink/abb/pogo/scraper/Values.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,21 @@ package ink.abb.pogo.scraper

val requiredXp = arrayOf(0, 1000, 3000, 6000, 10000, 15000, 21000, 28000, 36000, 45000, 55000, 65000, 75000,
85000, 100000, 120000, 140000, 160000, 185000, 210000, 260000, 335000, 435000, 560000, 710000, 900000, 1100000,
1350000, 1650000, 2000000, 2500000, 3000000, 3750000, 4750000, 6000000, 7500000, 9500000, 12000000, 15000000, 20000000)
1350000, 1650000, 2000000, 2500000, 3000000, 3750000, 4750000, 6000000, 7500000, 9500000, 12000000, 15000000, 20000000)

val pokedexId2Names = arrayOf("missingno", "bulbasaur", "ivysaur", "venosaur", "charmander", "charmeleon", "charizard", "squirtle", "wartortle", "blastoise",
"caterpie", "metapod", "butterfree", "weedle", "kakuna", "beedrill", "pidgey", "pidgeotto", "pidgeot", "rattata",
"raticate", "spearow", "fearow", "ekans", "arbok", "pikachu", "raichu", "sandshrew", "sandslash", "nidoran",
"nidorina", "nidoqueen", "nidoran", "nidorino", "nidoking", "clefairy", "clefable", "vulpix", "ninetales", "ninetails",
"jigglypuff", "wigglytuff", "zubat", "golbat", "oddish", "gloom", "vileplume", "paras", "parasect", "venonat",
"venomoth", "diglett", "dugtrio", "meowth", "persian", "psyduck", "golduck", "mankey", "primeape", "growlithe",
"arcanine", "poliwag", "poliwhirl", "poliwrath", "abra", "kadabra", "alakazam", "machop", "machoke", "machamp",
"bellsprout", "weepinbell", "victreebell", "tentacool", "tentacruel", "geodude", "graveler", "golem", "ponyta",
"rapidash", "slowpoke", "slowbro", "magnemite", "magneton", "farfetch", "doduo", "dodrio", "seel", "dewgong",
"grimer", "muk", "shellder", "cloyster", "gastly", "haunter", "gengar", "onix", "drowzee", "hypno", "krabby",
"kingler", "voltorb", "electrode", "exeggcute", "exeggutor", "cubone", "marowak", "hitmonlee", "hitmonchan",
"lickitung", "koffing", "weezing", "rhyhorn", "rhydon", "chansey", "tangela", "kangaskhan", "horsea", "seadra",
"goldeen", "seaking", "staryu", "starmie", "mime", "scyther", "jynx", "electrabuzz", "magmar", "pinsir", "tauros",
"magikarp", "gyarados", "lapras", "ditto", "eevee", "vaporeon", "jolteon", "flareon", "porygon", "omanyte", "omastar",
"kabuto", "kabutops", "aerodactyl", "snorlax", "articuno", "zapdos", "moltres", "dratini", "dragonair", "dragonite",
"mewtwo", "mew", "venusaur")
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import ink.abb.pogo.scraper.util.pokemon.shouldTransfer
class CatchOneNearbyPokemon : Task {
override fun run(bot: Bot, ctx: Context, settings: Settings) {
// STOP WALKING
if (ctx.pauseForSniping.get()) {
return
}
ctx.pauseWalking.set(true)
val pokemon = ctx.api.map.getCatchablePokemon(ctx.blacklistedEncounters)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ import ink.abb.pogo.scraper.Settings
import ink.abb.pogo.scraper.Task
import ink.abb.pogo.scraper.util.Log

class GetMapRandomDirection : Task {
class GetMapRandomDirection(val isForSniping: Boolean) : Task {
override fun run(bot: Bot, ctx: Context, settings: Settings) {
// query a small area to keep alive

if (ctx.pauseForSniping.get() && !isForSniping) {
return
}

val lat = ctx.lat.get() + randomLatLng()
val lng = ctx.lng.get() + randomLatLng()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ class ProcessPokestops(var pokestops: MutableCollection<Pokestop>) : Task {
var startPokestop: Pokestop? = null

override fun run(bot: Bot, ctx: Context, settings: Settings) {
if (ctx.pauseForSniping.get()) {
return
}

var writeCampStatus = false
if (lastFetch + refetchTime < bot.api.currentTimeMillis()) {
writeCampStatus = true
Expand Down
60 changes: 60 additions & 0 deletions src/main/kotlin/ink/abb/pogo/scraper/tasks/SnipeListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Pokemon Go Bot Copyright (C) 2016 PokemonGoBot-authors (see authors.md for more information)
* This program comes with ABSOLUTELY NO WARRANTY;
* This is free software, and you are welcome to redistribute it under certain conditions.
*
* For more information, refer to the LICENSE file in this repositories root directory
*/

package ink.abb.pogo.scraper.tasks

import ink.abb.pogo.scraper.Bot
import ink.abb.pogo.scraper.Context
import ink.abb.pogo.scraper.Settings
import ink.abb.pogo.scraper.Task
import ink.abb.pogo.scraper.pokedexId2Names
import kotlin.collections.Map
import java.io.*
import java.net.*
import java.util.ArrayList
import com.fasterxml.jackson.databind.*
import ink.abb.pogo.scraper.util.Log

class SnipeListener : Task {
override fun run(bot: Bot, ctx: Context, settings: Settings) {
val clientSocket = Socket("localhost", settings.snipingPort)

while (true) {
val dataReceived: BufferedReader
val multipleSnipes = ArrayList<Map<*,*>>()

try {
dataReceived = BufferedReader(InputStreamReader(clientSocket.inputStream))
val results = dataReceived.readLine().split("\n")
Log.red("$results")
for (result in results)
{
val result_map = ObjectMapper().readValue(result, Map::class.java)
multipleSnipes.add(result_map)
}

}
catch (e: Exception) {
continue
}

// We use a for loop because it processes multiple pokemon snipes at once.
for (snipe in multipleSnipes)
{
val latitude = snipe["Latitude"].toString().toDouble()
val longitude = snipe["Longitude"].toString().toDouble()
val pokemonId = snipe["Id"].toString().toInt()
val pokemonName: String = (pokedexId2Names[pokemonId + 1]).toString()

Log.green(text="ayo data: $snipe with name $pokemonName")
bot.task(SnipePokemon(latitude, longitude, pokemonName))
}

}
}
}
153 changes: 153 additions & 0 deletions src/main/kotlin/ink/abb/pogo/scraper/tasks/SnipePokemon.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* Pokemon Go Bot Copyright (C) 2016 PokemonGoBot-authors (see authors.md for more information)
* This program comes with ABSOLUTELY NO WARRANTY;
* This is free software, and you are welcome to redistribute it under certain conditions.
*
* For more information, refer to the LICENSE file in this repositories root directory
*/

package ink.abb.pogo.scraper.tasks

import POGOProtos.Networking.Responses.CatchPokemonResponseOuterClass.CatchPokemonResponse
import POGOProtos.Networking.Responses.EncounterResponseOuterClass.EncounterResponse.Status
import com.pokegoapi.api.inventory.Pokeball
import com.pokegoapi.api.map.pokemon.encounter.DiskEncounterResult
import ink.abb.pogo.scraper.Bot
import ink.abb.pogo.scraper.Context
import ink.abb.pogo.scraper.Settings
import ink.abb.pogo.scraper.Task
import ink.abb.pogo.scraper.util.Log
import ink.abb.pogo.scraper.util.cachedInventories
import ink.abb.pogo.scraper.util.inventory.hasPokeballs
import ink.abb.pogo.scraper.util.map.getCatchablePokemon
import ink.abb.pogo.scraper.util.pokemon.catch
import ink.abb.pogo.scraper.util.pokemon.getIvPercentage
import ink.abb.pogo.scraper.util.pokemon.getStatsFormatted
import ink.abb.pogo.scraper.util.pokemon.shouldTransfer

class SnipePokemon (val latitude: Double, val longitude: Double, val pokemonName: String): Task {
override fun run(bot: Bot, ctx: Context, settings: Settings) {
ctx.pauseWalking.set(true)
ctx.pauseForSniping.set(true)
val hasPokeballs = ctx.api.cachedInventories.itemBag.hasPokeballs()
if (!hasPokeballs) {
ctx.pauseWalking.set(false)
return
}

var oldLatitude = ctx.lat.get()
var oldLongitude = ctx.lng.get()

ctx.lat.set(latitude); ctx.lng.set(longitude)
ctx.api.setLocation(latitude, longitude, 0.0)
bot.task(GetMapRandomDirection(isForSniping=true))

val pokemon = ctx.api.map.getCatchablePokemon(ctx.blacklistedEncounters)

Log.cyan("Sniper Found $pokemon at long/lat ${ctx.lng.get()}/${ctx.lat.get()}")
val catchablePokemon = pokemon.find { it.pokemonId.toString().toLowerCase().equals(pokemonName.toLowerCase()) }

Log.cyan(text="$catchablePokemon")
if (null != catchablePokemon) {
if (settings.obligatoryTransfer.contains(catchablePokemon.pokemonId) && settings.desiredCatchProbabilityUnwanted == -1.0) {
ctx.blacklistedEncounters.add(catchablePokemon.encounterId)
Log.normal("Found pokemon ${catchablePokemon.pokemonId}; blacklisting it because it's unwanted")
ctx.pauseWalking.set(false)
return
}
Log.green("Found pokemon ${catchablePokemon.pokemonId}")

val encounterResult = catchablePokemon.encounterPokemon()
val wasFromLure = encounterResult is DiskEncounterResult
if (encounterResult.wasSuccessful()) {
val pokemonData = encounterResult.pokemonData
Log.green("Encountered pokemon ${catchablePokemon.pokemonId} " +
"with CP ${pokemonData.cp} and IV ${pokemonData.getIvPercentage()}%")

ctx.lat.set(oldLatitude); ctx.lng.set(oldLongitude)
ctx.api.setLocation(oldLatitude, oldLongitude, 0.0)

bot.task(GetMapRandomDirection(isForSniping=true))

val (shouldRelease, reason) = pokemonData.shouldTransfer(settings)
val desiredCatchProbability = if (shouldRelease) {
Log.yellow("Using desired_catch_probability_unwanted because $reason")
settings.desiredCatchProbabilityUnwanted
} else {
settings.desiredCatchProbability
}
if (desiredCatchProbability == -1.0) {
ctx.blacklistedEncounters.add(catchablePokemon.encounterId)
Log.normal("CP/IV of encountered pokemon ${catchablePokemon.pokemonId} is too low; blacklisting encounter")
ctx.pauseWalking.set(false)
return
}

val isCurveBall = (Math.random() < settings.desiredCurveRate)
val result = catchablePokemon.catch(
encounterResult.captureProbability,
ctx.api.cachedInventories.itemBag,
desiredCatchProbability,
isCurveBall,
!settings.neverUseBerries,
settings.randomBallThrows,
settings.waitBetweenThrows,
-1)

if (result == null) {
ctx.blacklistedEncounters.add(catchablePokemon.encounterId)
Log.red("No Pokeballs in your inventory; blacklisting Pokemon")
ctx.pauseWalking.set(false)
return
}

ctx.blacklistedEncounters.add(catchablePokemon.encounterId)
if (result.status == CatchPokemonResponse.CatchStatus.CATCH_SUCCESS) {
ctx.pokemonStats.first.andIncrement
if (wasFromLure) {
ctx.luredPokemonStats.andIncrement
}
val iv = (pokemonData.individualAttack + pokemonData.individualDefense + pokemonData.individualStamina) * 100 / 45
var message = "Caught a ${catchablePokemon.pokemonId} " +
"with CP ${pokemonData.cp} and IV $iv%"
message += "\r\n ${pokemonData.getStatsFormatted()}"
if (settings.displayIfPokemonFromLure) {
if (encounterResult is DiskEncounterResult)
message += " (lured pokemon) "
else
message += " (wild pokemon) "
}
if (settings.displayPokemonCatchRewards)
message += ": [${result.xpList.sum()}x XP, ${result.candyList.sum()}x " +
"Candy, ${result.stardustList.sum()}x Stardust]"
Log.cyan(message)

ctx.server.newPokemon(catchablePokemon.latitude, catchablePokemon.longitude, pokemonData)
ctx.server.sendProfile()
} else {
Log.red("Capture of ${catchablePokemon.pokemonId} failed with status : ${result.status}")
if (result.status == CatchPokemonResponse.CatchStatus.CATCH_ERROR) {
Log.red("Blacklisting pokemon to prevent infinite loop")
}
}
} else {
// We need to set this back to the old value.
ctx.lat.set(oldLatitude); ctx.lng.set(oldLongitude)
ctx.api.setLocation(oldLatitude, oldLongitude, 0.0)

Log.red("Encounter failed with result: ${encounterResult.status}")
if (encounterResult.status == Status.POKEMON_INVENTORY_FULL) {
Log.red("Disabling catching of Pokemon")

ctx.pokemonInventoryFullStatus.second.set(true)

settings.catchPokemon = false
}
}
}
ctx.pauseWalking.set(false)
bot.task(GetMapRandomDirection(isForSniping=false))
ctx.pauseForSniping.set(false)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import java.util.concurrent.atomic.AtomicBoolean

class WalkToStartPokestop(val startPokeStop: Pokestop) : Task {
override fun run(bot: Bot, ctx: Context, settings: Settings) {
if (ctx.pauseForSniping.get()) {
return
}
if (settings.followStreets) walkRoute(bot, ctx, settings)
else walk(bot, ctx, settings)

Expand Down