PokeBot/ai/control.lua

404 lines
10 KiB
Lua
Raw Normal View History

2015-04-06 01:18:46 -07:00
local Control = {}
2014-07-12 18:47:39 -07:00
local Battle
2015-04-06 01:18:46 -07:00
local Combat = require "ai.combat"
local Strategies
2014-07-12 18:47:39 -07:00
2015-04-24 21:34:49 -07:00
local Data = require "data.data"
2015-04-06 01:18:46 -07:00
local Bridge = require "util.bridge"
local Memory = require "util.memory"
2015-04-24 21:03:06 -07:00
local Menu = require "util.menu"
2015-04-06 01:18:46 -07:00
local Paint = require "util.paint"
local Utils = require "util.utils"
2014-07-12 18:47:39 -07:00
2015-04-06 01:18:46 -07:00
local Inventory = require "storage.inventory"
local Pokemon = require "storage.pokemon"
2014-07-12 18:47:39 -07:00
local potionInBattle = true
local encounters = 0
2014-07-12 18:47:39 -07:00
local canDie, shouldFight, minExp
2014-07-12 18:47:39 -07:00
local shouldCatch, attackIdx
local extraEncounter, maxEncounters
2015-04-06 00:50:00 -07:00
local battleYolo
2015-04-17 13:40:56 -07:00
local encountersSection
2014-07-12 18:47:39 -07:00
2015-04-06 01:18:46 -07:00
Control.areaName = "Unknown"
Control.getMoonExp = true
2015-04-06 01:18:46 -07:00
Control.yolo = false
2014-07-12 18:47:39 -07:00
local function withinOneKill(forExp)
return Pokemon.getExp() + 80 > forExp
end
2014-07-12 18:47:39 -07:00
local controlFunctions = {
2015-04-05 18:50:30 -07:00
a = function(data)
2015-04-06 01:18:46 -07:00
Control.areaName = data.a
2015-04-05 18:50:30 -07:00
return true
end,
2014-07-12 18:47:39 -07:00
potion = function(data)
if data.b ~= nil then
2015-04-06 01:18:46 -07:00
Control.battlePotion(data.b)
2014-07-12 18:47:39 -07:00
end
battleYolo = data.yolo
end,
encounters = function(data)
if RESET_FOR_TIME then
2015-04-28 00:19:04 -07:00
local limit = data.limit
2015-04-28 09:35:33 -07:00
if limit and BEAST_MODE then
2015-04-28 22:04:28 -07:00
limit = limit - math.ceil(limit * 0.3)
2015-04-28 00:19:04 -07:00
end
maxEncounters = limit
2014-07-12 18:47:39 -07:00
extraEncounter = data.extra
end
end,
pp = function(data)
2015-04-06 01:18:46 -07:00
Combat.factorPP(data.on)
2014-07-12 18:47:39 -07:00
end,
2015-04-11 10:36:22 -07:00
thrash = function(data)
Combat.setDisableThrash(data.disable)
2014-07-12 18:47:39 -07:00
end,
disableCatch = function()
shouldCatch = nil
shouldFight = nil
end,
-- RED
2014-07-12 18:47:39 -07:00
viridianExp = function()
minExp = 210
shouldFight = {{name="rattata",levels={2,3}}, {name="pidgey",levels={2}}}
2014-07-12 18:47:39 -07:00
end,
viridianBackupExp = function()
minExp = 210
shouldFight = {{name="rattata",levels={2,3}}, {name="pidgey",levels={2,3}}}
2014-07-12 18:47:39 -07:00
end,
nidoranBackupExp = function()
minExp = 210
shouldFight = {{name="rattata"}, {name="pidgey"}, {name="nidoran"}, {name="nidoranf",levels={2}}}
2014-07-12 18:47:39 -07:00
end,
2015-04-17 13:40:56 -07:00
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.canDie(false)
2015-04-24 21:34:49 -07:00
Control.getMoonExp = not Data.yellow
2015-04-29 11:37:35 -07:00
Bridge.moonGuesses(false)
end,
2014-07-12 18:47:39 -07:00
moon1Exp = function()
if Control.getMoonExp then
minExp = 2704
2015-04-28 17:31:23 -07:00
shouldFight = {{name="zubat",levels={9,10,11,12},exp=7.67}}
oneHits = true
end
2014-07-12 18:47:39 -07:00
end,
moon2Exp = function()
2015-04-27 23:23:40 -07:00
if Control.getMoonExp and Strategies.stats.nidoran then
minExp = 3011
2015-04-27 23:23:40 -07:00
local withinOne = withinOneKill(minExp)
if withinOne or Strategies.stats.nidoran.level4 then
2015-04-28 17:31:23 -07:00
shouldFight = {{name="zubat",exp=7.67}, {name="paras"}}
oneHits = not Strategies.stats.nidoran.level4 or not withinOne
2015-04-27 23:23:40 -07:00
end
end
2014-07-12 18:47:39 -07:00
end,
moon3Exp = function()
2015-04-27 23:23:40 -07:00
if Control.getMoonExp and Strategies.stats.nidoran then
minExp = 3798
2015-04-27 23:23:40 -07:00
local withinOne = withinOneKill(minExp)
if withinOne or Strategies.stats.nidoran.level4 then
2015-04-28 17:31:23 -07:00
shouldFight = {{name="zubat",exp=7.67}, {name="paras"}, {name="clefairy"}}
oneHits = not Strategies.stats.nidoran.level4 or not withinOne
2015-04-27 23:23:40 -07:00
end
end
2014-07-12 18:47:39 -07:00
end,
catchNidoran = function()
2015-04-28 00:19:04 -07:00
shouldCatch = {{name="nidoran",levels={3,4}}}
if not BEAST_MODE then
shouldCatch[2] = {name="spearow"}
end
2014-07-12 18:47:39 -07:00
end,
catchFlier = function()
2015-04-18 21:06:06 -07:00
if Pokemon.inParty("pidgey", "spearow") then
shouldCatch = {{name="sandshrew"}}
else
shouldCatch = {{name="spearow",alt="pidgey",hp=15}, {name="pidgey",alt="spearow",hp=15}}
end
2014-07-12 18:47:39 -07:00
end,
catchParas = function()
shouldCatch = {{name="paras",hp=16}}
end,
catchOddish = function()
shouldCatch = {{name="oddish",alt="paras",hp=26}}
end,
2015-04-07 05:01:40 -07:00
-- YELLOW
catchNidoranYellow = function()
shouldCatch = {{name="nidoran",levels={6}}}
2015-04-07 05:01:40 -07:00
end,
moonExpYellow = function()
minExp = 2704 --TODO
shouldFight = {{name="geodude"}, {name="clefairy",levels={12,13}}}
2015-04-07 05:01:40 -07:00
oneHits = true
end,
2015-04-18 21:06:06 -07:00
catchCutterYellow = function()
shouldCatch = {{name="sandshrew"}, {name="paras",levels={9,10,11,12}}}
2015-04-07 05:01:40 -07:00
end,
2014-07-12 18:47:39 -07:00
}
-- COMBAT
2015-04-06 01:18:46 -07:00
function Control.battlePotion(enable)
2015-04-05 18:50:30 -07:00
potionInBattle = enable
end
2015-04-06 01:18:46 -07:00
function Control.canDie(enabled)
if enabled == nil then
return canDie
end
canDie = enabled
end
2014-07-12 18:47:39 -07:00
2015-04-06 01:18:46 -07:00
function Control.shouldFight()
if not shouldFight then
2014-07-12 18:47:39 -07:00
return false
end
local expRemaining = minExp - Pokemon.getExp()
if expRemaining > 0 then
2015-04-06 01:18:46 -07:00
local oid = Memory.value("battle", "opponent_id")
local opponentLevel = Memory.value("battle", "opponent_level")
for i,encounter in ipairs(shouldFight) do
if oid == Pokemon.getID(encounter.name) and (not encounter.levels or Utils.match(opponentLevel, encounter.levels)) then
if oneHits then
2015-04-06 01:18:46 -07:00
local move = Combat.bestMove()
if move and move.maxDamage * 0.925 < Memory.double("battle", "opponent_hp") then
2014-07-12 18:47:39 -07:00
return false
end
end
2015-04-28 17:31:23 -07:00
if expRemaining < 100 and encounter.exp then
local getExp = encounter.exp * opponentLevel
return getExp >= expRemaining
end
2014-07-12 18:47:39 -07:00
return true
end
end
end
end
2015-04-06 01:18:46 -07:00
function Control.canCatch(partySize)
if not partySize then
2015-04-06 01:18:46 -07:00
partySize = Memory.value("player", "party_size")
2014-07-12 18:47:39 -07:00
end
2015-04-06 01:18:46 -07:00
local pokeballs = Inventory.count("pokeball")
2015-04-24 21:34:49 -07:00
local minimumCount = (Data.yellow and 3 or 4) - partySize
if pokeballs < minimumCount then
2015-04-24 21:34:49 -07:00
if Data.yellow and Pokemon.inParty("nidoran", "nidorino", "nidoking") and Pokemon.inParty("pidgey", "spearow") then
return false
end
2015-04-17 13:40:56 -07:00
Strategies.reset("pokeballs", "Not enough PokeBalls", pokeballs)
2014-07-12 18:47:39 -07:00
return false
end
return true
end
2015-04-06 01:18:46 -07:00
function Control.shouldCatch(partySize)
if maxEncounters and encounters > maxEncounters then
2015-04-06 01:18:46 -07:00
local extraCount = extraEncounter and Pokemon.inParty(extraEncounter)
if not extraCount or encounters > maxEncounters + 1 then
2015-04-17 13:40:56 -07:00
Strategies.reset("encounters", "Too many encounters", encounters)
2014-07-12 18:47:39 -07:00
return false
end
end
if not shouldCatch then
2014-07-12 18:47:39 -07:00
return false
end
2015-04-24 21:34:49 -07:00
if Data.yellow and not Inventory.contains("pokeball") then
2015-04-13 01:18:28 -07:00
return false
end
if not partySize then
2015-04-06 01:18:46 -07:00
partySize = Memory.value("player", "party_size")
2014-07-12 18:47:39 -07:00
end
if partySize == 4 then
2014-07-12 18:47:39 -07:00
shouldCatch = nil
return false
end
2015-04-06 01:18:46 -07:00
if not Control.canCatch(partySize) then
2014-07-12 18:47:39 -07:00
return true
end
2015-04-06 01:18:46 -07:00
local oid = Memory.value("battle", "opponent_id")
local opponentLevel = Memory.value("battle", "opponent_level")
2014-07-12 18:47:39 -07:00
for i,poke in ipairs(shouldCatch) do
2015-04-06 01:18:46 -07:00
if oid == Pokemon.getID(poke.name) and not Pokemon.inParty(poke.name, poke.alt) then
if not poke.levels or Utils.match(opponentLevel, poke.levels) then
2015-04-06 01:18:46 -07:00
local penultimate = poke.hp and Memory.double("battle", "opponent_hp") > poke.hp
if penultimate then
2015-04-06 01:18:46 -07:00
penultimate = Combat.nonKill()
2014-07-12 18:47:39 -07:00
end
if penultimate then
2015-04-09 16:53:56 -07:00
require("action.battle").fight(penultimate.midx)
2014-07-12 18:47:39 -07:00
else
2015-04-06 01:18:46 -07:00
Inventory.use("pokeball", nil, true)
2014-07-12 18:47:39 -07:00
end
return true
end
end
end
end
-- Items
2015-04-06 01:18:46 -07:00
function Control.canRecover()
return potionInBattle and (not battleYolo or not Control.yolo) and Pokemon.mainFighter()
2014-07-12 18:47:39 -07:00
end
2015-04-06 01:18:46 -07:00
function Control.set(data)
local controlFunction = controlFunctions[data.c]
if controlFunction then
controlFunction(data)
else
2015-04-24 21:34:49 -07:00
p("INVALID CONTROL", data.c, Data.gameName)
end
2014-07-12 18:47:39 -07:00
end
2015-04-06 01:18:46 -07:00
function Control.setYolo(enabled)
Control.yolo = enabled
2014-07-12 18:47:39 -07:00
end
2015-04-06 01:18:46 -07:00
function Control.setPotion(enabled)
2015-01-19 17:11:52 -08:00
potionInBattle = enabled
2014-07-12 18:47:39 -07:00
end
2015-04-06 01:18:46 -07:00
function Control.encounters()
2014-07-12 18:47:39 -07:00
return encounters
end
function Control.encounter(battleState)
if battleState > 0 then
local wildBattle = battleState == 1
local isCritical
2015-04-24 21:03:06 -07:00
if Menu.onBattleSelect() then
isCritical = false
Control.missed = false
elseif Memory.double("battle", "our_hp") == 0 then
if Memory.value("battle", "critical") == 1 then
isCritical = true
end
elseif not Control.missed then
local turnMarker = Memory.value("battle", "our_turn")
if turnMarker == 100 or turnMarker == 128 then
local isMiss = Memory.value("battle", "miss") == 1
if isMiss then
if not Control.ignoreMiss and Battle.accurateAttack and not Combat.sandAttacked() then
2015-04-17 18:24:40 -07:00
local exclaim = Strategies.deepRun and ";_; " or ""
Bridge.chat("gen 1 missed "..exclaim.."(1 in 256 chance)")
end
Control.missed = true
2015-04-17 13:40:56 -07:00
Data.increment("misses")
end
end
end
if isCritical ~= nil and isCritical ~= Control.criticaled then
Control.criticaled = isCritical
2015-04-17 13:40:56 -07:00
Data.increment("criticals")
end
if wildBattle then
local opponentAlive = Battle.opponentAlive()
if not Control.inBattle then
if opponentAlive then
Control.killedCatch = false
Control.inBattle = true
encounters = encounters + 1
Paint.wildEncounters(encounters)
Bridge.encounter()
2015-04-27 23:22:24 -07:00
Data.increment("encounters")
2015-04-17 13:40:56 -07:00
if encountersSection then
2015-04-30 12:50:38 -07:00
local sectionEncounters = Data.increment(encountersSection)
2015-04-17 13:40:56 -07:00
2015-04-22 22:12:11 -07:00
local opponent = Battle.opponent()
2015-04-30 12:50:38 -07:00
local encounterPrefix = ""
2015-04-22 22:12:11 -07:00
if opponent == "zubat" then
local zubatCount = Data.increment("encounters_zubat")
Data.run.encounters_zubat = zubatCount
2015-04-30 12:50:38 -07:00
encounterPrefix = "NightBat"
2015-04-22 22:12:11 -07:00
elseif opponent == "rattata" then
Data.run.encounters_rattata = Data.increment("encounters_rattata")
end
2015-04-30 12:50:38 -07:00
if encountersSection == "encounters_moon" and STREAMING_MODE then
Bridge.chat(encounterPrefix.." "..sectionEncounters, true)
end
end
end
else
if not opponentAlive and shouldCatch and not Control.killedCatch then
local gottaCatchEm = {"pidgey", "spearow", "paras", "oddish"}
local opponent = Battle.opponent()
for i,catch in ipairs(gottaCatchEm) do
if opponent == catch then
if not Pokemon.inParty(catch) then
local criticaled = Memory.value("battle", "critical") == 1
Bridge.chat("accidentally killed "..Utils.capitalize(catch).." with a "..(criticaled and "critical" or "high damage range").." :(")
Control.killedCatch = true
end
break
end
end
end
end
end
elseif Control.inBattle then
Control.inBattle = false
Control.escaped = Memory.value("battle", "battle_turns") == 0
2015-04-06 00:50:00 -07:00
end
2014-07-12 18:47:39 -07:00
end
2015-04-06 01:18:46 -07:00
function Control.reset()
canDie = false
2014-07-12 18:47:39 -07:00
oneHits = false
shouldCatch = nil
shouldFight = nil
extraEncounter = nil
2015-01-19 17:11:52 -08:00
potionInBattle = true
2014-07-12 18:47:39 -07:00
encounters = 0
battleYolo = false
maxEncounters = nil
Control.yolo = false
Control.inBattle = false
2015-04-15 01:38:51 -07:00
Control.preferredPotion = nil
2014-07-12 18:47:39 -07:00
end
2015-04-06 01:18:46 -07:00
function Control.init()
Battle = require("action.battle")
2015-04-24 21:34:49 -07:00
Strategies = require("ai."..Data.gameName..".strategies")
2015-04-06 00:50:00 -07:00
end
2015-04-06 01:18:46 -07:00
return Control