227 lines
5.4 KiB
Lua
227 lines
5.4 KiB
Lua
-- SETTINGS
|
|
|
|
GAME_NAME = "red" -- Only currently supported option
|
|
RESET_FOR_TIME = true -- Set to false if you just want to see the bot finish a run
|
|
|
|
local CUSTOM_SEED = nil -- Set to a known seed to replay it, or leave nil for random runs
|
|
local PAINT_ON = true -- Display contextual information while the bot runs
|
|
|
|
-- START CODE (hard hats on)
|
|
|
|
local START_WAIT = 99
|
|
local VERSION = "1.1"
|
|
|
|
YELLOW = GAME_NAME == "yellow"
|
|
INTERNAL = false
|
|
|
|
local battle = require "action.battle"
|
|
local textbox = require "action.textbox"
|
|
local walk = require "action.walk"
|
|
|
|
local combat = require "ai.combat"
|
|
local control = require "ai.control"
|
|
local strategies = require "ai.strategies"
|
|
|
|
local bridge = require "util.bridge"
|
|
local input = require "util.input"
|
|
local memory = require "util.memory"
|
|
local menu = require "util.menu"
|
|
local paint = require "util.paint"
|
|
local utils = require "util.utils"
|
|
local settings = require "util.settings"
|
|
|
|
local pokemon = require "storage.pokemon"
|
|
|
|
local hasAlreadyStartedPlaying = false
|
|
local inBattle, oldSecs
|
|
local running = true
|
|
local previousPartySize = 0
|
|
local lastHP
|
|
local criticaled = false
|
|
|
|
local function startNewAdventure()
|
|
local startMenu, withBattleStyle
|
|
if (YELLOW) then
|
|
startMenu = memory.raw(0x0F95) == 0
|
|
withBattleStyle = "battle_style"
|
|
else
|
|
startMenu = memory.value("player", "name") ~= 0
|
|
end
|
|
if (startMenu and menu.getCol() ~= 0) then
|
|
if (settings.set("text_speed", "battle_animation", withBattleStyle)) then
|
|
menu.select(0)
|
|
end
|
|
elseif (math.random(0, START_WAIT) == 0) then
|
|
input.press("Start")
|
|
end
|
|
end
|
|
|
|
local function choosePlayerNames()
|
|
local name
|
|
if (memory.value("player", "name2") == 80) then
|
|
name = "E"
|
|
else
|
|
name = "B"
|
|
end
|
|
textbox.name(name, true)
|
|
end
|
|
|
|
local function pollForResponse()
|
|
local response = bridge.process()
|
|
if (response) then
|
|
bridge.polling = false
|
|
textbox.setName(tonumber(response))
|
|
end
|
|
end
|
|
|
|
local function resetAll()
|
|
strategies.softReset()
|
|
combat.reset()
|
|
control.reset()
|
|
walk.reset()
|
|
paint.reset()
|
|
bridge.reset()
|
|
oldSecs = 0
|
|
running = false
|
|
previousPartySize = 0
|
|
-- client.speedmode = 200
|
|
|
|
if (CUSTOM_SEED) then
|
|
strategies.seed = CUSTOM_SEED
|
|
print("RUNNING WITH A FIXED SEED ("..strategies.seed.."), every run will play out identically!")
|
|
else
|
|
strategies.seed = os.time()
|
|
end
|
|
math.randomseed(strategies.seed)
|
|
end
|
|
|
|
-- Execute
|
|
|
|
print("Welcome to PokeBot "..GAME_NAME.." version "..VERSION)
|
|
STREAMING_MODE = not walk.init()
|
|
if STREAMING_MODE then
|
|
RESET_FOR_TIME = true
|
|
end
|
|
-- STREAMING_MODE = false --TODO disable
|
|
if (CUSTOM_SEED) then
|
|
client.reboot_core()
|
|
else
|
|
hasAlreadyStartedPlaying = utils.ingame()
|
|
end
|
|
|
|
strategies.init(hasAlreadyStartedPlaying)
|
|
if (RESET_FOR_TIME and hasAlreadyStartedPlaying) then
|
|
RESET_FOR_TIME = false
|
|
print("Disabling time-limit resets as the game is already running. Please reset the emulator and restart the script if you'd like to go for a fast time.")
|
|
end
|
|
if (STREAMING_MODE) then
|
|
bridge.init()
|
|
else
|
|
input.setDebug(true)
|
|
end
|
|
|
|
-- Main loop
|
|
|
|
local previousMap
|
|
|
|
while true do
|
|
local currentMap = memory.value("game", "map")
|
|
if (currentMap ~= previousMap) then
|
|
input.clear()
|
|
previousMap = currentMap
|
|
end
|
|
if (strategies.frames) then
|
|
if (memory.value("game", "battle") == 0) then
|
|
strategies.frames = strategies.frames + 1
|
|
end
|
|
gui.text(0, 80, strategies.frames)
|
|
end
|
|
if (bridge.polling) then
|
|
pollForResponse()
|
|
end
|
|
|
|
if (not input.update()) then
|
|
if (not utils.ingame()) then
|
|
if (currentMap == 0) then
|
|
if (running) then
|
|
if (not hasAlreadyStartedPlaying) then
|
|
client.reboot_core()
|
|
hasAlreadyStartedPlaying = true
|
|
else
|
|
resetAll()
|
|
end
|
|
else
|
|
startNewAdventure()
|
|
end
|
|
else
|
|
if (not running) then
|
|
bridge.liveSplit()
|
|
running = true
|
|
end
|
|
choosePlayerNames()
|
|
end
|
|
else
|
|
local battleState = memory.value("game", "battle")
|
|
if (battleState > 0) then
|
|
if (battleState == 1) then
|
|
if (not inBattle) then
|
|
control.wildEncounter()
|
|
if (strategies.moonEncounters) then
|
|
strategies.moonEncounters = strategies.moonEncounters + 1
|
|
end
|
|
inBattle = true
|
|
end
|
|
end
|
|
local isCritical
|
|
local battleMenu = memory.value("battle", "menu")
|
|
if (battleMenu == 94) then
|
|
isCritical = false
|
|
elseif (memory.double("battle", "our_hp") == 0) then
|
|
if (memory.value("battle", "critical") == 1) then
|
|
isCritical = true
|
|
end
|
|
end
|
|
if (isCritical ~= nil and isCritical ~= criticaled) then
|
|
criticaled = isCritical
|
|
strategies.criticaled = criticaled
|
|
end
|
|
else
|
|
inBattle = false
|
|
end
|
|
local currentHP = pokemon.index(0, "hp")
|
|
-- if (currentHP ~= lastHP) then
|
|
-- bridge.hp(currentHP, pokemon.index(0, "max_hp"))
|
|
-- lastHP = currentHP
|
|
-- end
|
|
if (currentHP == 0 and not control.canDie() and pokemon.index(0) > 0) then
|
|
strategies.death(currentMap)
|
|
elseif (walk.strategy) then
|
|
if (strategies.execute(walk.strategy)) then
|
|
walk.traverse(currentMap)
|
|
end
|
|
elseif (battleState > 0) then
|
|
if (not control.shouldCatch(partySize)) then
|
|
battle.automate()
|
|
end
|
|
elseif (textbox.handle()) then
|
|
walk.traverse(currentMap)
|
|
end
|
|
end
|
|
end
|
|
|
|
if (STREAMING_MODE) then
|
|
local newSecs = memory.raw(0xDA44)
|
|
if (newSecs ~= oldSecs and (newSecs > 0 or memory.raw(0xDA45) > 0)) then
|
|
bridge.time(paint.elapsedTime())
|
|
oldSecs = newSecs
|
|
end
|
|
elseif (PAINT_ON) then
|
|
paint.draw(currentMap)
|
|
end
|
|
|
|
input.advance()
|
|
emu.frameadvance()
|
|
end
|
|
|
|
bridge.close()
|