Track data over the course of each run

This commit is contained in:
Kyle Coburn 2015-04-17 13:40:56 -07:00
parent 7dfb5c7978
commit 9fad2ec9e5
12 changed files with 591 additions and 57 deletions

View File

@ -4,6 +4,8 @@ local Input = require "util.input"
local Memory = require "util.memory"
local Menu = require "util.menu"
local Data = require "data.data"
local alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ *():;[]ab-?!mf/.,"
-- local alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ *():;[]ポモ-?!♂♀/.,"
@ -82,6 +84,7 @@ function Textbox.setName(name)
nidoIdx = name + 1
nidoName = getLetterAt(name)
end
Data.run.voted_name = nidoName
end
function Textbox.isActive()

View File

@ -9,6 +9,7 @@ local Memory = require "util.memory"
local Paint = require "util.paint"
local Utils = require "util.utils"
local Data = require "data.data"
local Inventory = require "storage.inventory"
local Pokemon = require "storage.pokemon"
@ -19,11 +20,11 @@ local canDie, shouldFight, minExp
local shouldCatch, attackIdx
local extraEncounter, maxEncounters
local battleYolo
local encountersSection
local yellow = YELLOW
Control.areaName = "Unknown"
Control.moonEncounters = nil
Control.getMoonExp = true
Control.yolo = false
@ -82,8 +83,17 @@ local controlFunctions = {
shouldFight = {{name="rattata"}, {name="pidgey"}, {name="nidoran"}, {name="nidoranf",levels={2}}}
end,
trackEncounters = function(data)
local area = data.area
if area then
encountersSection = "encounters_"..area
Data.run[encountersSection] = 0
else
encountersSection = nil
end
end,
startMtMoon = function()
Control.moonEncounters = 0
Control.canDie(false)
Control.getMoonExp = not yellow
end,
@ -203,7 +213,7 @@ function Control.canCatch(partySize)
if yellow and Pokemon.inParty("nidoran", "nidorino", "nidoking") and Pokemon.inParty("pidgey", "spearow") then
return false
end
Strategies.reset("Not enough PokeBalls", pokeballs)
Strategies.reset("pokeballs", "Not enough PokeBalls", pokeballs)
return false
end
return true
@ -213,7 +223,7 @@ function Control.shouldCatch(partySize)
if maxEncounters and encounters > maxEncounters then
local extraCount = extraEncounter and Pokemon.inParty(extraEncounter)
if not extraCount or encounters > maxEncounters + 1 then
Strategies.reset("Too many encounters", encounters)
Strategies.reset("encounters", "Too many encounters", encounters)
return false
end
end
@ -301,11 +311,13 @@ function Control.encounter(battleState)
Bridge.chat("gen 1 missed :( (1 in 256 chance)")
end
Control.missed = true
Data.increment("misses")
end
end
end
if isCritical ~= nil and isCritical ~= Control.criticaled then
Control.criticaled = isCritical
Data.increment("criticals")
end
if wildBattle then
local opponentAlive = Battle.opponentAlive()
@ -316,11 +328,16 @@ function Control.encounter(battleState)
encounters = encounters + 1
Paint.wildEncounters(encounters)
Bridge.encounter()
if Control.moonEncounters then
if INTERNAL and STREAMING_MODE and Pokemon.isOpponent("zubat") then
Bridge.chat("NightBat")
if encountersSection then
Data.increment(encountersSection)
if Pokemon.isOpponent("zubat") then
local zubatCount = Data.increment("encounters_zubats")
Data.run.encounters_zubats = zubatCount
if INTERNAL and STREAMING_MODE then
Bridge.chat(Utils.multiplyString("NightBat", zubatCount))
end
end
Control.moonEncounters = Control.moonEncounters + 1
end
end
else

View File

@ -15,6 +15,7 @@ local Menu = require "util.menu"
local Player = require "util.player"
local Utils = require "util.utils"
local Data = require "data.data"
local Inventory = require "storage.inventory"
local Pokemon = require "storage.pokemon"
@ -306,7 +307,7 @@ strategyFunctions.fightBulbasaur = function()
special = Pokemon.index(0, "special"),
}
if stats.squirtle.attack < 11 and stats.squirtle.special < 12 then
return Strategies.reset("Bad Squirtle - "..stats.squirtle.attack.." attack, "..stats.squirtle.special.." special")
return Strategies.reset("stats", "Bad Squirtle - "..stats.squirtle.attack.." attack, "..stats.squirtle.special.." special")
end
status.tries = 9001
else
@ -339,7 +340,7 @@ strategyFunctions.catchNidoran = function()
local pokeballs = Inventory.count("pokeball")
local caught = Memory.value("player", "party_size") - 1
if pokeballs < 5 - caught * 2 then
return Strategies.reset("Ran too low on PokeBalls", pokeballs)
return Strategies.reset("pokeballs", "Ran too low on PokeBalls", pokeballs)
end
if Battle.isActive() then
local isNidoran = Pokemon.isOpponent("nidoran")
@ -363,7 +364,11 @@ strategyFunctions.catchNidoran = function()
end
else
local enableDSum = true
Pokemon.updateParty()
if not Data.run.early_flier then
Data.run.early_flier = Pokemon.inParty("spearow") ~= nil
end
local hasNidoran = Pokemon.inParty("nidoran")
if hasNidoran then
local gotExperience = Pokemon.getExp() > 205
@ -465,7 +470,7 @@ strategyFunctions.fightWeedle = function()
if Battle.isTrainer() then
status.canProgress = true
if Memory.value("battle", "our_status") > 0 and not Inventory.contains("antidote") then
return Strategies.reset("Poisoned, but we skipped the antidote")
return Strategies.reset("antidote", "Poisoned, but we skipped the antidote")
end
return Strategies.buffTo("tail_whip", 5)
elseif status.canProgress then
@ -476,7 +481,7 @@ end
strategyFunctions.equipForBrock = function(data)
if Strategies.initialize() then
if Pokemon.info("squirtle", "level") < 8 then
return Strategies.reset("Did not reach level 8 before Brock", Pokemon.getExp(), true)
return Strategies.reset("level8", "Did not reach level 8 before Brock", Pokemon.getExp(), true)
end
if data.anti then
local poisoned = Pokemon.info("squirtle", "status") > 0
@ -484,7 +489,7 @@ strategyFunctions.equipForBrock = function(data)
return true
end
if not Inventory.contains("antidote") then
return Strategies.reset("Poisoned, but we risked skipping the antidote")
return Strategies.reset("antidote", "Poisoned, but we risked skipping the antidote")
end
local curr_hp = Pokemon.info("squirtle", "hp")
if Inventory.contains("potion") and curr_hp > 8 and curr_hp < 18 then
@ -562,7 +567,7 @@ strategyFunctions.fightBrock = function()
local nidoranStatus = "Att: "..att..", Def: "..def..", Speed: "..spd..", Special: "..scl
if resetsForStats then
return Strategies.reset("Bad Nidoran - "..nidoranStatus)
return Strategies.reset("stats", "Bad Nidoran - "..nidoranStatus)
end
status.tries = 9001

View File

@ -15,6 +15,7 @@ local Player = require "util.player"
local Shop = require "action.shop"
local Utils = require "util.utils"
local Data = require "data.data"
local Inventory = require "storage.inventory"
local Pokemon = require "storage.pokemon"
@ -37,15 +38,19 @@ function Strategies.getTimeRequirement(name)
return Strategies.timeRequirements[name]()
end
function Strategies.hardReset(message, extra, wait)
function Strategies.hardReset(reason, message, extra, wait)
resetting = true
if Strategies.seed then
if Data.run.seed then
if extra then
extra = extra.." | "..Strategies.seed
extra = extra.." | "..Data.run.seed
else
extra = Strategies.seed
extra = Data.run.seed
end
end
local map, px, py = Memory.value("game", "map"), Player.position()
Data.reset(reason, Control.areaName, map, px, py)
Bridge.chat(message, extra)
if wait and INTERNAL and not STREAMING_MODE then
strategyFunctions.wait()
@ -55,7 +60,7 @@ function Strategies.hardReset(message, extra, wait)
return true
end
function Strategies.reset(reason, extra, wait)
function Strategies.reset(reason, explanation, extra, wait)
local time = Utils.elapsedTime()
local resetMessage = "reset"
if time then
@ -68,25 +73,29 @@ function Strategies.reset(reason, extra, wait)
else
separator = ":"
end
resetMessage = resetMessage..separator.." "..reason
resetMessage = resetMessage..separator.." "..explanation
if status.tweeted then
Strategies.tweetProgress(resetMessage)
end
return Strategies.hardReset(resetMessage, extra, wait)
return Strategies.hardReset(reason, resetMessage, extra, wait)
end
function Strategies.death(extra)
local reason
local reason, explanation
if Control.missed then
reason = "Missed"
explanation = "Missed"
reason = "miss"
elseif Control.criticaled then
reason = "Critical'd"
explanation = "Critical'd"
reason = "critical"
elseif Control.yolo then
reason = "Yolo strats"
explanation = "Yolo strats"
reason = "yolo"
else
reason = "Died"
explanation = "Died"
reason = "death"
end
return Strategies.reset(reason, extra)
return Strategies.reset(reason, explanation, extra)
end
function Strategies.overMinute(min)
@ -96,14 +105,14 @@ function Strategies.overMinute(min)
return Utils.igt() > (min * 60)
end
function Strategies.resetTime(timeLimit, reason, once)
function Strategies.resetTime(timeLimit, explanation, once)
if Strategies.overMinute(timeLimit) then
reason = "Took too long to "..reason
explanation = "Took too long to "..explanation
if RESET_FOR_TIME then
return Strategies.reset(reason)
return Strategies.reset("time", explanation)
end
if once then
print(reason.." "..Utils.elapsedTime())
print(explanation.." "..Utils.elapsedTime())
end
end
end
@ -500,6 +509,8 @@ Strategies.functions = {
end,
split = function(data)
Data.increment("reset_split")
Bridge.split(data and data.finished)
if Strategies.replay then
splitNumber = splitNumber + 1
@ -634,7 +645,7 @@ Strategies.functions = {
if not status.triedTeaching then
status.triedTeaching = true
if not Inventory.contains(itemName) then
return Strategies.reset("Unable to teach move "..itemName.." to "..data.poke, nil, true)
return Strategies.reset("error", "Unable to teach move "..itemName.." to "..data.poke, nil, true)
end
end
local replacement
@ -1050,12 +1061,13 @@ Strategies.functions = {
if Battle.pp("horn_attack") == 0 then
print("ERR: Ran out of Horn Attacks")
end
if Control.moonEncounters then
local moonEncounters = Data.run.encounters_moon
if moonEncounters then
local catchPokemon = yellow and "sandshrew" or "paras"
local capsName = Utils.capitalize(catchPokemon)
local parasStatus
local conjunction = "but"
local goodEncounters = Control.moonEncounters < 10
local goodEncounters = moonEncounters < 10
local catchDescription
if Pokemon.inParty(catchPokemon) then
catchDescription = catchPokemon
@ -1071,8 +1083,7 @@ Strategies.functions = {
parasStatus = "we didn't catch a "..capsName.." :("
end
Bridge.caught(catchDescription)
Bridge.chat(Control.moonEncounters.." Moon encounters, "..conjunction.." "..parasStatus)
Control.moonEncounters = nil
Bridge.chat(moonEncounters.." Moon encounters, "..conjunction.." "..parasStatus)
end
Strategies.resetTime("mt_moon", "complete Mt. Moon", true)
@ -1555,7 +1566,7 @@ Strategies.functions = {
end
local px, py = Player.position()
if px > 7 then
return Strategies.reset("Accidentally walked on the island :(", px, true)
return Strategies.reset("error", "Accidentally walked on the island :(", px, true)
end
if Memory.value("player", "moving") == 0 then
Player.interact("Right")
@ -1587,15 +1598,16 @@ Strategies.functions = {
victoryMessage = victoryMessage..", a new PB!"
end
Strategies.tweetProgress(victoryMessage)
if Strategies.seed then
print("v"..VERSION..": "..Utils.frames().." frames, with seed "..Strategies.seed)
if Data.run.seed then
Data.run.frames = Utils.frames()
print("v"..VERSION..": "..Data.run.frames.." frames, with seed "..Data.run.seed)
if STREAMING_MODE and not Strategies.replay then
print("Please save this seed number to share, if you would like proof of your run!")
print("A screenshot has been saved to the Gameboy\\Screenshots folder in BizHawk.")
gui.cleartext()
gui.text(0, 0, "PokeBot v"..VERSION)
gui.text(0, 7, "Seed: "..Strategies.seed)
gui.text(0, 7, "Seed: "..Data.run.seed)
gui.text(0, 14, "Name: "..Textbox.getNamePlaintext())
gui.text(0, 21, "Reset for time: "..tostring(RESET_FOR_TIME))
gui.text(0, 28, "Time: "..Utils.elapsedTime())
@ -1609,7 +1621,7 @@ Strategies.functions = {
elseif status.frames == 500 then
Bridge.chat("beat the game in "..status.finishTime.."!")
elseif status.frames > 2000 then
return Strategies.hardReset("Back to the grind - you can follow on Twitter for updates on our next good run! https://twitter.com/thepokebot")
return Strategies.hardReset("won", "Back to the grind - you can follow on Twitter for updates on our next good run! https://twitter.com/thepokebot")
end
status.frames = status.frames + 1
elseif Memory.value("menu", "shop_current") == 252 then

View File

@ -257,7 +257,7 @@ strategyFunctions.catchNidoran = function()
local pokeballs = Inventory.count("pokeball")
local caught = Memory.value("player", "party_size") > 1
if pokeballs < (caught and 1 or 2) then
return Strategies.reset("Ran too low on PokeBalls", pokeballs)
return Strategies.reset("pokeballs", "Ran too low on PokeBalls", pokeballs)
end
if Battle.isActive() then
status.path = nil
@ -332,7 +332,7 @@ strategyFunctions.checkNidoStats = function()
local resets = att < 15 or spd < 14 or scl < 12 --RISK
local nidoranStatus = "Att: "..att..", Def: "..def..", Speed: "..spd..", Special: "..scl
if resets then
return Strategies.reset("Bad Nidoran - "..nidoranStatus)
return Strategies.reset("stats", "Bad Nidoran - "..nidoranStatus)
end
-- if def < 12 then
-- statDiff = statDiff + 1

54
data/data.lua Normal file
View File

@ -0,0 +1,54 @@
local Data
local Bridge = require "util.bridge"
local Utils = require "util.utils"
local Pokemon = require "storage.pokemon"
local version = 0
local vIndex = 2
for segment in string.gmatch(VERSION, "([^.]+)") do
version = version + tonumber(segment) * 100 ^ vIndex
vIndex = vIndex - 1
end
Data = {
run = {},
versionNumber = version,
}
function Data.increment(key)
local incremented = Utils.increment(Data.run[key])
Data.run[key] = incremented
return incremented
end
function Data.reset(reason, areaName, map, px, py)
-- if INTERNAL and STREAMING_MODE then --TODO
if INTERNAL then
local report = Data.run
report.cutter = Pokemon.inParty("paras", "oddish", "sandshrew", "charmander")
for key,value in pairs(report) do
if value == true or value == false then
report[key] = value == true and 1 or 0
end
end
report.version = Data.versionNumber
report.reset_area = areaName
report.reset_map = map
report.reset_x = px
report.reset_y = py
report.reset_reason = reason
if not report.frames then
report.frames = Utils.frames()
end
Bridge.report(report)
end
Data.run = {}
end
return Data

View File

@ -12,7 +12,7 @@ local Paths = {
-- 1: RIVAL 1
-- Let's try this escape again
{0, {12,12}, {c="a",a="Pallet Town"}, {c="viridianExp"}, {c="encounters",limit=4}, {9,12}, {9,2}, {10,2}, {10,-1}},
{0, {12,12}, {c="a",a="Pallet Town"}, {c="viridianExp"}, {c="encounters",limit=4}, {c="trackEncounters",area="route1"}, {9,12}, {9,2}, {10,2}, {10,-1}},
-- First encounters
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
-- To the Mart
@ -36,7 +36,7 @@ local Paths = {
-- Viridian Mart redux
{42, {3,7}, {3,5}, {2,5}, {s="shopViridianPokeballs"}, {3,5}, {3,8}},
-- Sidequest
{1, {29,20}, {15,20}, {15,17}, {-1, 17}},
{1, {29,20}, {c="trackEncounters",area="nidoran"}, {15,20}, {15,17}, {-1, 17}},
-- Nidoran
{33, {39, 9}, {c="a",a="Nidoran grass"}, {c="nidoranBackupExp"}, {c="encounters",limit=7,extra="spearow"}, {35, 9}, {35,12}, {33,12}, {c="catchNidoran"}, {s="catchNidoran"}, {33,12}, {s="split"}, {37,12}, {37,9}, {40,9}},
@ -47,7 +47,7 @@ local Paths = {
-- To the Forest
{13, {7,71}, {7,57}, {4,57}, {4,52}, {10,52}, {10,44}, {3,44}, {3,43}},
-- Forest entrance
{50, {4,7}, {c="a",a="Viridian Forest"}, {4,1}, {5,1}, {5,0}},
{50, {4,7}, {c="a",a="Viridian Forest"}, {c="trackEncounters",area="forest"}, {4,1}, {5,1}, {5,0}},
-- Viridian Forest
{51, {17,47}, {17,43}, {26,43}, {26,34}, {25,34}, {25,32}, {27,32}, {27,20}, {25,20}, {25,12}, {s="grabAntidote"}, {25,9}, {17,9}, {17,16}, {13,16}, {13,3}, {7,3}, {7,22}, {1,22}, {1,19}, {s="grabForestPotion"}, {1,18}, {s="fightWeedle"}, {c="encounters",limit=22,extra="paras"}, {1,16}, {c="potion",b=false}, {s="equipForBrock",anti=true}, {1,5}, {s="equipForBrock"}, {1,-1}},
-- Forest exit
@ -68,7 +68,7 @@ local Paths = {
-- Leaving Pewter City
{2, {23,18}, {40,18}},
-- Route 3
{14, {0,10}, {c="a",a="Route 3"}, {c="catchFlier"}, {c="pp",on=true}, {s="battleModeSet"}, {8,10}, {8,8}, {11,8}, {11,6}, {s="bugCatcher"}, {11,4}, {12,4}, {s="potion",hp=19}, {13,4}, {s="talk",dir="Right"}, {s="shortsKid"}, {s="tweetAfterBrock"}, {13,5}, {s="potionBeforeCocoons"}, {18,5}, {s="talk",dir="Right"}, {s="swapMove",move="horn_attack",to=0}, {18,6}, {22,6}, {22,5}, {s="potion",hp=4}, {24,5}, {s="talk",dir="Down"}, {s="fightMetapod"}, {27,5}, {27,9}, {s="catchFlierBackup"}, {37,8}, {37,5}, {49,5}, {49,10}, {57,10}, {57,8}, {59,8}, {59,-1}},
{14, {0,10}, {c="a",a="Route 3"}, {c="catchFlier"}, {c="pp",on=true}, {c="trackEncounters",area="route3"}, {s="battleModeSet"}, {8,10}, {8,8}, {11,8}, {11,6}, {s="bugCatcher"}, {11,4}, {12,4}, {c="a",a="Shorts Kid"}, {s="potion",hp=19}, {13,4}, {s="talk",dir="Right"}, {s="shortsKid"}, {s="tweetAfterBrock"}, {13,5}, {c="a",a="Route 3"}, {s="potionBeforeCocoons"}, {18,5}, {s="talk",dir="Right"}, {s="swapMove",move="horn_attack",to=0}, {18,6}, {22,6}, {22,5}, {s="potion",hp=4}, {24,5}, {s="talk",dir="Down"}, {s="fightMetapod"}, {27,5}, {27,9}, {s="catchFlierBackup"}, {37,8}, {37,5}, {49,5}, {49,10}, {57,10}, {57,8}, {59,8}, {59,-1}},
-- To the Center
{15, {9,16}, {c="pp",on=false}, {12,16}, {12,6}, {11,6}, {11,5}},
-- PP up
@ -79,7 +79,7 @@ local Paths = {
-- 4: ROUTE 3
-- Mt. Moon F1
{59, {14,35}, {c="a",a="Mt. Moon"}, {c="startMtMoon"}, {c="catchParas"}, {14,22}, {21,22}, {21,15}, {24,15}, {24,27}, {25,27}, {25,31}, {s="talk",dir="Left"}, {25,32}, {33,32}, {33,31}, {34,31}, {s="take",dir="Right"}, {35,31}, {35,23}, {s="take",dir="Right"}, {35,7}, {30,7}, {s="evolveNidorino"}, {c="moon1Exp"}, {28,7}, {16,7}, {16,17}, {2,17}, {2,3}, {s="take",dir="Up"}, {5,3}, {5,5}},
{59, {14,35}, {c="a",a="Mt. Moon"}, {c="trackEncounters",area="moon"}, {c="startMtMoon"}, {c="catchParas"}, {14,22}, {21,22}, {21,15}, {24,15}, {24,27}, {25,27}, {25,31}, {s="talk",dir="Left"}, {25,32}, {33,32}, {33,31}, {34,31}, {s="take",dir="Right"}, {35,31}, {35,23}, {s="take",dir="Right"}, {35,7}, {30,7}, {s="evolveNidorino"}, {c="moon1Exp"}, {28,7}, {16,7}, {16,17}, {2,17}, {2,3}, {s="take",dir="Up"}, {5,3}, {5,5}},
-- Mt. Moon B2
{60, {5,5}, {5,17}, {21,17}},
-- Mt. Moon B3
@ -90,7 +90,7 @@ local Paths = {
-- 5: MT. MOON
-- To Cerulean
{15, {24,6}, {s="reportMtMoon"}, {s="split"}, {24,8}, {35,8}, {35,10}, {61,10}, {61,8}, {79,8}, {79,10}, {90,10}},
{15, {24,6}, {s="reportMtMoon"}, {c="trackEncounters",area=nil}, {s="split"}, {24,8}, {35,8}, {35,10}, {61,10}, {61,8}, {79,8}, {79,10}, {90,10}},
-- Enter Cerulean
{3, {0,18}, {c="a",a="Cerulean"}, {14,18}, {s="dodgeCerulean"}, {19,18}, {19,17}},
-- Cerulean Center
@ -106,7 +106,7 @@ local Paths = {
-- Rival 2
{3, {9,12}, {c="a",a="Cerulean Rival"}, {21,12}, {21,6}, {s="rivalSandAttack"}, {21,-1}},
-- Nugget bridge
{35, {11,35}, {c="a",a="Nugget Bridge"}, {11,32}, {s="talk",dir="Up"}, {s="hornAttackCaterpie"}, {10,32}, {10,29}, {s="potion",hp=12,yolo=10}, {s="talk",dir="Up"}, {11,29}, {11,27}, {s="rareCandyEarly",close=true}, {s="potion",hp=10,yolo=8,close=true}, {11,26}, {s="talk",dir="Up"}, {s="swapThrash"}, {10,26}, {10,24}, {s="teachThrash"}, {s="potion",hp=4}, {10,23}, {s="talk",dir="Up"}, {s="swapThrash"}, {11,23}, {11,21}, {s="teachThrash"}, {s="potionForMankey"}, {11,20}, {s="talk",dir="Up"}, {s="redbarMankey"}, {s="swapThrash"}, {10,20}, {10,19}, {s="teachThrash"}, {10,15}, {s="learnThrash"}, {s="swapThrash"}, {s="waitToFight"}, {s="teachThrash"}, {s="split"}, {10,8}, {20,8}},
{35, {11,35}, {c="a",a="Nugget Bridge"}, {11,32}, {s="talk",dir="Up"}, {s="hornAttackCaterpie"}, {10,32}, {10,29}, {s="potion",hp=12,yolo=10}, {s="talk",dir="Up"}, {11,29}, {11,27}, {s="rareCandyEarly",close=true}, {s="potion",hp=10,yolo=8,close=true}, {11,26}, {s="talk",dir="Up"}, {s="swapThrash"}, {10,26}, {10,24}, {s="teachThrash"}, {s="potion",hp=4}, {10,23}, {s="talk",dir="Up"}, {s="swapThrash"}, {11,23}, {11,21}, {s="teachThrash"}, {s="potionForMankey"}, {11,20}, {s="talk",dir="Up"}, {s="swapThrash"}, {s="redbarMankey"}, {10,20}, {10,19}, {s="teachThrash"}, {10,15}, {s="learnThrash"}, {s="swapThrash"}, {s="waitToFight"}, {s="teachThrash"}, {s="split"}, {10,8}, {20,8}},
-- 6: NUGGET BRIDGE
@ -445,7 +445,7 @@ local Paths = {
-- Blue
{120, {4,3}, {c="a",a="Blue"}, {s="blue"}, {3,0}},
-- Champion
{118, {4,2}, {s="champion"}}
{118, {4,2}, {c="a",a="Champion"}, {s="champion"}}
}

417
external/json.lua vendored Normal file
View File

@ -0,0 +1,417 @@
-----------------------------------------------------------------------------
-- JSON4Lua: JSON encoding / decoding support for the Lua language.
-- json Module.
-- Author: Craig Mason-Jones
-- Homepage: http://github.com/craigmj/json4lua/
-- Version: 1.0.0
-- This module is released under the MIT License (MIT).
-- Please see LICENCE.txt for details.
--
-- USAGE:
-- This module exposes two functions:
-- json.encode(o)
-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string.
-- json.decode(json_string)
-- Returns a Lua object populated with the data encoded in the JSON string json_string.
--
-- REQUIREMENTS:
-- compat-5.1 if using Lua 5.0
--
-- CHANGELOG
-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix).
-- Fixed Lua 5.1 compatibility issues.
-- Introduced json.null to have null values in associative arrays.
-- json.encode() performance improvement (more than 50%) through table.concat rather than ..
-- Introduced decode ability to ignore /**/ comments in the JSON string.
-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Imports and dependencies
-----------------------------------------------------------------------------
local math = require('math')
local string = require("string")
local table = require("table")
-----------------------------------------------------------------------------
-- Module declaration
-----------------------------------------------------------------------------
local json = {} -- Public namespace
local json_private = {} -- Private namespace
-- Public functions
-- Private functions
local decode_scanArray
local decode_scanComment
local decode_scanConstant
local decode_scanNumber
local decode_scanObject
local decode_scanString
local decode_scanWhitespace
local encodeString
local isArray
local isEncodable
-----------------------------------------------------------------------------
-- PUBLIC FUNCTIONS
-----------------------------------------------------------------------------
--- Encodes an arbitrary Lua object / variable.
-- @param v The Lua object / variable to be JSON encoded.
-- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)
function json.encode (v)
-- Handle nil values
if v==nil then
return "null"
end
local vtype = type(v)
-- Handle strings
if vtype=='string' then
return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string
end
-- Handle booleans
if vtype=='number' or vtype=='boolean' then
return tostring(v)
end
-- Handle tables
if vtype=='table' then
local rval = {}
-- Consider arrays separately
local bArray, maxCount = isArray(v)
if bArray then
for i = 1,maxCount do
table.insert(rval, json.encode(v[i]))
end
else -- An object, not an array
for i,j in pairs(v) do
if isEncodable(i) and isEncodable(j) then
table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j))
end
end
end
if bArray then
return '[' .. table.concat(rval,',') ..']'
else
return '{' .. table.concat(rval,',') .. '}'
end
end
-- Handle null values
if vtype=='function' and v==null then
return 'null'
end
assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v))
end
--- Decodes a JSON string and returns the decoded value as a Lua data structure / value.
-- @param s The string to scan.
-- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1.
-- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil,
-- and the position of the first character after
-- the scanned JSON object.
function json.decode(s, startPos)
startPos = startPos and startPos or 1
startPos = decode_scanWhitespace(s,startPos)
assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')
local curChar = string.sub(s,startPos,startPos)
-- Object
if curChar=='{' then
return decode_scanObject(s,startPos)
end
-- Array
if curChar=='[' then
return decode_scanArray(s,startPos)
end
-- Number
if string.find("+-0123456789.e", curChar, 1, true) then
return decode_scanNumber(s,startPos)
end
-- String
if curChar==[["]] or curChar==[[']] then
return decode_scanString(s,startPos)
end
if string.sub(s,startPos,startPos+1)=='/*' then
return decode(s, decode_scanComment(s,startPos))
end
-- Otherwise, it must be a constant
return decode_scanConstant(s,startPos)
end
--- The null function allows one to specify a null value in an associative array (which is otherwise
-- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }
function null()
return null -- so json.null() will also return null ;-)
end
-----------------------------------------------------------------------------
-- Internal, PRIVATE functions.
-- Following a Python-like convention, I have prefixed all these 'PRIVATE'
-- functions with an underscore.
-----------------------------------------------------------------------------
--- Scans an array from JSON into a Lua object
-- startPos begins at the start of the array.
-- Returns the array and the next starting position
-- @param s The string being scanned.
-- @param startPos The starting position for the scan.
-- @return table, int The scanned array as a table, and the position of the next character to scan.
function decode_scanArray(s,startPos)
local array = {} -- The return value
local stringLen = string.len(s)
assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s )
startPos = startPos + 1
-- Infinite loop for array elements
repeat
startPos = decode_scanWhitespace(s,startPos)
assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.')
local curChar = string.sub(s,startPos,startPos)
if (curChar==']') then
return array, startPos+1
end
if (curChar==',') then
startPos = decode_scanWhitespace(s,startPos+1)
end
assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.')
object, startPos = json.decode(s,startPos)
table.insert(array,object)
until false
end
--- Scans a comment and discards the comment.
-- Returns the position of the next character following the comment.
-- @param string s The JSON string to scan.
-- @param int startPos The starting position of the comment
function decode_scanComment(s, startPos)
assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos)
local endPos = string.find(s,'*/',startPos+2)
assert(endPos~=nil, "Unterminated comment in string at " .. startPos)
return endPos+2
end
--- Scans for given constants: true, false or null
-- Returns the appropriate Lua type, and the position of the next character to read.
-- @param s The string being scanned.
-- @param startPos The position in the string at which to start scanning.
-- @return object, int The object (true, false or nil) and the position at which the next character should be
-- scanned.
function decode_scanConstant(s, startPos)
local consts = { ["true"] = true, ["false"] = false, ["null"] = nil }
local constNames = {"true","false","null"}
for i,k in pairs(constNames) do
if string.sub(s,startPos, startPos + string.len(k) -1 )==k then
return consts[k], startPos + string.len(k)
end
end
assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)
end
--- Scans a number from the JSON encoded string.
-- (in fact, also is able to scan numeric +- eqns, which is not
-- in the JSON spec.)
-- Returns the number, and the position of the next character
-- after the number.
-- @param s The string being scanned.
-- @param startPos The position at which to start scanning.
-- @return number, int The extracted number and the position of the next character to scan.
function decode_scanNumber(s,startPos)
local endPos = startPos+1
local stringLen = string.len(s)
local acceptableChars = "+-0123456789.e"
while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true)
and endPos<=stringLen
) do
endPos = endPos + 1
end
local stringValue = 'return ' .. string.sub(s,startPos, endPos-1)
local stringEval = loadstring(stringValue)
assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)
return stringEval(), endPos
end
--- Scans a JSON object into a Lua object.
-- startPos begins at the start of the object.
-- Returns the object and the next starting position.
-- @param s The string being scanned.
-- @param startPos The starting position of the scan.
-- @return table, int The scanned object as a table and the position of the next character to scan.
function decode_scanObject(s,startPos)
local object = {}
local stringLen = string.len(s)
local key, value
assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s)
startPos = startPos + 1
repeat
startPos = decode_scanWhitespace(s,startPos)
assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.')
local curChar = string.sub(s,startPos,startPos)
if (curChar=='}') then
return object,startPos+1
end
if (curChar==',') then
startPos = decode_scanWhitespace(s,startPos+1)
end
assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.')
-- Scan the key
key, startPos = json.decode(s,startPos)
assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
startPos = decode_scanWhitespace(s,startPos)
assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos)
startPos = decode_scanWhitespace(s,startPos+1)
assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)
value, startPos = json.decode(s,startPos)
object[key]=value
until false -- infinite loop while key-value pairs are found
end
-- START SoniEx2
-- Initialize some things used by decode_scanString
-- You know, for efficiency
local escapeSequences = {
["\\t"] = "\t",
["\\f"] = "\f",
["\\r"] = "\r",
["\\n"] = "\n",
["\\b"] = "\b"
}
setmetatable(escapeSequences, {__index = function(t,k)
-- skip "\" aka strip escape
return string.sub(k,2)
end})
-- END SoniEx2
--- Scans a JSON string from the opening inverted comma or single quote to the
-- end of the string.
-- Returns the string extracted as a Lua string,
-- and the position of the next non-string character
-- (after the closing inverted comma or single quote).
-- @param s The string being scanned.
-- @param startPos The starting position of the scan.
-- @return string, int The extracted string as a Lua string, and the next character to parse.
function decode_scanString(s,startPos)
assert(startPos, 'decode_scanString(..) called without start position')
local startChar = string.sub(s,startPos,startPos)
-- START SoniEx2
-- PS: I don't think single quotes are valid JSON
assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string')
--assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
local t = {}
local i,j = startPos,startPos
while string.find(s, startChar, j+1) ~= j+1 do
local oldj = j
i,j = string.find(s, "\\.", j+1)
local x,y = string.find(s, startChar, oldj+1)
if not i or x < i then
i,j = x,y-1
end
table.insert(t, string.sub(s, oldj+1, i-1))
if string.sub(s, i, j) == "\\u" then
local a = string.sub(s,j+1,j+4)
j = j + 4
local n = tonumber(a, 16)
assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j)
-- math.floor(x/2^y) == lazy right shift
-- a % 2^b == bitwise_and(a, (2^b)-1)
-- 64 = 2^6
-- 4096 = 2^12 (or 2^6 * 2^6)
local x
if n < 0x80 then
x = string.char(n % 0x80)
elseif n < 0x800 then
-- [110x xxxx] [10xx xxxx]
x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40))
else
-- [1110 xxxx] [10xx xxxx] [10xx xxxx]
x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40))
end
table.insert(t, x)
else
table.insert(t, escapeSequences[string.sub(s, i, j)])
end
end
table.insert(t,string.sub(j, j+1))
assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")")
return table.concat(t,""), j+2
-- END SoniEx2
end
--- Scans a JSON string skipping all whitespace from the current start position.
-- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.
-- @param s The string being scanned
-- @param startPos The starting position where we should begin removing whitespace.
-- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string
-- was reached.
function decode_scanWhitespace(s,startPos)
local whitespace=" \n\r\t"
local stringLen = string.len(s)
while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do
startPos = startPos + 1
end
return startPos
end
--- Encodes a string to be JSON-compatible.
-- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)
-- @param s The string to return as a JSON encoded (i.e. backquoted string)
-- @return The string appropriately escaped.
local escapeList = {
['"'] = '\\"',
['\\'] = '\\\\',
['/'] = '\\/',
['\b'] = '\\b',
['\f'] = '\\f',
['\n'] = '\\n',
['\r'] = '\\r',
['\t'] = '\\t'
}
function json_private.encodeString(s)
local s = tostring(s)
return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat
end
-- Determines whether the given Lua type is an array or a table / dictionary.
-- We consider any table an array if it has indexes 1..n for its n items, and no
-- other data in the table.
-- I think this method is currently a little 'flaky', but can't think of a good way around it yet...
-- @param t The table to evaluate as an array
-- @return boolean, number True if the table can be represented as an array, false otherwise. If true,
-- the second returned value is the maximum
-- number of indexed elements in the array.
function isArray(t)
-- Next we count all the elements, ensuring that any non-indexed elements are not-encodable
-- (with the possible exception of 'n')
local maxIndex = 0
for k,v in pairs(t) do
if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair
if (not isEncodable(v)) then return false end -- All array elements must be encodable
maxIndex = math.max(maxIndex,k)
else
if (k=='n') then
if v ~= table.getn(t) then return false end -- False if n does not hold the number of elements
else -- Else of (k=='n')
if isEncodable(v) then return false end
end -- End of (k~='n')
end -- End of k,v not an indexed pair
end -- End of loop across all pairs
return true, maxIndex
end
--- Determines whether the given Lua object / table / variable can be JSON encoded. The only
-- types that are JSON encodable are: string, boolean, number, nil, table and json.null.
-- In this implementation, all other types are ignored.
-- @param o The object to examine.
-- @return boolean True if the object should be JSON encoded, false if it should be ignored.
function isEncodable(o)
local t = type(o)
return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or (t=='function' and o==null)
end
return json

View File

@ -30,6 +30,7 @@ local Paint = require "util.paint"
local Utils = require "util.utils"
local Settings = require "util.settings"
local Data = require "data.data"
local Pokemon = require "storage.pokemon"
local hasAlreadyStartedPlaying = false
@ -48,17 +49,16 @@ local function resetAll()
Bridge.reset()
oldSeconds = 0
running = false
-- client.speedmode = 200
if CUSTOM_SEED then
Strategies.seed = CUSTOM_SEED
Data.run.seed = CUSTOM_SEED
Strategies.replay = true
p("RUNNING WITH A FIXED SEED ("..NIDORAN_NAME.." "..Strategies.seed.."), every run will play out identically!", true)
p("RUNNING WITH A FIXED SEED ("..NIDORAN_NAME.." "..Data.run.seed.."), every run will play out identically!", true)
else
Strategies.seed = os.time()
print("PokeBot v"..VERSION..": starting a new run with seed "..Strategies.seed)
Data.run.seed = os.time()
print("PokeBot v"..VERSION..": starting a new run with seed "..Data.run.seed)
end
math.randomseed(Strategies.seed)
math.randomseed(Data.run.seed)
end
-- EXECUTE

View File

@ -1,5 +1,7 @@
local Bridge = {}
local json = require("external.json")
local socket
if INTERNAL then
socket = require("socket")
@ -132,6 +134,13 @@ function Bridge.encounter()
send("encounter")
end
function Bridge.report(report)
if not STREAMING_MODE then
print(json.encode(report))
end
send("report", json.encode(report))
end
function Bridge.reset()
send("reset")
timeStopped = false

View File

@ -8,6 +8,8 @@ local Input = require "util.input"
local Memory = require "util.memory"
local Menu = require "util.menu"
local Data = require "data.data"
local START_WAIT = 99
local yellow = YELLOW
@ -91,6 +93,7 @@ function Settings.pollForResponse(forcedName)
response = forcedName
elseif response then
response = tonumber(response)
Data.run.voted_for_name = true
end
if response then
Bridge.polling = false

View File

@ -79,6 +79,20 @@ function Utils.nextCircularIndex(index, direction, totalCount)
return nextIndex
end
function Utils.increment(amount)
if not amount then
return 1
end
return amount + 1
end
function Utils.multiplyString(string, times)
for i=1, times-1 do
string = string.." "..string
end
return string
end
-- GAME
function Utils.canPotionWith(potion, forDamage, curr_hp, max_hp)