First Commit
First Commit, Alpha version, Will play up to first battle
This commit is contained in:
parent
85f6a9afa2
commit
c8f5de6715
|
@ -0,0 +1,296 @@
|
||||||
|
local Battle = {}
|
||||||
|
|
||||||
|
local Textbox = require "action.textbox"
|
||||||
|
|
||||||
|
local Combat = require "ai.combat"
|
||||||
|
local Control = require "ai.control"
|
||||||
|
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Menu = require "util.menu"
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
|
||||||
|
local Inventory = require "storage.inventory"
|
||||||
|
local Pokemon = require "storage.pokemon"
|
||||||
|
|
||||||
|
-- HELPERS
|
||||||
|
|
||||||
|
local function potionsForHit(potion, curr_hp, max_hp)
|
||||||
|
if not potion then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local ours, killAmount = Combat.inKillRange()
|
||||||
|
if ours then
|
||||||
|
return Utils.canPotionWith(potion, killAmount, curr_hp, max_hp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function recover()
|
||||||
|
if Control.canRecover() then
|
||||||
|
local currentHP = Pokemon.index(0, "hp")
|
||||||
|
if currentHP > 0 then
|
||||||
|
local maxHP = Pokemon.index(0, "max_hp")
|
||||||
|
if currentHP < maxHP then
|
||||||
|
local first, second
|
||||||
|
if potionIn == "full" then
|
||||||
|
first, second = "full_restore", "super_potion"
|
||||||
|
if maxHP - currentHP > 54 then
|
||||||
|
first = "full_restore"
|
||||||
|
second = "super_potion"
|
||||||
|
else
|
||||||
|
first = "super_potion"
|
||||||
|
second = "full_restore"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if maxHP - currentHP > 22 then
|
||||||
|
first = "super_potion"
|
||||||
|
second = "potion"
|
||||||
|
else
|
||||||
|
first = "potion"
|
||||||
|
second = "super_potion"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local potion = Inventory.contains(first, second)
|
||||||
|
if potionsForHit(potion, currentHP, maxHP) then
|
||||||
|
Inventory.use(potion, nil, true)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--[[if Memory.value("battle", "paralyzed") == 64 then
|
||||||
|
local heals = Inventory.contains("paralyze_heal", "full_restore")
|
||||||
|
if heals then
|
||||||
|
Inventory.use(heals, nil, true)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
end
|
||||||
|
|
||||||
|
local function openBattleMenu()
|
||||||
|
--if Memory.value("battle", "text") == 1 then
|
||||||
|
if Memory.value("battle", "text") == 3 then
|
||||||
|
Input.cancel()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local battleMenu = Memory.value("battle", "menu")
|
||||||
|
--local col = Menu.getCol()
|
||||||
|
--if battleMenu == 106 or (battleMenu == 94 and col == 5) then
|
||||||
|
if battleMenu == 106 then
|
||||||
|
return true
|
||||||
|
--elseif battleMenu == 94 then
|
||||||
|
elseif battleMenu == 186 then
|
||||||
|
local rowSelected = Memory.value("battle", "menuY")
|
||||||
|
local columnSelected = Memory.value("battle", "menuX")
|
||||||
|
if columnSelected == 0 then
|
||||||
|
if rowSelected == 1 then
|
||||||
|
Input.press("Up")
|
||||||
|
else
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("Left")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("B")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function attack(attackIndex)
|
||||||
|
if Memory.double("battle", "opponent_hp") < 1 then
|
||||||
|
Input.cancel()
|
||||||
|
elseif openBattleMenu() then
|
||||||
|
--Menu.select(attackIndex, true, false, false, false, 3)
|
||||||
|
Menu.select(attackIndex, true, false, false, 3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function movePP(name)
|
||||||
|
local midx = Pokemon.battleMove(name)
|
||||||
|
if not midx then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
--return Memory.raw(0x102C + midx)
|
||||||
|
return Memory.raw(0x0634 + midx)
|
||||||
|
end
|
||||||
|
Battle.pp = movePP
|
||||||
|
|
||||||
|
-- UTILS
|
||||||
|
|
||||||
|
--[[function Battle.swapMove(sidx, fidx)
|
||||||
|
if openBattleMenu() then
|
||||||
|
local selection = Memory.value("menu", "selection_mode")
|
||||||
|
local swapSelect
|
||||||
|
if selection == sidx then
|
||||||
|
swapSelect = fidx
|
||||||
|
else
|
||||||
|
swapSelect = sidx
|
||||||
|
end
|
||||||
|
if Menu.select(swapSelect, false, false, nil, true, 3) then
|
||||||
|
Input.press("Select")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
|
function Battle.isActive()
|
||||||
|
return Memory.value("game", "battle") > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Battle.isTrainer()
|
||||||
|
local battleType = Memory.value("game", "battle")
|
||||||
|
if battleType == 2 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if battleType == 1 then
|
||||||
|
Battle.handle()
|
||||||
|
else
|
||||||
|
Textbox.handle()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Battle.opponent()
|
||||||
|
return Pokemon.getName(Memory.value("battle", "opponent_id"))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- HANDLE
|
||||||
|
|
||||||
|
function Battle.run()
|
||||||
|
if Memory.double("battle", "opponent_hp") < 1 then
|
||||||
|
Input.cancel()
|
||||||
|
--elseif Memory.value("battle", "menu") ~= 94 then
|
||||||
|
elseif Memory.value("battle", "menu") ~= 186 then
|
||||||
|
--if Memory.value("menu", "text_length") == 127 then
|
||||||
|
-- Input.press("B")
|
||||||
|
--else
|
||||||
|
Input.press("B", 2)
|
||||||
|
--Input.cancel()
|
||||||
|
--end
|
||||||
|
elseif Memory.value("battle", "menu") == 186 then
|
||||||
|
--elseif Textbox.handle() then
|
||||||
|
--local rowSelected = Memory.value("battle", "menuY")
|
||||||
|
--local columnSelected = Memory.value("battle", "menuX")
|
||||||
|
--local selected = Memory.value("menu", "selection")
|
||||||
|
--if selected == 239 then
|
||||||
|
--if rowSelected == 2 and columnSelected == 2 then
|
||||||
|
-- Input.press("A", 2)
|
||||||
|
--else
|
||||||
|
Input.escape()
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Battle.handle()
|
||||||
|
--if not Control.shouldCatch() then
|
||||||
|
--if Control.shouldFight() then
|
||||||
|
-- Battle.fight()
|
||||||
|
--else
|
||||||
|
Battle.run()
|
||||||
|
--end
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Battle.handleWild()
|
||||||
|
if Memory.value("game", "battle") ~= 1 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Battle.handle()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Battle.fight(move, skipBuffs)
|
||||||
|
if move then
|
||||||
|
if type(move) ~= "number" then
|
||||||
|
move = Pokemon.battleMove(move)
|
||||||
|
end
|
||||||
|
attack(move)
|
||||||
|
else
|
||||||
|
move = Combat.bestMove()
|
||||||
|
if move then
|
||||||
|
--Battle.accurateAttack = move.accuracy == 100
|
||||||
|
attack(move.midx)
|
||||||
|
--elseif Memory.value("menu", "text_length") == 127 then
|
||||||
|
-- Input.press("B")
|
||||||
|
else
|
||||||
|
Input.cancel()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Battle.swap(target)
|
||||||
|
local battleMenu = Memory.value("battle", "menu")
|
||||||
|
if Utils.onPokemonSelect(battleMenu) then
|
||||||
|
if Menu.getCol() == 0 then
|
||||||
|
Menu.select(Pokemon.indexOf(target), true)
|
||||||
|
else
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
elseif battleMenu == 94 then
|
||||||
|
local selected = Memory.value("menu", "selection")
|
||||||
|
if selected == 199 then
|
||||||
|
Input.press("A", 2)
|
||||||
|
elseif Menu.getCol() == 9 then
|
||||||
|
Input.press("Right", 0)
|
||||||
|
else
|
||||||
|
Input.press("Up", 0)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.cancel()
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
|
function Battle.automate(moveName, skipBuffs)
|
||||||
|
--if not recover() then
|
||||||
|
local state = Memory.value("game", "battle")
|
||||||
|
if state == 0 then
|
||||||
|
Input.cancel()
|
||||||
|
else
|
||||||
|
if moveName and movePP(moveName) == 0 then
|
||||||
|
moveName = nil
|
||||||
|
end
|
||||||
|
if state == 1 then
|
||||||
|
--if Control.shouldFight() then
|
||||||
|
-- Battle.fight(moveName, skipBuffs)
|
||||||
|
--else
|
||||||
|
Battle.run()
|
||||||
|
--end
|
||||||
|
elseif state == 2 then
|
||||||
|
Battle.fight(moveName, skipBuffs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- SACRIFICE
|
||||||
|
|
||||||
|
--[[function Battle.sacrifice(...)
|
||||||
|
local sacrifice = Pokemon.getSacrifice(...)
|
||||||
|
if sacrifice then
|
||||||
|
Battle.swap(sacrifice)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Battle.redeployNidoking()
|
||||||
|
if Pokemon.isDeployed("nidoking") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local battleMenu = Memory.value("battle", "menu")
|
||||||
|
if Utils.onPokemonSelect(battleMenu) then
|
||||||
|
Menu.select(0, true)
|
||||||
|
elseif battleMenu == 95 and Menu.getCol() == 1 then
|
||||||
|
Input.press("A")
|
||||||
|
else
|
||||||
|
local __, turns = Combat.bestMove()
|
||||||
|
if turns == 1 then
|
||||||
|
if Pokemon.isDeployed("spearow") then
|
||||||
|
forced = "growl"
|
||||||
|
else
|
||||||
|
forced = "sand_attack"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Battle.automate(forced)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end]]
|
||||||
|
|
||||||
|
return Battle
|
|
@ -0,0 +1,109 @@
|
||||||
|
local Shop = {}
|
||||||
|
|
||||||
|
local Textbox = require "action.textbox"
|
||||||
|
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Menu = require "util.menu"
|
||||||
|
local Player = require "util.player"
|
||||||
|
|
||||||
|
local Inventory = require "storage.inventory"
|
||||||
|
|
||||||
|
--local yellow = YELLOW
|
||||||
|
|
||||||
|
--[[function Shop.transaction(options)
|
||||||
|
local item, itemMenu, menuIdx, quantityMenu
|
||||||
|
if options.sell then
|
||||||
|
menuIdx = 1
|
||||||
|
itemMenu = yellow and 28 or 29
|
||||||
|
quantityMenu = 158
|
||||||
|
for i,sit in ipairs(options.sell) do
|
||||||
|
local idx = Inventory.indexOf(sit.name)
|
||||||
|
if idx ~= -1 then
|
||||||
|
item = sit
|
||||||
|
item.index = idx
|
||||||
|
item.amount = Inventory.count(sit.name)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not item and options.buy then
|
||||||
|
menuIdx = 0
|
||||||
|
itemMenu = yellow and 122 or 123
|
||||||
|
quantityMenu = 161
|
||||||
|
for i,bit in ipairs(options.buy) do
|
||||||
|
local needed = (bit.amount or 1) - Inventory.count(bit.name)
|
||||||
|
if needed > 0 then
|
||||||
|
item = bit
|
||||||
|
item.amount = needed
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not item then
|
||||||
|
if not Textbox.isActive() then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Input.press("B")
|
||||||
|
elseif Player.isFacing(options.direction or "Left") then
|
||||||
|
if Textbox.isActive() then
|
||||||
|
local mainMenu = yellow and 245 or 32
|
||||||
|
if Menu.isCurrently(mainMenu, "shop") then
|
||||||
|
Menu.select(menuIdx, true, false, "shop")
|
||||||
|
elseif Menu.getCol() == 15 then
|
||||||
|
Input.press("A")
|
||||||
|
elseif Menu.isCurrently(itemMenu, "transaction") then
|
||||||
|
if Menu.select(item.index, "accelerate", true, "transaction", true) then
|
||||||
|
if Menu.isCurrently(quantityMenu, "shop") then
|
||||||
|
local currAmount = Memory.value("shop", "transaction_amount")
|
||||||
|
if Menu.balance(currAmount, item.amount, false, 99, true) then
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("B")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Player.interact(options.direction or "Left")
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Shop.vend(options)
|
||||||
|
local item
|
||||||
|
menuIdx = 0
|
||||||
|
for i,bit in ipairs(options.buy) do
|
||||||
|
local needed = (bit.amount or 1) - Inventory.count(bit.name)
|
||||||
|
if needed > 0 then
|
||||||
|
item = bit
|
||||||
|
item.buy = needed
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not item then
|
||||||
|
if not Textbox.isActive() then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Input.press("B")
|
||||||
|
elseif Player.face(options.direction) then
|
||||||
|
if Textbox.isActive() then
|
||||||
|
if Memory.value("battle", "text") > 1 and Memory.value("battle", "menu") ~= 95 then
|
||||||
|
Menu.select(item.index, true)
|
||||||
|
else
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end]]
|
||||||
|
|
||||||
|
return Shop
|
|
@ -0,0 +1,192 @@
|
||||||
|
local Textbox = {}
|
||||||
|
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Menu = require "util.menu"
|
||||||
|
|
||||||
|
local alphabet_upper = "ABCDEF .GHIJKL ,MNOPQRS TUVWXYZ "
|
||||||
|
local alphabet_lower = "abcdef .ghijkl ,mnopqrs tuvwxyz "
|
||||||
|
local alphabet_number = "01234 56789 !?<>/- _{}[] "
|
||||||
|
-- < = male symbol
|
||||||
|
-- > = female symbol
|
||||||
|
-- { or } = "
|
||||||
|
-- [ or ] = '
|
||||||
|
|
||||||
|
local TableNumber = 1
|
||||||
|
local ActualUpper = 1
|
||||||
|
|
||||||
|
local function getIndexForLetter(letter, Mode)
|
||||||
|
if Mode == "Upper" then
|
||||||
|
return alphabet_upper:find(letter, 1, true)
|
||||||
|
elseif Mode == "Lower" then
|
||||||
|
return alphabet_lower:find(letter, 1, true)
|
||||||
|
elseif Mode == "Number" then
|
||||||
|
return alphabet_number:find(letter, 1, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Textbox.name(letter, randomize)
|
||||||
|
local inputting = Memory.value("menu", "text_input")
|
||||||
|
if inputting then
|
||||||
|
-- Set vars
|
||||||
|
local lidx
|
||||||
|
local drow
|
||||||
|
local dcol
|
||||||
|
local NameTable = {}
|
||||||
|
local ColumnMax
|
||||||
|
--Get values
|
||||||
|
local crow = Memory.value("text_inputing", "row")
|
||||||
|
local ccol = Memory.value("text_inputing", "column")
|
||||||
|
local mode = Memory.value("text_inputing", "mode")
|
||||||
|
|
||||||
|
--if letter then
|
||||||
|
local StringLenght = string.len(letter)
|
||||||
|
letter:gsub(".",function(letter2)
|
||||||
|
table.insert(NameTable,letter2)
|
||||||
|
|
||||||
|
if NameTable[TableNumber] then
|
||||||
|
local Mode = "Upper"
|
||||||
|
|
||||||
|
--its a letter
|
||||||
|
if string.match(NameTable[TableNumber], '%a') then
|
||||||
|
if string.match(NameTable[TableNumber], '%u') then
|
||||||
|
Mode = "Upper"
|
||||||
|
elseif string.match(NameTable[TableNumber], '%l') then
|
||||||
|
Mode = "Lower"
|
||||||
|
end
|
||||||
|
--its a number
|
||||||
|
elseif string.match(NameTable[TableNumber], '%d') then
|
||||||
|
Mode = "Number"
|
||||||
|
--its anything but not a letter or a number
|
||||||
|
else
|
||||||
|
if string.find(alphabet_upper, NameTable[TableNumber]) ~= nil then
|
||||||
|
Mode = "Upper"
|
||||||
|
elseif string.find(alphabet_lower, NameTable[TableNumber]) ~= nil then
|
||||||
|
Mode = "Lower"
|
||||||
|
elseif string.find(alphabet_number, NameTable[TableNumber]) ~= nil then
|
||||||
|
Mode = "Number"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--Set lidx
|
||||||
|
lidx = getIndexForLetter(NameTable[TableNumber], Mode)
|
||||||
|
|
||||||
|
local Waiting = Input.isWaiting()
|
||||||
|
|
||||||
|
--Proceed
|
||||||
|
if not Waiting then
|
||||||
|
--Get/set Lower/Upper
|
||||||
|
if Mode == "Upper" and mode ~= 0 or Mode == "Lower" and mode ~= 1 or Mode == "Number" and mode ~= 2 then
|
||||||
|
if mode == 2 then
|
||||||
|
ColumnMax = 6
|
||||||
|
else
|
||||||
|
ColumnMax = 8
|
||||||
|
end
|
||||||
|
if crow ~= 0 then
|
||||||
|
Input.press("Up", 2)
|
||||||
|
elseif crow == 0 then
|
||||||
|
if ccol < ColumnMax then
|
||||||
|
Input.press("Right", 2)
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--Get/Set Letter
|
||||||
|
else
|
||||||
|
if mode == 2 then
|
||||||
|
ColumnMax = 6
|
||||||
|
else
|
||||||
|
ColumnMax = 8
|
||||||
|
end
|
||||||
|
dcol = math.fmod(lidx - 1, ColumnMax)
|
||||||
|
if ccol < dcol then
|
||||||
|
Input.press("Right", 2)
|
||||||
|
elseif ccol > dcol then
|
||||||
|
Input.press("Left", 2)
|
||||||
|
elseif ccol == dcol then
|
||||||
|
drow = math.ceil(lidx/ColumnMax)-1
|
||||||
|
if crow < drow then
|
||||||
|
Input.press("Down", 2)
|
||||||
|
elseif crow > drow then
|
||||||
|
Input.press("Up", 2)
|
||||||
|
elseif crow == drow then
|
||||||
|
Input.press("A", 2)
|
||||||
|
TableNumber = TableNumber + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local Waiting = Input.isWaiting()
|
||||||
|
|
||||||
|
if TableNumber > StringLenght and not Waiting then
|
||||||
|
if Memory.value("menu", "text_length")-7 > 0 then
|
||||||
|
if mode == 2 then
|
||||||
|
ColumnMax = 6
|
||||||
|
else
|
||||||
|
ColumnMax = 8
|
||||||
|
end
|
||||||
|
--get column/row
|
||||||
|
if crow ~= 2 and ccol ~= ColumnMax then
|
||||||
|
Input.press("Start", 2)
|
||||||
|
elseif crow == 2 and ccol == ColumnMax then
|
||||||
|
Input.press("A", 2)
|
||||||
|
TableNumber = 1
|
||||||
|
ActualUpper = 1
|
||||||
|
NameTable = {}
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--[[else
|
||||||
|
if Memory.value("menu", "text_length")-7 > 0 then
|
||||||
|
Input.press("Start")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
lidx = nidoIdx
|
||||||
|
|
||||||
|
crow = Memory.value("menu", "input_row")
|
||||||
|
drow = math.ceil(lidx / 9)
|
||||||
|
if Menu.balance(crow, drow, true, 6, true) then
|
||||||
|
ccol = math.floor(Memory.value("menu", "column") / 2)
|
||||||
|
dcol = math.fmod(lidx - 1, 9)
|
||||||
|
if Menu.sidle(ccol, dcol, 9, true) then
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
--end
|
||||||
|
else
|
||||||
|
--Reset Values
|
||||||
|
TableNumber = 1
|
||||||
|
ActualUpper = 1
|
||||||
|
NameTable = {}
|
||||||
|
|
||||||
|
if randomize then
|
||||||
|
Input.press("A", math.random(1, 5))
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
--Input.cancel()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Textbox.isActive()
|
||||||
|
local Active = false
|
||||||
|
--if Memory.value("game", "textbox") == 1 or Memory.value("game", "textboxing") == 1 then
|
||||||
|
if Memory.value("game", "textbox") > 0 then
|
||||||
|
Active = true
|
||||||
|
end
|
||||||
|
return Active
|
||||||
|
end
|
||||||
|
|
||||||
|
function Textbox.handle()
|
||||||
|
if not Textbox.isActive() then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Input.cancel()
|
||||||
|
end
|
||||||
|
|
||||||
|
return Textbox
|
|
@ -0,0 +1,169 @@
|
||||||
|
local Walk = {}
|
||||||
|
|
||||||
|
local Control = require "ai.control"
|
||||||
|
|
||||||
|
local Paths = require "data.paths"
|
||||||
|
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Player = require "util.player"
|
||||||
|
|
||||||
|
local Pokemon = require "storage.pokemon"
|
||||||
|
|
||||||
|
|
||||||
|
local path, stepIdx, currentMap, currentMap2
|
||||||
|
local pathIdx = 0
|
||||||
|
local customIdx = 1
|
||||||
|
local customDir = 1
|
||||||
|
|
||||||
|
-- Private functions
|
||||||
|
|
||||||
|
local function setPath(index, region)
|
||||||
|
pathIdx = index
|
||||||
|
stepIdx = 2
|
||||||
|
currentMap = region
|
||||||
|
path = Paths[index]
|
||||||
|
end
|
||||||
|
|
||||||
|
local function completeStep(region)
|
||||||
|
stepIdx = stepIdx + 1
|
||||||
|
return Walk.traverse(region)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Helper functions
|
||||||
|
|
||||||
|
function dir(px, py, dx, dy)
|
||||||
|
local direction
|
||||||
|
if py > dy then
|
||||||
|
direction = "Up"
|
||||||
|
elseif py < dy then
|
||||||
|
direction = "Down"
|
||||||
|
elseif px > dx then
|
||||||
|
direction = "Left"
|
||||||
|
else
|
||||||
|
direction = "Right"
|
||||||
|
end
|
||||||
|
return direction
|
||||||
|
end
|
||||||
|
Walk.dir = dir
|
||||||
|
|
||||||
|
function step(dx, dy, slow)
|
||||||
|
local px, py = Player.position()
|
||||||
|
if px == dx and py == dy then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
--set slow mode
|
||||||
|
local SlowMode = false
|
||||||
|
if slow ~= nil and slow == true then
|
||||||
|
SlowMode = true
|
||||||
|
end
|
||||||
|
Input.press(dir(px, py, dx, dy), 0, SlowMode)
|
||||||
|
end
|
||||||
|
Walk.step = step
|
||||||
|
|
||||||
|
-- Table functions
|
||||||
|
|
||||||
|
function Walk.reset()
|
||||||
|
path = nil
|
||||||
|
pathIdx = 0
|
||||||
|
customIdx = 1
|
||||||
|
customDir = 1
|
||||||
|
currentMap = nil
|
||||||
|
currentMap2 = nil
|
||||||
|
Walk.strategy = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function Walk.init()
|
||||||
|
local region = Memory.double("game", "map")
|
||||||
|
local px, py = Player.position()
|
||||||
|
if region == 0 and px == 0 and py == 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for tries=1,2 do
|
||||||
|
for i,p in ipairs(Paths) do
|
||||||
|
if i > 2 and p[1] == region then
|
||||||
|
local origin = p[3]
|
||||||
|
if tries == 2 or (origin[1] == px and origin[2] == py) then
|
||||||
|
setPath(i, region)
|
||||||
|
return tries == 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Walk.traverse(region)
|
||||||
|
local newIndex
|
||||||
|
if not path or currentMap ~= region then
|
||||||
|
Walk.strategy = nil
|
||||||
|
customIdx = 1
|
||||||
|
customDir = 1
|
||||||
|
setPath(pathIdx + 1, region)
|
||||||
|
newIndex = pathIdx
|
||||||
|
elseif stepIdx > #path then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local tile = path[stepIdx]
|
||||||
|
if tile.c then
|
||||||
|
Control.set(tile)
|
||||||
|
return completeStep(region)
|
||||||
|
end
|
||||||
|
if tile.s then
|
||||||
|
if Walk.strategy then
|
||||||
|
Walk.strategy = nil
|
||||||
|
return completeStep(region)
|
||||||
|
end
|
||||||
|
Walk.strategy = tile
|
||||||
|
elseif step(tile[1], tile[2], tile[3]) then
|
||||||
|
Pokemon.updateParty()
|
||||||
|
return completeStep(region)
|
||||||
|
end
|
||||||
|
return newIndex
|
||||||
|
end
|
||||||
|
|
||||||
|
function Walk.canMove()
|
||||||
|
--return Memory.value("player", "moving") == 0 and Memory.value("player", "fighting") == 0
|
||||||
|
--return Memory.value("player", "moving") == 1 and Memory.value("game", "battle") == 0
|
||||||
|
return Memory.value("player", "moving") == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Custom path
|
||||||
|
|
||||||
|
--[[function Walk.invertCustom(silent)
|
||||||
|
if not silent then
|
||||||
|
customIdx = customIdx + customDir
|
||||||
|
end
|
||||||
|
customDir = customDir * -1
|
||||||
|
end
|
||||||
|
|
||||||
|
function Walk.custom(cpath, increment)
|
||||||
|
if not cpath then
|
||||||
|
customIdx = 1
|
||||||
|
customDir = 1
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if increment then
|
||||||
|
customIdx = customIdx + customDir
|
||||||
|
end
|
||||||
|
local tile = cpath[customIdx]
|
||||||
|
if not tile then
|
||||||
|
if customIdx < 1 then
|
||||||
|
customIdx = #cpath
|
||||||
|
else
|
||||||
|
customIdx = 1
|
||||||
|
end
|
||||||
|
return customIdx
|
||||||
|
end
|
||||||
|
local t1, t2 = tile[1], tile[2]
|
||||||
|
if t2 == nil then
|
||||||
|
if Player.face(t1) then
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
return t1
|
||||||
|
end
|
||||||
|
if step(t1, t2) then
|
||||||
|
customIdx = customIdx + customDir
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
|
return Walk
|
|
@ -0,0 +1,420 @@
|
||||||
|
local Combat = {}
|
||||||
|
|
||||||
|
local Movelist = require "data.movelist"
|
||||||
|
local Opponents = require "data.opponents"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Pokemon = require "storage.pokemon"
|
||||||
|
|
||||||
|
local damageMultiplier = { -- http://bulbapedia.bulbagarden.net/wiki/Type_chart#Generation_II
|
||||||
|
normal = {normal=1.0, fighting=1.0, flying=1.0, poison=1.0, ground=1.0, rock=0.5, bug=1.0, ghost=0.0, steel=0.5, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=1.0, ice=1.0, dragon=1.0, dark=1.0, },
|
||||||
|
fighting = {normal=2.0, fighting=1.0, flying=0.5, poison=0.5, ground=1.0, rock=2.0, bug=0.5, ghost=0.0, steel=2.0, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=0.5, ice=2.0, dragon=1.0, dark=2.0, },
|
||||||
|
flying = {normal=1.0, fighting=2.0, flying=1.0, poison=1.0, ground=1.0, rock=0.5, bug=2.0, ghost=1.0, steel=0.5, fire=1.0, water=1.0, grass=2.0, electric=0.5, psychic=1.0, ice=1.0, dragon=1.0, dark=1.0, },
|
||||||
|
poison = {normal=1.0, fighting=1.0, flying=1.0, poison=0.5, ground=0.5, rock=0.5, bug=2.0, ghost=0.5, steel=0.0, fire=1.0, water=1.0, grass=2.0, electric=1.0, psychic=1.0, ice=1.0, dragon=1.0, dark=1.0, },
|
||||||
|
ground = {normal=1.0, fighting=1.0, flying=0.0, poison=2.0, ground=1.0, rock=2.0, bug=0.5, ghost=1.0, steel=2.0, fire=2.0, water=1.0, grass=0.5, electric=2.0, psychic=1.0, ice=1.0, dragon=1.0, dark=1.0, },
|
||||||
|
rock = {normal=1.0, fighting=0.5, flying=2.0, poison=1.0, ground=0.5, rock=1.0, bug=2.0, ghost=1.0, steel=0.5, fire=2.0, water=1.0, grass=1.0, electric=1.0, psychic=1.0, ice=2.0, dragon=1.0, dark=1.0, },
|
||||||
|
bug = {normal=1.0, fighting=0.5, flying=0.5, poison=2.0, ground=1.0, rock=1.0, bug=1.0, ghost=0.5, steel=0.5, fire=0.5, water=1.0, grass=2.0, electric=1.0, psychic=2.0, ice=1.0, dragon=1.0, dark=2.0, },
|
||||||
|
ghost = {normal=0.0, fighting=1.0, flying=1.0, poison=1.0, ground=1.0, rock=1.0, bug=1.0, ghost=2.0, steel=1.0, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=0.0, ice=1.0, dragon=1.0, dark=0.5, },
|
||||||
|
steel = {normal=1.0, fighting=1.0, flying=1.0, poison=1.0, ground=1.0, rock=2.0, bug=1.0, ghost=1.0, steel=0.5, fire=0.5, water=0.5, grass=1.0, electric=0.5, psychic=1.0, ice=2.0, dragon=1.0, dark=1.0, },
|
||||||
|
fire = {normal=1.0, fighting=1.0, flying=1.0, poison=1.0, ground=1.0, rock=0.5, bug=2.0, ghost=1.0, steel=2.0, fire=0.5, water=0.5, grass=2.0, electric=1.0, psychic=1.0, ice=2.0, dragon=0.5, dark=1.0, },
|
||||||
|
water = {normal=1.0, fighting=1.0, flying=1.0, poison=1.0, ground=2.0, rock=2.0, bug=1.0, ghost=1.0, steel=1.0, fire=2.0, water=0.5, grass=0.5, electric=1.0, psychic=1.0, ice=1.0, dragon=0.5, dark=1.0, },
|
||||||
|
grass = {normal=1.0, fighting=1.0, flying=0.5, poison=0.5, ground=2.0, rock=2.0, bug=0.5, ghost=1.0, steel=0.5, fire=0.5, water=2.0, grass=0.5, electric=1.0, psychic=1.0, ice=1.0, dragon=0.5, dark=1.0, },
|
||||||
|
electric = {normal=1.0, fighting=1.0, flying=2.0, poison=1.0, ground=0.0, rock=1.0, bug=1.0, ghost=1.0, steel=1.0, fire=1.0, water=2.0, grass=0.5, electric=0.5, psychic=1.0, ice=1.0, dragon=0.5, dark=1.0, },
|
||||||
|
psychic = {normal=1.0, fighting=2.0, flying=1.0, poison=2.0, ground=1.0, rock=1.0, bug=1.0, ghost=1.0, steel=0.5, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=0.5, ice=1.0, dragon=1.0, dark=0.0, },
|
||||||
|
ice = {normal=1.0, fighting=1.0, flying=2.0, poison=1.0, ground=2.0, rock=1.0, bug=1.0, ghost=1.0, steel=0.5, fire=1.0, water=0.5, grass=2.0, electric=1.0, psychic=1.0, ice=0.5, dragon=2.0, dark=1.0, },
|
||||||
|
dragon = {normal=1.0, fighting=1.0, flying=1.0, poison=1.0, ground=1.0, rock=1.0, bug=1.0, ghost=1.0, steel=0.5, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=1.0, ice=1.0, dragon=2.0, dark=1.0, },
|
||||||
|
dark = {normal=1.0, fighting=0.5, flying=1.0, poison=1.0, ground=1.0, rock=1.0, bug=1.0, ghost=2.0, steel=1.0, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=2.0, ice=1.0, dragon=1.0, dark=0.5, },
|
||||||
|
}
|
||||||
|
|
||||||
|
local types = {}
|
||||||
|
types[0] = "normal"
|
||||||
|
types[1] = "fighting"
|
||||||
|
types[2] = "flying"
|
||||||
|
types[3] = "poison"
|
||||||
|
types[4] = "ground"
|
||||||
|
types[5] = "rock"
|
||||||
|
types[6] = "bug"
|
||||||
|
types[7] = "ghost" --??
|
||||||
|
types[8] = "steel" --??
|
||||||
|
|
||||||
|
types[10] = "fire"
|
||||||
|
types[11] = "water"
|
||||||
|
types[12] = "grass"
|
||||||
|
types[13] = "electric"
|
||||||
|
types[14] = "psychic"
|
||||||
|
types[15] = "ice"
|
||||||
|
types[16] = "dragon"
|
||||||
|
types[17] = "dark"
|
||||||
|
|
||||||
|
local savedEncounters = {}
|
||||||
|
local enablePP = false
|
||||||
|
|
||||||
|
local floor = math.floor
|
||||||
|
|
||||||
|
--[[local function isDisabled(mid)
|
||||||
|
return mid == Memory.value("battle", "disabled")
|
||||||
|
end
|
||||||
|
Combat.isDisabled = isDisabled]]
|
||||||
|
|
||||||
|
local function calcDamage(move, attacker, defender, rng)
|
||||||
|
if move.fixed then
|
||||||
|
return move.fixed, move.fixed
|
||||||
|
end
|
||||||
|
--[[if move.power == 0 or isDisabled(move.id) then
|
||||||
|
return 0, 0
|
||||||
|
end
|
||||||
|
if move.power > 9000 then
|
||||||
|
if Memory.value("battle", "x_accuracy") == 1 and defender.speed < attacker.speed then
|
||||||
|
return 9001, 9001
|
||||||
|
end
|
||||||
|
return 0, 0
|
||||||
|
end
|
||||||
|
if move.name == "Thrash" and Combat.disableThrash then
|
||||||
|
return 0, 0
|
||||||
|
end]]
|
||||||
|
|
||||||
|
local attFactor, defFactor
|
||||||
|
if move.special then
|
||||||
|
--attFactor, defFactor = attacker.spec, defender.spec
|
||||||
|
attFactor, defFactor = attacker.spec_att, defender.spec_def
|
||||||
|
else
|
||||||
|
attFactor, defFactor = attacker.att, defender.def
|
||||||
|
end
|
||||||
|
local damage = floor(floor(floor(2 * attacker.level / 5 + 2) * math.max(1, attFactor) * move.power / math.max(1, defFactor)) / 50) + 2
|
||||||
|
|
||||||
|
if move.move_type == attacker.type1 or move.move_type == attacker.type2 then
|
||||||
|
damage = floor(damage * 1.5) -- STAB
|
||||||
|
end
|
||||||
|
|
||||||
|
local dmp = damageMultiplier[move.move_type]
|
||||||
|
local typeEffect1, typeEffect2 = dmp[defender.type1], dmp[defender.type2]
|
||||||
|
if defender.type1 == defender.type2 then
|
||||||
|
typeEffect2 = 1
|
||||||
|
end
|
||||||
|
damage = floor(damage * typeEffect1 * typeEffect2)
|
||||||
|
if move.multiple then
|
||||||
|
damage = damage * move.multiple
|
||||||
|
end
|
||||||
|
if rng then
|
||||||
|
return damage, damage
|
||||||
|
end
|
||||||
|
return floor(damage * 217 / 255), damage
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getOpponentType(ty)
|
||||||
|
local t1 = types[Memory.value("battle", "opponent_type1")]
|
||||||
|
if ty ~= 0 then
|
||||||
|
t1 = types[Memory.value("battle", "opponent_type2")]
|
||||||
|
if not t1 then
|
||||||
|
return Memory.value("battle", "opponent_type2")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if t1 then
|
||||||
|
return t1
|
||||||
|
end
|
||||||
|
return Memory.value("battle", "opponent_type1")
|
||||||
|
end
|
||||||
|
Combat.getOpponentType = getOpponentType
|
||||||
|
|
||||||
|
function getOurType(ty)
|
||||||
|
local t1 = types[Memory.value("battle", "our_type1")]
|
||||||
|
if ty ~= 0 then
|
||||||
|
t1 = types[Memory.value("battle", "our_type2")]
|
||||||
|
if not t1 then
|
||||||
|
return Memory.value("battle", "opponent_type2")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if t1 then
|
||||||
|
return t1
|
||||||
|
end
|
||||||
|
return Memory.value("battle", "opponent_type1")
|
||||||
|
end
|
||||||
|
Combat.getOurType = getOurType
|
||||||
|
|
||||||
|
local function getMoves(who)--Get the moveset of us [0] or them [1]
|
||||||
|
local moves = {}
|
||||||
|
local base
|
||||||
|
if who == 1 then
|
||||||
|
base = Memory.value("battle", "opponent_move_id")
|
||||||
|
else
|
||||||
|
base = Memory.value("battle", "our_move_id")
|
||||||
|
end
|
||||||
|
for idx=0, 3 do
|
||||||
|
local val = Memory.raw(base + idx)
|
||||||
|
if val > 0 then
|
||||||
|
local moveTable = Movelist.get(val)
|
||||||
|
if who == 0 then
|
||||||
|
moveTable.pp = Memory.value("battle", "our_move_pp")
|
||||||
|
end
|
||||||
|
moves[idx + 1] = moveTable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return moves
|
||||||
|
end
|
||||||
|
Combat.getMoves = getMoves
|
||||||
|
|
||||||
|
local function modPlayerStats(user, enemy, move)
|
||||||
|
local effect = move.effects
|
||||||
|
if effect then
|
||||||
|
local diff = effect.diff
|
||||||
|
local hitThem = diff < 0
|
||||||
|
local stat = effect.stat
|
||||||
|
if hitThem then
|
||||||
|
enemy[stat] = math.max(2, enemy[stat] + diff)
|
||||||
|
else
|
||||||
|
user[stat] = user[stat] + diff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return user, enemy
|
||||||
|
end
|
||||||
|
|
||||||
|
local function calcBestHit(attacker, defender, ours, rng)
|
||||||
|
local bestTurns, bestMinTurns = 9001, 9001
|
||||||
|
local bestDmg = -1
|
||||||
|
local ourMaxHit
|
||||||
|
local ret = nil
|
||||||
|
for idx,move in ipairs(attacker.moves) do
|
||||||
|
if not move.pp or move.pp > 0 then
|
||||||
|
local minDmg, maxDmg = calcDamage(move, attacker, defender, rng)
|
||||||
|
if maxDmg then
|
||||||
|
local minTurns, maxTurns
|
||||||
|
if maxDmg <= 0 then
|
||||||
|
minTurns, maxTurns = 9001, 9001
|
||||||
|
else
|
||||||
|
minTurns = math.ceil(defender.hp / maxDmg)
|
||||||
|
maxTurns = math.ceil(defender.hp / minDmg)
|
||||||
|
end
|
||||||
|
if ours then
|
||||||
|
local replaces
|
||||||
|
if not ret or minTurns < bestMinTurns or maxTurns < bestTurns then
|
||||||
|
replaces = true
|
||||||
|
--elseif maxTurns == bestTurns and move.name == "Thrash" then
|
||||||
|
-- replaces = defender.hp == Memory.double("battle", "opponent_max_hp")
|
||||||
|
--elseif maxTurns == bestTurns and ret.name == "Thrash" then
|
||||||
|
-- replaces = defender.hp ~= Memory.double("battle", "opponent_max_hp")
|
||||||
|
elseif move.fast and not ret.fast then
|
||||||
|
replaces = maxTurns <= bestTurns
|
||||||
|
elseif ret.fast then
|
||||||
|
replaces = maxTurns < bestTurns
|
||||||
|
--[[elseif enablePP then
|
||||||
|
if maxTurns < 2 or maxTurns == bestMaxTurns then
|
||||||
|
if ret.name == "Earthquake" and (move.name == "Ice-Beam" or move.name == "Thunderbolt") then
|
||||||
|
replaces = true
|
||||||
|
elseif move.pp > ret.pp then
|
||||||
|
if ret.name == "Horn-Drill" then
|
||||||
|
replaces = true
|
||||||
|
elseif move.name ~= "Earthquake" then
|
||||||
|
replaces = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
elseif minDmg > bestDmg then
|
||||||
|
replaces = true
|
||||||
|
end
|
||||||
|
if replaces then
|
||||||
|
ret = move
|
||||||
|
bestMinTurns = minTurns
|
||||||
|
bestTurns = maxTurns
|
||||||
|
bestDmg = minDmg
|
||||||
|
ourMaxHit = maxDmg
|
||||||
|
end
|
||||||
|
elseif maxDmg > bestDmg then -- Opponents automatically hit max
|
||||||
|
ret = move
|
||||||
|
bestTurns = minTurns
|
||||||
|
bestDmg = maxDmg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ret then
|
||||||
|
ret.damage = bestDmg
|
||||||
|
ret.maxDamage = ourMaxHit
|
||||||
|
ret.minTurns = bestMinTurns
|
||||||
|
return ret, bestTurns
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getBestMove(ours, enemy, draw)
|
||||||
|
if enemy.hp < 1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local bm, bestUs = calcBestHit(ours, enemy, true)
|
||||||
|
local jj, bestEnemy = calcBestHit(enemy, ours, false)
|
||||||
|
if not bm then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if draw and bm.midx then
|
||||||
|
Utils.drawText(0, 35, ''..bm.midx.." "..bm.name)
|
||||||
|
end
|
||||||
|
return bm, bestUs, bestEnemy
|
||||||
|
end
|
||||||
|
|
||||||
|
local function activePokemon(preset)
|
||||||
|
local ours = {
|
||||||
|
id = Memory.value("battle", "our_id"),
|
||||||
|
level = Memory.value("battle", "our_level"),
|
||||||
|
hp = Memory.double("battle", "our_hp"),
|
||||||
|
att = Memory.double("battle", "our_attack"),
|
||||||
|
def = Memory.double("battle", "our_defense"),
|
||||||
|
--spec = Memory.double("battle", "our_special"),
|
||||||
|
spec_att = Memory.double("battle", "our_special_attack"),
|
||||||
|
spec_def = Memory.double("battle", "our_special_defense"),
|
||||||
|
speed = Memory.double("battle", "our_speed"),
|
||||||
|
type1 = getOurType(0),
|
||||||
|
type2 = getOurType(1),
|
||||||
|
moves = getMoves(0),
|
||||||
|
}
|
||||||
|
|
||||||
|
local enemy
|
||||||
|
if preset then
|
||||||
|
enemy = Opponents[preset]
|
||||||
|
local toBoost = enemy.boost
|
||||||
|
if toBoost then
|
||||||
|
--local currSpec = ours.spec
|
||||||
|
local currSpec = ours.spec_att
|
||||||
|
local booster = toBoost.mp
|
||||||
|
if (currSpec < 140) == (booster > 1) then
|
||||||
|
--ours.spec = math.floor(currSpec * booster)
|
||||||
|
ours.spec_att = math.floor(currSpec * booster)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
enemy = {
|
||||||
|
id = Memory.value("battle", "opponent_id"),
|
||||||
|
level = Memory.value("battle", "opponent_level"),
|
||||||
|
hp = Memory.double("battle", "opponent_hp"),
|
||||||
|
att = Memory.double("battle", "opponent_attack"),
|
||||||
|
def = Memory.double("battle", "opponent_defense"),
|
||||||
|
--spec = Memory.double("battle", "our_special"),
|
||||||
|
spec_att = Memory.double("battle", "our_special_attack"),
|
||||||
|
spec_def = Memory.double("battle", "our_special_defense"),
|
||||||
|
speed = Memory.double("battle", "opponent_speed"),
|
||||||
|
type1 = getOpponentType(0),
|
||||||
|
type2 = getOpponentType(1),
|
||||||
|
moves = getMoves(1),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return ours, enemy
|
||||||
|
end
|
||||||
|
Combat.activePokemon = activePokemon
|
||||||
|
|
||||||
|
local function isSleeping()
|
||||||
|
--return Memory.raw(0x116F) > 1
|
||||||
|
return Memory.value("battle", "our_status") == 14 --######################
|
||||||
|
end
|
||||||
|
Combat.isSleeping = isSleeping
|
||||||
|
|
||||||
|
local function isConfused()
|
||||||
|
--return Memory.raw(0x106B) > 0
|
||||||
|
return Memory.value("battle", "our_status") == 15 --######################
|
||||||
|
end
|
||||||
|
Combat.isConfused = isConfused
|
||||||
|
|
||||||
|
-- HP
|
||||||
|
|
||||||
|
function Combat.hp()
|
||||||
|
return Pokemon.index(0, "hp")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Combat.redHP()
|
||||||
|
return math.ceil(Pokemon.index(0, "max_hp") * 0.2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Combat.inRedBar()
|
||||||
|
return Combat.hp() <= Combat.redHP()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Combat AI
|
||||||
|
|
||||||
|
function Combat.factorPP(enabled)
|
||||||
|
enablePP = enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
function Combat.reset()
|
||||||
|
enablePP = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Combat.healthFor(opponent)
|
||||||
|
local ours, enemy = activePokemon(opponent)
|
||||||
|
local enemyAttack, turnsToDie = calcBestHit(enemy, ours, false)
|
||||||
|
return enemyAttack.damage
|
||||||
|
end
|
||||||
|
|
||||||
|
function Combat.inKillRange(draw)
|
||||||
|
local ours, enemy = activePokemon()
|
||||||
|
local enemyAttack, __ = calcBestHit(enemy, ours, false)
|
||||||
|
local __, turnsToKill = calcBestHit(ours, enemy, true)
|
||||||
|
if not turnsToKill or not enemyAttack then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if draw then
|
||||||
|
Utils.drawText(0, 21, ours.speed.." "..enemy.speed)
|
||||||
|
Utils.drawText(0, 28, turnsToDie.." "..ours.hp.." | "..turnsToKill.." "..enemy.hp)
|
||||||
|
end
|
||||||
|
local hpReq = enemyAttack.damage
|
||||||
|
local isConfused = isConfused()
|
||||||
|
if isConfused then
|
||||||
|
hpReq = hpReq + math.floor(ours.hp * 0.2)
|
||||||
|
end
|
||||||
|
if ours.hp <= hpReq then
|
||||||
|
local outsped = enemyAttack.outspeed
|
||||||
|
if outsped and outsped ~= true then
|
||||||
|
outsped = Memory.value("battle", "attack_turns") > 0
|
||||||
|
end
|
||||||
|
if outsped or isConfused or turnsToKill > 1 or ours.speed <= enemy.speed or isSleeping() then
|
||||||
|
return ours, hpReq
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getBattlePokemon()
|
||||||
|
local ours, enemy = activePokemon()
|
||||||
|
if enemy.hp == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for idx=1,4 do
|
||||||
|
local move = ours.moves[idx]
|
||||||
|
if move then
|
||||||
|
move.midx = idx
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ours, enemy
|
||||||
|
end
|
||||||
|
|
||||||
|
function Combat.nonKill()
|
||||||
|
local ours, enemy = getBattlePokemon()
|
||||||
|
if not enemy then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local bestDmg = -1
|
||||||
|
local ret = nil
|
||||||
|
for idx,move in ipairs(ours.moves) do
|
||||||
|
if not move.pp or move.pp > 0 then
|
||||||
|
local __, maxDmg = calcDamage(move, ours, enemy, true)
|
||||||
|
local threshold = maxDmg * 0.975
|
||||||
|
if threshold and threshold < enemy.hp and threshold > bestDmg then
|
||||||
|
ret = move
|
||||||
|
bestDmg = threshold
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
function Combat.bestMove()
|
||||||
|
local ours, enemy = getBattlePokemon()
|
||||||
|
if enemy then
|
||||||
|
return getBestMove(ours, enemy)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Combat.enemyAttack()
|
||||||
|
local ours, enemy = activePokemon()
|
||||||
|
if enemy.hp == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
return calcBestHit(enemy, ours, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Combat
|
|
@ -0,0 +1,300 @@
|
||||||
|
local Control = {}
|
||||||
|
|
||||||
|
local Battle
|
||||||
|
local Strategies
|
||||||
|
local Combat = require "ai.combat"
|
||||||
|
local Bridge = require "util.bridge"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Paint = require "util.paint"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
local Inventory = require "storage.inventory"
|
||||||
|
local Pokemon = require "storage.pokemon"
|
||||||
|
|
||||||
|
local potionInBattle = true
|
||||||
|
local encounters = 0
|
||||||
|
|
||||||
|
local canDie, shouldFight, minExp
|
||||||
|
local shouldCatch, attackIdx
|
||||||
|
local extraEncounter, maxEncounters
|
||||||
|
local battleYolo
|
||||||
|
|
||||||
|
Control.areaName = "Unknown"
|
||||||
|
Control.moonEncounters = nil
|
||||||
|
Control.getMoonExp = true
|
||||||
|
Control.yolo = false
|
||||||
|
|
||||||
|
--[[local function withinOneKill(forExp)
|
||||||
|
return Pokemon.getExp() + 80 > forExp
|
||||||
|
end]]
|
||||||
|
|
||||||
|
local controlFunctions = {
|
||||||
|
|
||||||
|
a = function(data)
|
||||||
|
Control.areaName = data.a
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
potion = function(data)
|
||||||
|
if data.b ~= nil then
|
||||||
|
Control.battlePotion(data.b)
|
||||||
|
end
|
||||||
|
battleYolo = data.yolo
|
||||||
|
end,
|
||||||
|
|
||||||
|
encounters = function(data)
|
||||||
|
if RESET_FOR_TIME then
|
||||||
|
maxEncounters = data.limit
|
||||||
|
extraEncounter = data.extra
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
pp = function(data)
|
||||||
|
Combat.factorPP(data.on)
|
||||||
|
end,
|
||||||
|
|
||||||
|
setThrash = function(data)
|
||||||
|
Combat.disableThrash = data.disable
|
||||||
|
end,
|
||||||
|
|
||||||
|
disableCatch = function()
|
||||||
|
shouldCatch = nil
|
||||||
|
shouldFight = nil
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- EXP
|
||||||
|
|
||||||
|
--[[viridianExp = function()
|
||||||
|
minExp = 210
|
||||||
|
shouldFight = {{name="rattata",lvl={2,3}}, {name="pidgey",lvl={2}}}
|
||||||
|
end,
|
||||||
|
|
||||||
|
viridianBackupExp = function()
|
||||||
|
minExp = 210
|
||||||
|
shouldFight = {{name="rattata",lvl={2,3}}, {name="pidgey",lvl={2,3}}}
|
||||||
|
end,
|
||||||
|
|
||||||
|
nidoranBackupExp = function()
|
||||||
|
minExp = 210
|
||||||
|
shouldFight = {{name="rattata"}, {name="pidgey"}, {name="nidoran"}, {name="nidoranf",lvl={2}}}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- CATCH
|
||||||
|
|
||||||
|
catchNidoran = function()
|
||||||
|
shouldCatch = {{name="nidoran",lvl={3,4}}, {name="spearow"}}
|
||||||
|
end,
|
||||||
|
|
||||||
|
catchFlier = function()
|
||||||
|
shouldCatch = {{name="spearow",alt="pidgey",hp=15}, {name="pidgey",alt="spearow",hp=15}}
|
||||||
|
end,]]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-- COMBAT
|
||||||
|
|
||||||
|
function Control.battlePotion(enable)
|
||||||
|
potionInBattle = enable
|
||||||
|
end
|
||||||
|
|
||||||
|
function Control.canDie(enabled)
|
||||||
|
if enabled == nil then
|
||||||
|
return canDie
|
||||||
|
end
|
||||||
|
canDie = enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
local function isNewFight()
|
||||||
|
if Memory.double("battle", "opponent_hp") == Memory.double("battle", "opponent_max_hp") then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Control.shouldFight()
|
||||||
|
if not shouldFight then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local expTotal = Pokemon.getExp()
|
||||||
|
if expTotal < minExp then
|
||||||
|
local oid = Memory.value("battle", "opponent_id")
|
||||||
|
local olvl = Memory.value("battle", "opponent_level")
|
||||||
|
for i,p in ipairs(shouldFight) do
|
||||||
|
if oid == Pokemon.getID(p.name) and (not p.lvl or Utils.match(olvl, p.lvl)) then
|
||||||
|
if oneHits then
|
||||||
|
local move = Combat.bestMove()
|
||||||
|
if move and move.maxDamage * 0.925 < Memory.double("battle", "opponent_hp") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end`]]
|
||||||
|
|
||||||
|
function Control.canCatch(partySize)
|
||||||
|
if not partySize then
|
||||||
|
partySize = Memory.value("player", "party_size")
|
||||||
|
end
|
||||||
|
local pokeballs = Inventory.count("pokeball")
|
||||||
|
--local minimumCount = 4 - partySize
|
||||||
|
local minimumCount = 1
|
||||||
|
if pokeballs < minimumCount then
|
||||||
|
Strategies.reset("Not enough PokeBalls", pokeballs)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[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)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not shouldCatch then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not partySize then
|
||||||
|
partySize = Memory.value("player", "party_size")
|
||||||
|
end
|
||||||
|
if partySize == 4 then
|
||||||
|
shouldCatch = nil
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not Control.canCatch(partySize) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local oid = Memory.value("battle", "opponent_id")
|
||||||
|
for i,poke in ipairs(shouldCatch) do
|
||||||
|
if oid == Pokemon.getID(poke.name) and not Pokemon.inParty(poke.name, poke.alt) then
|
||||||
|
if not poke.lvl or Utils.match(Memory.value("battle", "opponent_level"), poke.lvl) then
|
||||||
|
local penultimate = poke.hp and Memory.double("battle", "opponent_hp") > poke.hp
|
||||||
|
if penultimate then
|
||||||
|
penultimate = Combat.nonKill()
|
||||||
|
end
|
||||||
|
if penultimate then
|
||||||
|
require("action.battle").fight(penultimate.midx)
|
||||||
|
else
|
||||||
|
Inventory.use("pokeball", nil, true)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
|
-- Items
|
||||||
|
|
||||||
|
function Control.canRecover()
|
||||||
|
return potionInBattle and (not battleYolo or not Control.yolo)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Control.set(data)
|
||||||
|
controlFunctions[data.c](data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Control.setYolo(enabled)
|
||||||
|
Control.yolo = enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
function Control.setPotion(enabled)
|
||||||
|
potionInBattle = enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
function Control.encounters()
|
||||||
|
return encounters
|
||||||
|
end
|
||||||
|
|
||||||
|
function Control.encounter(battleState)
|
||||||
|
if battleState > 0 then
|
||||||
|
local wildBattle = false
|
||||||
|
if battleState == 1 then
|
||||||
|
wildBattle = true
|
||||||
|
end
|
||||||
|
--[[local isCritical
|
||||||
|
local battleMenu = Memory.value("battle", "menu")
|
||||||
|
if battleMenu == 94 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 Memory.value("battle", "accuracy") == 7 then
|
||||||
|
Bridge.chat("gen 1 missed :( (1 in 256 chance)")
|
||||||
|
end
|
||||||
|
Control.missed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if isCritical ~= nil and isCritical ~= Control.criticaled then
|
||||||
|
Control.criticaled = isCritical
|
||||||
|
end]]
|
||||||
|
if wildBattle then
|
||||||
|
local opponentHP = Memory.double("battle", "opponent_hp")
|
||||||
|
if not Control.inBattle then
|
||||||
|
Control.escaped = false
|
||||||
|
if opponentHP > 0 then
|
||||||
|
Control.killedCatch = false
|
||||||
|
Control.inBattle = true
|
||||||
|
encounters = encounters + 1
|
||||||
|
Paint.wildEncounters(encounters)
|
||||||
|
Bridge.encounter()
|
||||||
|
--if Control.moonEncounters then
|
||||||
|
-- Control.moonEncounters = Control.moonEncounters + 1
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
--if opponentHP == 0 and shouldCatch and not Control.killedCatch then
|
||||||
|
--if opponentHP == 0 and shouldCatch 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
|
||||||
|
-- Bridge.chat("accidentally killed "..Utils.capitalize(catch).." with a "..(isCritical and "critical" or "high damage range").." :(")
|
||||||
|
-- Control.killedCatch = true
|
||||||
|
-- end
|
||||||
|
-- break
|
||||||
|
-- end
|
||||||
|
--end
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Control.inBattle then
|
||||||
|
if Memory.value("battle", "battle_turns") == 0 then
|
||||||
|
Control.escaped = true
|
||||||
|
end
|
||||||
|
Control.inBattle = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Control.reset()
|
||||||
|
canDie = false
|
||||||
|
oneHits = false
|
||||||
|
--shouldCatch = nil
|
||||||
|
--shouldFight = nil
|
||||||
|
extraEncounter = nil
|
||||||
|
potionInBattle = true
|
||||||
|
encounters = 0
|
||||||
|
battleYolo = false
|
||||||
|
maxEncounters = nil
|
||||||
|
|
||||||
|
Control.yolo = false
|
||||||
|
Control.inBattle = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Control.init()
|
||||||
|
local LowerGameName = string.lower(GAME_NAME)
|
||||||
|
Battle = require "action.battle"
|
||||||
|
Strategies = require("ai."..LowerGameName..".strategies")
|
||||||
|
end
|
||||||
|
|
||||||
|
return Control
|
|
@ -0,0 +1,178 @@
|
||||||
|
|
||||||
|
local Combat = require "ai.combat"
|
||||||
|
local Control = require "ai.control"
|
||||||
|
local Strategies = require "ai.strategies"
|
||||||
|
|
||||||
|
local Battle = require "action.battle"
|
||||||
|
local Shop = require "action.shop"
|
||||||
|
local Textbox = require "action.textbox"
|
||||||
|
local Walk = require "action.walk"
|
||||||
|
|
||||||
|
local Bridge = require "util.bridge"
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Menu = require "util.menu"
|
||||||
|
local Player = require "util.player"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
|
||||||
|
local Inventory = require "storage.inventory"
|
||||||
|
local Pokemon = require "storage.pokemon"
|
||||||
|
|
||||||
|
local status = Strategies.status
|
||||||
|
|
||||||
|
local strategyFunctions = Strategies.functions
|
||||||
|
|
||||||
|
--local bulbasaurScl
|
||||||
|
--local UsingSTRATS = ""
|
||||||
|
|
||||||
|
-- TIME CONSTRAINTS
|
||||||
|
|
||||||
|
Strategies.timeRequirements = {
|
||||||
|
|
||||||
|
--[[charmander = function()
|
||||||
|
return 2.39
|
||||||
|
end,
|
||||||
|
|
||||||
|
pidgey = function()
|
||||||
|
local timeLimit = 7.55
|
||||||
|
return timeLimit
|
||||||
|
end,
|
||||||
|
|
||||||
|
glitch = function()
|
||||||
|
local timeLimit = 10.15
|
||||||
|
if Pokemon.inParty("pidgey") then
|
||||||
|
timeLimit = timeLimit + 0.67
|
||||||
|
end
|
||||||
|
return timeLimit
|
||||||
|
end,]]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-- HELPERS
|
||||||
|
|
||||||
|
--[[local function pidgeyDSum()
|
||||||
|
local sx, sy = Player.position()
|
||||||
|
if status.tries == nil then
|
||||||
|
if status.tries then
|
||||||
|
status.tries.idx = 1
|
||||||
|
status.tries.x, status.tries.y = sx, sy
|
||||||
|
else
|
||||||
|
status.tries = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if status.tries ~= 0 and Control.escaped then
|
||||||
|
if status.tries[status.tries.idx] == 0 then
|
||||||
|
tries.idx = tries.idx + 1
|
||||||
|
if tries.idx > 3 then
|
||||||
|
tries = 0
|
||||||
|
end
|
||||||
|
return pidgeyDSum()
|
||||||
|
end
|
||||||
|
if status.tries.x ~= sx or status.tries.y ~= sy then
|
||||||
|
status.tries[status.tries.idx] = status.tries[status.tries.idx] - 1
|
||||||
|
status.tries.x, status.tries.y = sx, sy
|
||||||
|
end
|
||||||
|
sy = 47
|
||||||
|
else
|
||||||
|
sy = 48
|
||||||
|
end
|
||||||
|
if sx == 8 then
|
||||||
|
sx = 9
|
||||||
|
else
|
||||||
|
sx = 8
|
||||||
|
end
|
||||||
|
Walk.step(sx, sy)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tackleDSum()
|
||||||
|
local sx, sy = Player.position()
|
||||||
|
if status.tries == nil then
|
||||||
|
if status.tries then
|
||||||
|
status.tries.idx = 1
|
||||||
|
status.tries.x, status.tries.y = sx, sy
|
||||||
|
else
|
||||||
|
status.tries = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if status.tries ~= 0 and Control.escaped then
|
||||||
|
if status.tries[status.tries.idx] == 0 then
|
||||||
|
tries.idx = tries.idx + 1
|
||||||
|
if tries.idx > 3 then
|
||||||
|
tries = 0
|
||||||
|
end
|
||||||
|
return tackleDSum()
|
||||||
|
end
|
||||||
|
if status.tries.x ~= sx or status.tries.y ~= sy then
|
||||||
|
status.tries[status.tries.idx] = status.tries[status.tries.idx] - 1
|
||||||
|
status.tries.x, status.tries.y = sx, sy
|
||||||
|
end
|
||||||
|
--sx = 1
|
||||||
|
--else
|
||||||
|
--sx = 2
|
||||||
|
end
|
||||||
|
if sy == 6 then
|
||||||
|
sy = 8
|
||||||
|
else
|
||||||
|
sy = 6
|
||||||
|
end
|
||||||
|
Walk.step(sx, sy)
|
||||||
|
end]]
|
||||||
|
|
||||||
|
-- STRATEGIES
|
||||||
|
|
||||||
|
local strategyFunctions = Strategies.functions
|
||||||
|
|
||||||
|
strategyFunctions.setHour = function()
|
||||||
|
if Strategies.initialize() then
|
||||||
|
status.tempDir = false
|
||||||
|
end
|
||||||
|
local Main = Memory.value("menu", "main")
|
||||||
|
local Current = Memory.value("menu", "settings_current")
|
||||||
|
local Row = Memory.value("menu", "start_menu_row")
|
||||||
|
local Hours = Memory.value("menu", "hours_row")
|
||||||
|
local Mins = Memory.value("menu", "minutes_row")
|
||||||
|
|
||||||
|
if Main == 29 then
|
||||||
|
local Waiting = Input.isWaiting()
|
||||||
|
if not Waiting then
|
||||||
|
if Current == 76 then
|
||||||
|
if Hours < GAME_HOURS then
|
||||||
|
Input.press("Right", 0)
|
||||||
|
elseif Hours > GAME_HOURS then
|
||||||
|
Input.press("Left", 0)
|
||||||
|
else
|
||||||
|
if Mins < GAME_MINUTES then
|
||||||
|
Input.press("Right", 0)
|
||||||
|
elseif Mins > GAME_MINUTES then
|
||||||
|
Input.press("Left", 0)
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Current == 78 then
|
||||||
|
if Row == 1 then
|
||||||
|
Input.press("Up", 2)
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- PROCESS
|
||||||
|
|
||||||
|
function Strategies.completeGameStrategy()
|
||||||
|
status = Strategies.status
|
||||||
|
end
|
||||||
|
|
||||||
|
function Strategies.resetGame()
|
||||||
|
--maxEtherSkip = false
|
||||||
|
status = Strategies.status
|
||||||
|
stats = Strategies.stats
|
||||||
|
end
|
||||||
|
|
||||||
|
return Strategies
|
|
@ -0,0 +1,369 @@
|
||||||
|
local Strategies = {}
|
||||||
|
|
||||||
|
local Combat = require "ai.combat"
|
||||||
|
local Control = require "ai.control"
|
||||||
|
|
||||||
|
local Battle = require "action.battle"
|
||||||
|
local Textbox = require "action.textbox"
|
||||||
|
local Walk = require "action.walk"
|
||||||
|
|
||||||
|
local Bridge = require "util.bridge"
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Menu = require "util.menu"
|
||||||
|
local Player = require "util.player"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
|
||||||
|
local Inventory = require "storage.inventory"
|
||||||
|
local Pokemon = require "storage.pokemon"
|
||||||
|
|
||||||
|
--local yellow = YELLOW
|
||||||
|
local splitNumber, splitTime = 0, 0
|
||||||
|
local resetting, itemPos1, itemPos2, itemNumber
|
||||||
|
|
||||||
|
local status = {tries = 0, canProgress = nil, initialized = false, tempDir = false}
|
||||||
|
Strategies.status = status
|
||||||
|
|
||||||
|
local strategyFunctions
|
||||||
|
|
||||||
|
-- RISK/RESET
|
||||||
|
|
||||||
|
function Strategies.getTimeRequirement(name)
|
||||||
|
return Strategies.timeRequirements[name]()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- RISK/RESET
|
||||||
|
|
||||||
|
function Strategies.hardReset(message, extra, wait)
|
||||||
|
resetting = true
|
||||||
|
if Strategies.seed then
|
||||||
|
if extra then
|
||||||
|
extra = extra.." | "..Strategies.seed
|
||||||
|
else
|
||||||
|
extra = Strategies.seed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--Reset values
|
||||||
|
--RUNNING4CONTINUE = false
|
||||||
|
--RUNNING4NEWGAME = true
|
||||||
|
|
||||||
|
Bridge.chat(message, extra)
|
||||||
|
if wait and INTERNAL and not STREAMING_MODE then
|
||||||
|
strategyFunctions.wait()
|
||||||
|
else
|
||||||
|
client.reboot_core()
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Strategies.reset(reason, extra, wait)
|
||||||
|
local time = Utils.elapsedTime()
|
||||||
|
local resetMessage = "reset"
|
||||||
|
if time then
|
||||||
|
resetMessage = resetMessage.." after "..time
|
||||||
|
end
|
||||||
|
resetMessage = resetMessage.." at "..Control.areaName
|
||||||
|
local separator
|
||||||
|
if Strategies.deepRun and not Control.yolo then
|
||||||
|
separator = " BibleThump"
|
||||||
|
else
|
||||||
|
separator = ":"
|
||||||
|
end
|
||||||
|
resetMessage = resetMessage..separator.." "..reason
|
||||||
|
if status.tweeted then
|
||||||
|
Strategies.tweetProgress(resetMessage)
|
||||||
|
end
|
||||||
|
return Strategies.hardReset(resetMessage, extra, wait)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- RESET TO CONTINUE
|
||||||
|
|
||||||
|
--[[function Strategies.SkipReset(message)
|
||||||
|
RUNNING4CONTINUE = true
|
||||||
|
EXTERNALDONE = false
|
||||||
|
client.reboot_core()
|
||||||
|
return true
|
||||||
|
end]]
|
||||||
|
|
||||||
|
function Strategies.death(extra)
|
||||||
|
local reason = "Died"
|
||||||
|
--[[local reason
|
||||||
|
if Control.missed then
|
||||||
|
reason = "Missed"
|
||||||
|
elseif Control.criticaled then
|
||||||
|
reason = "Critical'd"
|
||||||
|
elseif Control.yolo then
|
||||||
|
reason = "Yolo strats"
|
||||||
|
else
|
||||||
|
reason = "Died"
|
||||||
|
end]]
|
||||||
|
return Strategies.reset(reason, extra)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Strategies.overMinute(min)
|
||||||
|
if type(min) == "string" then
|
||||||
|
min = Strategies.getTimeRequirement(min)
|
||||||
|
end
|
||||||
|
return Utils.igt() > (min * 60)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Strategies.resetTime(timeLimit, reason, once)
|
||||||
|
if Strategies.overMinute(timeLimit) then
|
||||||
|
reason = "Took too long to "..reason
|
||||||
|
if RESET_FOR_TIME then
|
||||||
|
return Strategies.reset(reason)
|
||||||
|
end
|
||||||
|
if once then
|
||||||
|
print(reason.." "..Utils.elapsedTime())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- HELPERS
|
||||||
|
|
||||||
|
function Strategies.initialize()
|
||||||
|
if not status.initialized then
|
||||||
|
status.initialized = true
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Strategies.buffTo(buff, defLevel, usePPAmount, oneHit)
|
||||||
|
if Battle.isActive() then
|
||||||
|
status.canProgress = true
|
||||||
|
local forced
|
||||||
|
if not usePPAmount then
|
||||||
|
if defLevel and Memory.double("battle", "opponent_defense") > defLevel then
|
||||||
|
forced = buff
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local AvailablePP = Battle.pp(buff)
|
||||||
|
if not oneHit then
|
||||||
|
if AvailablePP > usePPAmount then
|
||||||
|
forced = buff
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if Strategies.initialize() then
|
||||||
|
status.tempDir = AvailablePP
|
||||||
|
end
|
||||||
|
if AvailablePP > status.tempDir-1 then
|
||||||
|
forced = buff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Battle.automate(forced, true)
|
||||||
|
elseif status.canProgress then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
Battle.automate()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Strategies.dodgeUp(npc, sx, sy, dodge, offset)
|
||||||
|
if not Battle.handleWild() then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local px, py = Player.position()
|
||||||
|
if py < sy - 1 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local wx, wy = px, py
|
||||||
|
if py < sy then
|
||||||
|
wy = py - 1
|
||||||
|
elseif px == sx or px == dodge then
|
||||||
|
if px - Memory.raw(npc) == offset then
|
||||||
|
if px == sx then
|
||||||
|
wx = dodge
|
||||||
|
else
|
||||||
|
wx = sx
|
||||||
|
end
|
||||||
|
else
|
||||||
|
wy = py - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Walk.step(wx, wy)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function dodgeH(options)
|
||||||
|
local left = 1
|
||||||
|
if options.left then
|
||||||
|
left = -1
|
||||||
|
end
|
||||||
|
local px, py = Player.position()
|
||||||
|
if px * left > options.sx * left + (options.dist or 1) * left then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local wx, wy = px, py
|
||||||
|
if px * left > options.sx * left then
|
||||||
|
wx = px + 1 * left
|
||||||
|
elseif py == options.sy or py == options.dodge then
|
||||||
|
if py - Memory.raw(options.npc) == options.offset then
|
||||||
|
if py == options.sy then
|
||||||
|
wy = options.dodge
|
||||||
|
else
|
||||||
|
wy = options.sy
|
||||||
|
end
|
||||||
|
else
|
||||||
|
wx = px + 1 * left
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Walk.step(wx, wy)
|
||||||
|
end]]
|
||||||
|
|
||||||
|
-- GENERALIZED STRATEGIES
|
||||||
|
|
||||||
|
Strategies.functions = {
|
||||||
|
|
||||||
|
split = function(data)
|
||||||
|
Bridge.split(data and data.finished)
|
||||||
|
if not INTERNAL then
|
||||||
|
splitNumber = splitNumber + 1
|
||||||
|
|
||||||
|
local timeDiff
|
||||||
|
splitTime, timeDiff = Utils.timeSince(splitTime)
|
||||||
|
if timeDiff then
|
||||||
|
print(splitNumber..". "..Control.areaName..": "..Utils.elapsedTime().." ("..timeDiff..")")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
interact = function(data)
|
||||||
|
if Battle.handleWild() then
|
||||||
|
if Battle.isActive() then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if Textbox.isActive() then
|
||||||
|
if status.tries > 0 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
status.tries = status.tries - 1
|
||||||
|
Input.cancel()
|
||||||
|
elseif Player.interact(data.dir) then
|
||||||
|
status.tries = status.tries + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
confirm = function(data)
|
||||||
|
if Battle.handleWild() then
|
||||||
|
if Textbox.isActive() then
|
||||||
|
status.tries = status.tries + 1
|
||||||
|
Input.cancel(data.type or "A")
|
||||||
|
else
|
||||||
|
if status.tries > 0 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Player.interact(data.dir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
setDirection = function(data)
|
||||||
|
if Player.isFacing(data.dir) then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
Input.press(data.dir, 2)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
speak = function()
|
||||||
|
if Strategies.initialize() then
|
||||||
|
status.tempDir = false
|
||||||
|
end
|
||||||
|
if Textbox.isActive() then
|
||||||
|
Input.press("A", 2)
|
||||||
|
status.tempDir = true
|
||||||
|
else
|
||||||
|
if status.tempDir then
|
||||||
|
status.tempDir = false
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
openMenu = function()
|
||||||
|
if Textbox.isActive() then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
Input.press("Start", 2)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
closeMenu = function()
|
||||||
|
if not Textbox.isActive() then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
Input.press("B")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
allowDeath = function(data)
|
||||||
|
Control.canDie(data.on)
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
--[[champion = function()
|
||||||
|
if status.canProgress then
|
||||||
|
if status.tries > 1500 then
|
||||||
|
return Strategies.hardReset("Beat the game in "..status.canProgress.." !")
|
||||||
|
end
|
||||||
|
if status.tries == 0 then
|
||||||
|
Bridge.tweet("Beat Pokemon "..GAME_NAME.." in "..status.canProgress.."!")
|
||||||
|
if Strategies.seed then
|
||||||
|
print(Utils.frames().." frames, with seed "..Strategies.seed)
|
||||||
|
print("Please save this seed number to share, if you would like proof of your run!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
status.tries = status.tries + 1
|
||||||
|
elseif Memory.value("menu", "shop_current") == 252 then
|
||||||
|
Strategies.functions.split({finished=true})
|
||||||
|
status.canProgress = Utils.elapsedTime()
|
||||||
|
else
|
||||||
|
Input.cancel()
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
}
|
||||||
|
|
||||||
|
strategyFunctions = Strategies.functions
|
||||||
|
|
||||||
|
function Strategies.execute(data)
|
||||||
|
if strategyFunctions[data.s](data) then
|
||||||
|
status = {tries=0}
|
||||||
|
Strategies.status = status
|
||||||
|
Strategies.completeGameStrategy()
|
||||||
|
-- print(data.s)
|
||||||
|
if resetting then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Strategies.init(midGame)
|
||||||
|
if not STREAMING_MODE then
|
||||||
|
splitTime = Utils.timeSince(0)
|
||||||
|
end
|
||||||
|
if midGame then
|
||||||
|
Combat.factorPP(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Strategies.softReset()
|
||||||
|
status = {tries=0}
|
||||||
|
Strategies.status = status
|
||||||
|
stats = {}
|
||||||
|
Strategies.stats = stats
|
||||||
|
Strategies.updates = {}
|
||||||
|
|
||||||
|
splitNumber, splitTime = 0, 0
|
||||||
|
resetting = nil
|
||||||
|
Strategies.deepRun = false
|
||||||
|
Strategies.resetGame()
|
||||||
|
end
|
||||||
|
|
||||||
|
return Strategies
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,225 @@
|
||||||
|
local Opponents = {
|
||||||
|
|
||||||
|
--[[RivalGyarados = {
|
||||||
|
type1 = "water",
|
||||||
|
type2 = "flying",
|
||||||
|
def = 71,
|
||||||
|
id = 22,
|
||||||
|
spec = 87,
|
||||||
|
hp = 126,
|
||||||
|
speed = 72,
|
||||||
|
level = 38,
|
||||||
|
att = 106,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Hydro-Pump",
|
||||||
|
accuracy = 80,
|
||||||
|
power = 120,
|
||||||
|
id = 56,
|
||||||
|
special = true,
|
||||||
|
max_pp = 5,
|
||||||
|
move_type = "water",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
boost = {
|
||||||
|
stat = "spec",
|
||||||
|
mp = 1.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
HypnoHeadbutt = {
|
||||||
|
type1 = "psychic",
|
||||||
|
type2 = "psychic",
|
||||||
|
def = 58,
|
||||||
|
id = 129,
|
||||||
|
spec = 88,
|
||||||
|
hp = 107,
|
||||||
|
speed = 56,
|
||||||
|
level = 34,
|
||||||
|
att = 60,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Headbutt",
|
||||||
|
accuracy = 100,
|
||||||
|
power = 70,
|
||||||
|
id = 29,
|
||||||
|
special = false,
|
||||||
|
max_pp = 15,
|
||||||
|
move_type = "normal",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
HypnoConfusion = {
|
||||||
|
type1 = "psychic",
|
||||||
|
type2 = "psychic",
|
||||||
|
def = 58,
|
||||||
|
id = 129,
|
||||||
|
spec = 88,
|
||||||
|
hp = 107,
|
||||||
|
speed = 56,
|
||||||
|
level = 34,
|
||||||
|
att = 60,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Confusion",
|
||||||
|
accuracy = 100,
|
||||||
|
power = 50,
|
||||||
|
id = 93,
|
||||||
|
special = true,
|
||||||
|
max_pp = 25,
|
||||||
|
move_type = "psychic",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
KogaWeezing = {
|
||||||
|
type1 = "poison",
|
||||||
|
type2 = "poison",
|
||||||
|
def = 115,
|
||||||
|
id = 143,
|
||||||
|
spec = 84,
|
||||||
|
hp = 115,
|
||||||
|
speed = 63,
|
||||||
|
level = 43,
|
||||||
|
att = 90,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Self-Destruct",
|
||||||
|
accuracy = 100,
|
||||||
|
power = 260,
|
||||||
|
id = 120,
|
||||||
|
special = false,
|
||||||
|
max_pp = 5,
|
||||||
|
move_type = "normal",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
GiovanniRhyhorn = {
|
||||||
|
type1 = "ground",
|
||||||
|
type2 = "rock",
|
||||||
|
def = 97,
|
||||||
|
id = 18,
|
||||||
|
spec = 39,
|
||||||
|
hp = 134,
|
||||||
|
speed = 34,
|
||||||
|
level = 45,
|
||||||
|
att = 89,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Stomp",
|
||||||
|
move_type = "normal",
|
||||||
|
accuracy = 100,
|
||||||
|
power = 65,
|
||||||
|
id = 23,
|
||||||
|
special = false,
|
||||||
|
max_pp = 20,
|
||||||
|
damage = 21,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
LoreleiDewgong = {
|
||||||
|
type1 = "water",
|
||||||
|
type2 = "ice",
|
||||||
|
def = 100,
|
||||||
|
id = 120,
|
||||||
|
spec = 116,
|
||||||
|
hp = 169,
|
||||||
|
speed = 89,
|
||||||
|
level = 54,
|
||||||
|
att = 90,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Aurora-Beam",
|
||||||
|
accuracy = 100,
|
||||||
|
power = 65,
|
||||||
|
id = 62,
|
||||||
|
special = true,
|
||||||
|
max_pp = 20,
|
||||||
|
move_type = "ice",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
boost = {
|
||||||
|
stat = "spec",
|
||||||
|
mp = 2 / 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
LanceGyarados = {
|
||||||
|
type1 = "water",
|
||||||
|
type2 = "flying",
|
||||||
|
def = 105,
|
||||||
|
id = 22,
|
||||||
|
spec = 130,
|
||||||
|
hp = 187,
|
||||||
|
speed = 108,
|
||||||
|
level = 58,
|
||||||
|
att = 160,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Hydro-Pump",
|
||||||
|
accuracy = 80,
|
||||||
|
power = 120,
|
||||||
|
id = 56,
|
||||||
|
special = true,
|
||||||
|
max_pp = 5,
|
||||||
|
move_type = "water",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
boost = {
|
||||||
|
stat = "spec",
|
||||||
|
mp = 1.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
BluePidgeot = {
|
||||||
|
type1 = "normal",
|
||||||
|
type2 = "flying",
|
||||||
|
def = 106,
|
||||||
|
id = 151,
|
||||||
|
spec = 100,
|
||||||
|
hp = 182,
|
||||||
|
speed = 125,
|
||||||
|
level = 61,
|
||||||
|
att = 113,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Wing-Attack",
|
||||||
|
accuracy = 100,
|
||||||
|
power = 35,
|
||||||
|
id = 17,
|
||||||
|
special = false,
|
||||||
|
max_pp = 35,
|
||||||
|
move_type = "flying",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
BlueSky = {
|
||||||
|
type1 = "normal",
|
||||||
|
type2 = "flying",
|
||||||
|
def = 106,
|
||||||
|
id = 151,
|
||||||
|
spec = 100,
|
||||||
|
hp = 182,
|
||||||
|
speed = 125,
|
||||||
|
level = 61,
|
||||||
|
att = 113,
|
||||||
|
moves = {
|
||||||
|
{
|
||||||
|
name = "Sky-Attack",
|
||||||
|
accuracy = 90,
|
||||||
|
power = 140,
|
||||||
|
id = 143,
|
||||||
|
special = false,
|
||||||
|
max_pp = 5,
|
||||||
|
move_type = "flying",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},]]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return Opponents
|
|
@ -0,0 +1,38 @@
|
||||||
|
local paths = {
|
||||||
|
-- Inside truck
|
||||||
|
{65, {9,9}, {12,9}},
|
||||||
|
-- Go to Mom House
|
||||||
|
{9, {11,17}},
|
||||||
|
-- Mom house
|
||||||
|
{1, {15,15}, {15,14}, {15,9}},
|
||||||
|
-- Bedroom
|
||||||
|
{2, {14,9}, {12,9}, {s="setDirection",dir="Up"}, {s="setHour"}, {12,9}, {14,9}, {14,8}},
|
||||||
|
-- Dad TV Show
|
||||||
|
{1, {15,10}, {11,12}, {15,12}, {15,16}},
|
||||||
|
-- Go to neightbor house
|
||||||
|
{9, {12,16}, {21,16}, {21,15}},
|
||||||
|
-- Inside Neighbor house
|
||||||
|
{3, {9,15}, {9,9}},
|
||||||
|
-- Inside Bedroom
|
||||||
|
{4, {8,9}, {8,10}, {12,10}, {s="setDirection",dir="Down"}, {s="speak"}, {8,10}, {8,8}},
|
||||||
|
-- Inside house
|
||||||
|
{3, {9,10}, {9,16}},
|
||||||
|
-- Go Help prof.
|
||||||
|
{9, {21,16}, {18,16}, {18,8}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
--Remake Path for Girl
|
||||||
|
if GAME_GENDER == 2 then
|
||||||
|
paths[2] = {9, {20,17}}
|
||||||
|
paths[3] = {3, {9,15}, {9,14}, {9,9}}
|
||||||
|
paths[4] = {4, {8,9}, {10,9}, {s="setDirection",dir="Up"}, {s="setHour"}, {10,9}, {8,9}, {8,8}}
|
||||||
|
paths[5] = {3, {9,10}, {13,12}, {9,12}, {9,16}}
|
||||||
|
paths[6] = {9, {21,16}, {12,16}, {12,15}}
|
||||||
|
paths[7] = {1, {15,15}, {15,9}}
|
||||||
|
paths[8] = {2, {14,9}, {14,10}, {10,10}, {s="setDirection",dir="Down"}, {s="speak"}, {14,10}, {14,8}}
|
||||||
|
paths[9] = {1, {15,10}, {15,16}}
|
||||||
|
paths[10][2] = {12,16}
|
||||||
|
end
|
||||||
|
|
||||||
|
return paths
|
|
@ -0,0 +1,239 @@
|
||||||
|
--##################################################
|
||||||
|
--############# ############
|
||||||
|
--############# SETTING ############
|
||||||
|
--############# ############
|
||||||
|
--##################################################
|
||||||
|
|
||||||
|
--Reset Settings
|
||||||
|
RESET_FOR_TIME = false -- Set to false if you just want to see the bot finish a run without reset for time
|
||||||
|
RESET_FOR_ENCOUNTERS = false -- Set to false if you just want to see the bot finish a run without reset for encounters
|
||||||
|
|
||||||
|
--Game Settings
|
||||||
|
GAME_NAME = "Emerald" -- Set to Ruby/Sapphire or Emerald
|
||||||
|
GAME_HOURS = 17 -- Set the internal game hour (0-23h)
|
||||||
|
GAME_MINUTES = 35 -- Set the internal game minutes (0-59min)
|
||||||
|
GAME_GENDER = 1 -- Set the player gender (1-2 // boy-girl)
|
||||||
|
|
||||||
|
GAME_TEXT_SPEED = 2 -- Set the Text Speed (0-2 // slow-fast)
|
||||||
|
GAME_BATTLE_ANIMATION = 1 -- Set the battle animation (0-1 // no-yes)
|
||||||
|
GAME_BATTLE_STYLE = 1 -- Set the battle style (0-1 // shift-set)
|
||||||
|
GAME_SOUND_STYLE = 1 -- Set the sound style (0-1 // stereo-mono)
|
||||||
|
GAME_BUTTON_STYLE = 0 -- Set the button style (0-2)
|
||||||
|
GAME_WINDOWS_STYLE = 4 -- Set the windows style (0-19)
|
||||||
|
|
||||||
|
--Connection Settings
|
||||||
|
INTERNAL = false -- Allow connection with LiveSplit ?
|
||||||
|
STREAMING_MODE = false -- Enable Streaming mode
|
||||||
|
|
||||||
|
--Script Settings
|
||||||
|
CUSTOM_SEED = nil -- Set to a known seed to replay it, or leave nil for random runs
|
||||||
|
PAINT_ON = true -- Display contextual information while the bot runs
|
||||||
|
|
||||||
|
--Names Settings
|
||||||
|
PLAYER_NAME = "TeStInG" -- Player name
|
||||||
|
RIVAL_NAME = "URRival" -- Rival name
|
||||||
|
MUDKIP_NAME = "Muddy" -- Set Mudkip name
|
||||||
|
|
||||||
|
--NAMES SETTINGS TIPS :
|
||||||
|
-- - Can use up to 7 letter ingame
|
||||||
|
-- - Upper, Lower case and Number allowed
|
||||||
|
-- - Specials Characters :
|
||||||
|
-- < = male symbol
|
||||||
|
-- > = female symbol
|
||||||
|
-- { or } = "
|
||||||
|
-- [ or ] = '
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--#####################################################################################
|
||||||
|
--#####################################################################################
|
||||||
|
--########### ###############
|
||||||
|
--########### PLEASE DON'T EDIT ANYTHING BELLOW, IT'S AT YOUR RISK ###############
|
||||||
|
--########### START CODE (hard hats on) ###############
|
||||||
|
--########### ###############
|
||||||
|
--#####################################################################################
|
||||||
|
--#####################################################################################
|
||||||
|
|
||||||
|
-- SET VALUES
|
||||||
|
|
||||||
|
local VERSION = "0.1-BETA"
|
||||||
|
|
||||||
|
local START_WAIT = 99
|
||||||
|
local hasAlreadyStartedPlaying = false
|
||||||
|
local oldSeconds
|
||||||
|
local running = true
|
||||||
|
local lastHP
|
||||||
|
|
||||||
|
--RUNNING4CONTINUE = false --used to continue a game
|
||||||
|
--RUNNING4NEWGAME = true --used to make a new game (remove last save also)
|
||||||
|
--EXTERNALDONE = false --used when the above settings are done externally
|
||||||
|
--local InternalDone = false --used when the above settings are done internally
|
||||||
|
|
||||||
|
-- LOAD DIR
|
||||||
|
|
||||||
|
local LowerGameName = string.lower(GAME_NAME)
|
||||||
|
|
||||||
|
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."..LowerGameName..".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"
|
||||||
|
|
||||||
|
-- GLOBAL
|
||||||
|
|
||||||
|
function p(...) --print
|
||||||
|
local string
|
||||||
|
if #arg == 0 then
|
||||||
|
string = arg[0]
|
||||||
|
else
|
||||||
|
string = ""
|
||||||
|
for i,str in ipairs(arg) do
|
||||||
|
if str == true then
|
||||||
|
string = string.."\n"
|
||||||
|
else
|
||||||
|
string = string..str.." "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print(string)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- RESET
|
||||||
|
|
||||||
|
local function resetAll()
|
||||||
|
Strategies.softReset()
|
||||||
|
Combat.reset()
|
||||||
|
Control.reset()
|
||||||
|
Walk.reset()
|
||||||
|
Paint.reset()
|
||||||
|
Bridge.reset()
|
||||||
|
oldSeconds = 0
|
||||||
|
running = false
|
||||||
|
Utils.reset()
|
||||||
|
-- client.speedmode = 200
|
||||||
|
|
||||||
|
if CUSTOM_SEED then
|
||||||
|
Strategies.seed = CUSTOM_SEED
|
||||||
|
p("RUNNING WITH A FIXED SEED ("..Strategies.seed.."), every run will play out identically!", true)
|
||||||
|
else
|
||||||
|
Strategies.seed = os.time()
|
||||||
|
p("Starting a new run with seed "..Strategies.seed, true)
|
||||||
|
end
|
||||||
|
math.randomseed(Strategies.seed)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- EXECUTE
|
||||||
|
|
||||||
|
local OWNER = "Bouletmarc"
|
||||||
|
p("Welcome to PokeBot Version "..VERSION, true)
|
||||||
|
p("Actually running Pokemon "..GAME_NAME.." Speedruns by "..OWNER, true)
|
||||||
|
|
||||||
|
Control.init()
|
||||||
|
|
||||||
|
--STREAMING_MODE = not walk.init()
|
||||||
|
if INTERNAL and STREAMING_MODE then
|
||||||
|
RESET_FOR_TIME = true
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
p("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.", true)
|
||||||
|
end
|
||||||
|
if STREAMING_MODE then
|
||||||
|
Bridge.init()
|
||||||
|
else
|
||||||
|
Input.setDebug(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- MAIN LOOP
|
||||||
|
|
||||||
|
local previousMap
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local currentMap = Memory.double("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
|
||||||
|
-- Utils.drawText(0, 80, Strategies.frames)
|
||||||
|
--end
|
||||||
|
--if Bridge.polling then
|
||||||
|
-- Settings.pollForResponse()
|
||||||
|
--end
|
||||||
|
|
||||||
|
if not Input.update() then
|
||||||
|
if not Utils.ingame() and currentMap == 0 then
|
||||||
|
if running then
|
||||||
|
if not hasAlreadyStartedPlaying then
|
||||||
|
if emu.framecount() == 1 then client.reboot_core() end
|
||||||
|
hasAlreadyStartedPlaying = true
|
||||||
|
else
|
||||||
|
resetAll()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Settings.startNewAdventure(START_WAIT)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if not running then
|
||||||
|
Bridge.liveSplit()
|
||||||
|
running = true
|
||||||
|
end
|
||||||
|
--local battleState = Memory.value("game", "battle")
|
||||||
|
--Control.encounter(battleState)
|
||||||
|
--local curr_hp = Pokemon.index(0, "hp")
|
||||||
|
--if curr_hp == 0 and not Control.canDie() and Pokemon.index(0) > 0 then
|
||||||
|
-- Strategies.death(currentMap)
|
||||||
|
--elseif Walk.strategy then
|
||||||
|
if 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 newSeconds = Memory.value("time", "seconds")
|
||||||
|
if newSeconds ~= oldSeconds and (newSeconds > 0 or Memory.value("time", "frames") > 0) then
|
||||||
|
Bridge.time(Utils.elapsedTime())
|
||||||
|
oldSeconds = newSeconds
|
||||||
|
end
|
||||||
|
elseif PAINT_ON then
|
||||||
|
Paint.draw(currentMap)
|
||||||
|
end
|
||||||
|
|
||||||
|
Input.advance()
|
||||||
|
emu.frameadvance()
|
||||||
|
end
|
||||||
|
|
||||||
|
Bridge.close()
|
|
@ -0,0 +1,273 @@
|
||||||
|
local Inventory = {}
|
||||||
|
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Menu = require "util.menu"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
|
||||||
|
local Pokemon = require "storage.pokemon"
|
||||||
|
|
||||||
|
local ItemList = require "storage.itemlist"
|
||||||
|
|
||||||
|
--[[local items = {
|
||||||
|
pokeball = 4,
|
||||||
|
bicycle = 6,
|
||||||
|
moon_stone = 10,
|
||||||
|
antidote = 11,
|
||||||
|
burn_heal = 12,
|
||||||
|
paralyze_heal = 15,
|
||||||
|
full_restore = 16,
|
||||||
|
super_potion = 19,
|
||||||
|
potion = 20,
|
||||||
|
escape_rope = 29,
|
||||||
|
carbos = 38,
|
||||||
|
repel = 30,
|
||||||
|
|
||||||
|
rare_candy = 40,
|
||||||
|
helix_fossil = 42,
|
||||||
|
nugget = 49,
|
||||||
|
pokedoll = 51,
|
||||||
|
super_repel = 56,
|
||||||
|
fresh_water = 60,
|
||||||
|
soda_pop = 61,
|
||||||
|
coin_case = 69,
|
||||||
|
pokeflute = 73,
|
||||||
|
ether = 80,
|
||||||
|
max_ether = 81,
|
||||||
|
elixer = 82,
|
||||||
|
|
||||||
|
x_accuracy = 46,
|
||||||
|
x_speed = 67,
|
||||||
|
x_special = 68,
|
||||||
|
|
||||||
|
cut = 196,
|
||||||
|
fly = 197,
|
||||||
|
surf = 198,
|
||||||
|
strength = 199,
|
||||||
|
|
||||||
|
horn_drill = 207,
|
||||||
|
bubblebeam = 211,
|
||||||
|
water_gun = 212,
|
||||||
|
ice_beam = 213,
|
||||||
|
thunderbolt = 224,
|
||||||
|
earthquake = 226,
|
||||||
|
dig = 228,
|
||||||
|
tm34 = 234,
|
||||||
|
rock_slide = 248,
|
||||||
|
}]]
|
||||||
|
|
||||||
|
--local ITEM_BASE = Memory.value("inventory", "item_base")
|
||||||
|
|
||||||
|
-- Data
|
||||||
|
|
||||||
|
function Inventory.indexOf(name)
|
||||||
|
--local searchID = items[name]
|
||||||
|
local searchID = ItemList.items[name]
|
||||||
|
for i=0,19 do
|
||||||
|
--local iidx = ITEM_BASE + i * 2
|
||||||
|
local SubIndex = i * 2
|
||||||
|
local iidx = ITEM_BASE + SubIndex
|
||||||
|
if Memory.raw(iidx) == searchID then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
|
||||||
|
function Inventory.count(name)
|
||||||
|
local index = Inventory.indexOf(name)
|
||||||
|
if index ~= -1 then
|
||||||
|
local SubIndex = index * 2
|
||||||
|
return Memory.raw(ITEM_BASE + SubIndex + 1)
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Inventory.contains(...)
|
||||||
|
for i,name in ipairs(arg) do
|
||||||
|
if Inventory.count(name) > 0 then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Actions
|
||||||
|
|
||||||
|
--[[function Inventory.teach(item, poke, replaceIdx, altPoke)
|
||||||
|
local main = Memory.value("menu", "main")
|
||||||
|
local column = Menu.getCol()
|
||||||
|
if main == 144 then
|
||||||
|
if column == 5 then
|
||||||
|
Menu.select(replaceIdx, true)
|
||||||
|
else
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
elseif main == 128 then
|
||||||
|
if column == 5 then
|
||||||
|
Menu.select(Inventory.indexOf(item), "accelerate", true)
|
||||||
|
elseif column == 11 then
|
||||||
|
Menu.select(2, true)
|
||||||
|
elseif column == 14 then
|
||||||
|
Menu.select(0, true)
|
||||||
|
end
|
||||||
|
elseif main == Menu.pokemon then
|
||||||
|
Input.press("B")
|
||||||
|
elseif main == 64 or main == 96 or main == 192 then
|
||||||
|
if column == 5 then
|
||||||
|
Menu.select(replaceIdx, true)
|
||||||
|
elseif column == 14 then
|
||||||
|
Input.press("A")
|
||||||
|
elseif column == 15 then
|
||||||
|
Menu.select(0, true)
|
||||||
|
else
|
||||||
|
local idx = 0
|
||||||
|
if poke then
|
||||||
|
idx = Pokemon.indexOf(poke, altPoke)
|
||||||
|
end
|
||||||
|
Menu.select(idx, true)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end]]
|
||||||
|
|
||||||
|
function Inventory.isFull()
|
||||||
|
return Memory.value("inventory", "item_count") == 20
|
||||||
|
end
|
||||||
|
|
||||||
|
function Inventory.use(item, poke, midfight, BagMenu)
|
||||||
|
if midfight then
|
||||||
|
local battleMenu = Memory.value("battle", "menu")
|
||||||
|
--if battleMenu == 94 then
|
||||||
|
--open bag menu
|
||||||
|
if battleMenu == 186 then
|
||||||
|
local rowSelected = Memory.value("battle", "menuY")
|
||||||
|
local ColumnSelected = Memory.value("battle", "menuX")
|
||||||
|
if ColumnSelected == 1 then
|
||||||
|
if rowSelected == 1 then
|
||||||
|
Input.press("Down")
|
||||||
|
else
|
||||||
|
--select bag
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("Left")
|
||||||
|
end
|
||||||
|
--elseif battleMenu == 233 then
|
||||||
|
--inside bag menu
|
||||||
|
elseif battleMenu == 128 then
|
||||||
|
--if its not done
|
||||||
|
if not give_done then
|
||||||
|
if column ~= BagMenu then
|
||||||
|
--select proper bag menu
|
||||||
|
Menu.setCol(BagMenu)
|
||||||
|
else
|
||||||
|
if Memory.value("menu", "shop_current") ~= 70 then
|
||||||
|
--select the item
|
||||||
|
Menu.select(Inventory.indexOf(item)+1, "accelerate", "input")
|
||||||
|
else
|
||||||
|
--accept the use
|
||||||
|
Menu.select(1, true, "input")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--if its done
|
||||||
|
else
|
||||||
|
Menu.close()
|
||||||
|
end
|
||||||
|
elseif Utils.onPokemonSelect(battleMenu) then
|
||||||
|
if poke then
|
||||||
|
--if type(poke) == "string" then
|
||||||
|
-- poke = Pokemon.indexOf(poke)
|
||||||
|
--end
|
||||||
|
Menu.select(poke, true, "input")
|
||||||
|
else
|
||||||
|
Input.press("A")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("B")
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local main = Memory.value("menu", "main")
|
||||||
|
local column = Menu.getCol()
|
||||||
|
local give_done = false
|
||||||
|
--select item menu
|
||||||
|
if main == 121 then
|
||||||
|
Menu.select(3, true)
|
||||||
|
--inside bag menu
|
||||||
|
elseif main == 50 then
|
||||||
|
--if its not done
|
||||||
|
if not give_done then
|
||||||
|
if column ~= BagMenu then
|
||||||
|
--select proper bag menu
|
||||||
|
Menu.setCol(BagMenu)
|
||||||
|
else
|
||||||
|
if Memory.value("menu", "shop_current") ~= 66 then
|
||||||
|
--select the item
|
||||||
|
Menu.select(Inventory.indexOf(item)+1, "accelerate", "input")
|
||||||
|
else
|
||||||
|
--accept the use
|
||||||
|
Menu.select(1, true, "input")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--if its done
|
||||||
|
else
|
||||||
|
Menu.close()
|
||||||
|
end
|
||||||
|
--inside pokemon menu
|
||||||
|
elseif main == 127 then
|
||||||
|
local idx = 1
|
||||||
|
if poke then
|
||||||
|
idx = poke
|
||||||
|
end
|
||||||
|
if Memory.value("menu", "input_row") ~= idx then
|
||||||
|
Menu.select(idx, true, "input")
|
||||||
|
else
|
||||||
|
Input.press("A", 1)
|
||||||
|
give_done = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--####################################
|
||||||
|
--[[if main == 144 then
|
||||||
|
if Memory.value("battle", "menu") == 95 then
|
||||||
|
Input.press("B")
|
||||||
|
else
|
||||||
|
local idx = 0
|
||||||
|
if poke then
|
||||||
|
idx = Pokemon.indexOf(poke)
|
||||||
|
end
|
||||||
|
Menu.select(idx, true)
|
||||||
|
end
|
||||||
|
elseif main == 128 or main == 60 then
|
||||||
|
if column == 5 then
|
||||||
|
Menu.select(Inventory.indexOf(item), "accelerate", true)
|
||||||
|
elseif column == 11 then
|
||||||
|
Menu.select(2, true)
|
||||||
|
elseif column == 14 then
|
||||||
|
Menu.select(0, true)
|
||||||
|
else
|
||||||
|
local index = 0
|
||||||
|
if poke then
|
||||||
|
index = Pokemon.indexOf(poke)
|
||||||
|
end
|
||||||
|
Menu.select(index, true)
|
||||||
|
end
|
||||||
|
elseif main == 228 then
|
||||||
|
if column == 14 and Memory.value("battle", "menu") == 95 then
|
||||||
|
Input.press("B")
|
||||||
|
end
|
||||||
|
elseif main == Menu.pokemon then
|
||||||
|
Input.press("B")
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end]]
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return Inventory
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
ItemList = {}
|
||||||
|
|
||||||
|
ItemList.items = {
|
||||||
|
masterball = 1,
|
||||||
|
ultraball = 2,
|
||||||
|
bright_powder = 3,
|
||||||
|
greatball = 4,
|
||||||
|
pokeball = 5,
|
||||||
|
--teru_sama = 6,
|
||||||
|
bicycle = 7,
|
||||||
|
moon_stone = 8,
|
||||||
|
antidote = 9,
|
||||||
|
burn_heal = 10,
|
||||||
|
ice_heal = 11,
|
||||||
|
awakening = 12,
|
||||||
|
paralyze_heal = 13,
|
||||||
|
full_restore = 14,
|
||||||
|
max_potion = 15,
|
||||||
|
hyper_potion = 16,
|
||||||
|
super_potion = 17,
|
||||||
|
potion = 18,
|
||||||
|
escape_rope = 19,
|
||||||
|
repel = 20,
|
||||||
|
--carbos = 38,
|
||||||
|
rare_candy = 32,
|
||||||
|
--helix_fossil = 42,
|
||||||
|
--nugget = 49,
|
||||||
|
--pokedoll = 51,
|
||||||
|
super_repel = 42,
|
||||||
|
--fresh_water = 60,
|
||||||
|
--soda_pop = 61,
|
||||||
|
coin_case = 54,
|
||||||
|
--pokeflute = 73,
|
||||||
|
--ether = 80,
|
||||||
|
--max_ether = 81,
|
||||||
|
--elixer = 82,
|
||||||
|
--x_accuracy = 46,
|
||||||
|
--x_speed = 67,
|
||||||
|
--x_special = 68,
|
||||||
|
--horn_drill = 207,
|
||||||
|
--bubblebeam = 211,
|
||||||
|
--water_gun = 212,
|
||||||
|
--ice_beam = 213,
|
||||||
|
--thunderbolt = 224,
|
||||||
|
--earthquake = 226,
|
||||||
|
--dig = 228,
|
||||||
|
--tm34 = 234,
|
||||||
|
--rock_slide = 248,
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemList.moves = {
|
||||||
|
cut = 15,
|
||||||
|
fly = 19,
|
||||||
|
surf = 57,
|
||||||
|
strength = 70,
|
||||||
|
teleport = 100,
|
||||||
|
watefall = 127,
|
||||||
|
whirlpool = 250,
|
||||||
|
}
|
||||||
|
|
||||||
|
--return ItemList
|
||||||
|
|
|
@ -0,0 +1,325 @@
|
||||||
|
local Pokemon = {}
|
||||||
|
|
||||||
|
local Bridge = require "util.bridge"
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Menu = require "util.menu"
|
||||||
|
|
||||||
|
local pokeIDs = {
|
||||||
|
pidgey = 16,
|
||||||
|
spearow = 21,
|
||||||
|
rattata = 19,
|
||||||
|
nidoranF = 29,
|
||||||
|
nidoranM = 32,
|
||||||
|
|
||||||
|
chikorita = 152,
|
||||||
|
bayleef = 153,
|
||||||
|
meganium = 154,
|
||||||
|
|
||||||
|
cyndaquil = 155,
|
||||||
|
quilava = 156,
|
||||||
|
typhlosion = 157,
|
||||||
|
|
||||||
|
totodile = 158,
|
||||||
|
croconaw = 159,
|
||||||
|
feraligatr = 160,
|
||||||
|
|
||||||
|
sentret = 161,
|
||||||
|
furret = 162,
|
||||||
|
hoothoot = 163,
|
||||||
|
marill = 183,
|
||||||
|
azumarill = 184,
|
||||||
|
sudowoodo = 185,
|
||||||
|
politoed = 186,
|
||||||
|
hoppip = 187,
|
||||||
|
}
|
||||||
|
|
||||||
|
local moveList = {
|
||||||
|
cut = 15,
|
||||||
|
fly = 19,
|
||||||
|
surf = 57,
|
||||||
|
strength = 70,
|
||||||
|
teleport = 100,
|
||||||
|
watefall = 127,
|
||||||
|
whirlpool = 250,
|
||||||
|
|
||||||
|
sand_attack = 28,
|
||||||
|
horn_attack = 30,
|
||||||
|
horn_drill = 32,
|
||||||
|
tackle = 33,
|
||||||
|
thrash = 37,
|
||||||
|
tail_whip = 39,
|
||||||
|
poison_sting = 40,
|
||||||
|
leer = 43,
|
||||||
|
growl = 45,
|
||||||
|
water_gun = 55,
|
||||||
|
ice_beam = 58,
|
||||||
|
bubblebeam = 61,
|
||||||
|
leech_seed = 73,
|
||||||
|
thunderbolt = 85,
|
||||||
|
earthquake = 89,
|
||||||
|
dig = 91,
|
||||||
|
rock_slide = 157,
|
||||||
|
}
|
||||||
|
|
||||||
|
--[[local data = {
|
||||||
|
hp = {1, true},
|
||||||
|
status = {4},
|
||||||
|
moves = {8},
|
||||||
|
pp = {28},
|
||||||
|
level = {33},
|
||||||
|
max_hp = {34, true},
|
||||||
|
|
||||||
|
attack = {36, true},
|
||||||
|
defense = {38, true},
|
||||||
|
speed = {40, true},
|
||||||
|
special = {42, true},
|
||||||
|
}]]
|
||||||
|
|
||||||
|
local previousPartySize
|
||||||
|
|
||||||
|
--[[local function getAddress(index)
|
||||||
|
return 0x116B + index * 0x2C
|
||||||
|
end]]
|
||||||
|
|
||||||
|
--local function index(index, offset)
|
||||||
|
--[[local function index(index)
|
||||||
|
local double
|
||||||
|
--if not offset then
|
||||||
|
-- offset = 0
|
||||||
|
--else
|
||||||
|
-- local dataTable = data[offset]
|
||||||
|
-- offset = dataTable[1]
|
||||||
|
-- double = dataTable[2]
|
||||||
|
--end
|
||||||
|
local address = getAddress(index) + offset
|
||||||
|
local address = getAddress(index)
|
||||||
|
local value = Memory.raw(address)
|
||||||
|
if double then
|
||||||
|
value = value + Memory.raw(address + 1)
|
||||||
|
end
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
Pokemon.index = index]]
|
||||||
|
|
||||||
|
--[[local function indexOf(...)
|
||||||
|
for ni,name in ipairs(arg) do
|
||||||
|
local pid = pokeIDs[name]
|
||||||
|
for i=0,5 do
|
||||||
|
local atIdx = index(i)
|
||||||
|
if atIdx == pid then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
Pokemon.indexOf = indexOf]]
|
||||||
|
|
||||||
|
-- Table functions
|
||||||
|
|
||||||
|
function Pokemon.battleMove(name)
|
||||||
|
local mid = moveList[name]
|
||||||
|
for i=0,3 do
|
||||||
|
--if mid == Memory.raw(0x101B + i) then
|
||||||
|
if mid == Memory.raw(0x062E + i) then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Pokemon.moveIndex(move, pokemon)
|
||||||
|
local pokemonIdx
|
||||||
|
if pokemon then
|
||||||
|
pokemonIdx = indexOf(pokemon)
|
||||||
|
else
|
||||||
|
pokemonIdx = 0
|
||||||
|
end
|
||||||
|
local address = getAddress(pokemonIdx) + 7
|
||||||
|
local mid = moveList[move]
|
||||||
|
for i=1,4 do
|
||||||
|
if mid == Memory.raw(address + i) then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
|
--function Pokemon.info(name, offset)
|
||||||
|
--[[function Pokemon.info(name)
|
||||||
|
--return index(indexOf(name), offset)
|
||||||
|
return index(indexOf(name))
|
||||||
|
end]]
|
||||||
|
|
||||||
|
function Pokemon.getID(name)
|
||||||
|
return pokeIDs[name]
|
||||||
|
end
|
||||||
|
|
||||||
|
function Pokemon.getName(id)
|
||||||
|
for name,pid in pairs(pokeIDs) do
|
||||||
|
if pid == id then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Pokemon.getSacrifice(...)
|
||||||
|
for i,name in ipairs(arg) do
|
||||||
|
local pokemonIndex = indexOf(name)
|
||||||
|
if pokemonIndex ~= -1 and index(pokemonIndex, "hp") > 0 then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
|
--[[function Pokemon.inParty(...)
|
||||||
|
for i,name in ipairs(arg) do
|
||||||
|
if indexOf(name) ~= -1 then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
|
--[[function Pokemon.forMove(move)
|
||||||
|
local moveID = moveList[move]
|
||||||
|
for i=0,5 do
|
||||||
|
local address = getAddress(i)
|
||||||
|
for j=8,11 do
|
||||||
|
if Memory.raw(address + j) == moveID then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return -1
|
||||||
|
end]]
|
||||||
|
|
||||||
|
--[[function Pokemon.hasMove(move)
|
||||||
|
return Pokemon.forMove(move) ~= -1
|
||||||
|
end]]
|
||||||
|
|
||||||
|
function Pokemon.updateParty()
|
||||||
|
--local partySize = Memory.value("player", "party_size")
|
||||||
|
--if partySize ~= previousPartySize then
|
||||||
|
--local poke = Pokemon.inParty("tododile", "paras", "spearow", "pidgey", "nidoran", "squirtle")
|
||||||
|
--local poke = Pokemon.inParty("tododile")
|
||||||
|
--if poke then
|
||||||
|
-- Bridge.caught(poke)
|
||||||
|
-- previousPartySize = partySize
|
||||||
|
--end
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Pokemon.pp(index, move)
|
||||||
|
local midx = Pokemon.battleMove(move)
|
||||||
|
return Memory.raw(getAddress(index) + 28 + midx)
|
||||||
|
end]]
|
||||||
|
|
||||||
|
-- General
|
||||||
|
|
||||||
|
function Pokemon.isOpponent(...)
|
||||||
|
local oid = Memory.value("battle", "opponent_id")
|
||||||
|
for i,name in ipairs(arg) do
|
||||||
|
if oid == pokeIDs[name] then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Pokemon.isDeployed(...)
|
||||||
|
local deployedID = Memory.value("battle", "our_id")
|
||||||
|
for i,name in ipairs(arg) do
|
||||||
|
if deployedID == pokeIDs[name] then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Pokemon.isEvolving()
|
||||||
|
return false
|
||||||
|
--return Memory.value("menu", "pokemon") == 144
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Pokemon.getExp()
|
||||||
|
return Memory.raw(0x117A) * 256 + Memory.raw(0x117B)
|
||||||
|
end]]
|
||||||
|
|
||||||
|
--[[function Pokemon.inRedBar()
|
||||||
|
local curr_hp, max_hp = index(0, "hp"), index(0, "max_hp")
|
||||||
|
return curr_hp / max_hp <= 0.2
|
||||||
|
end]]
|
||||||
|
|
||||||
|
function Pokemon.use(move)
|
||||||
|
--local main = Memory.value("menu", "main")
|
||||||
|
local battlemenu = Memory.value("battle", "menu")
|
||||||
|
local pokeName = Pokemon.forMove(move)
|
||||||
|
local column = Memory.value("battle", "menuX")
|
||||||
|
local row = Memory.value("battle", "menuY")
|
||||||
|
if battlemenu == 186 then
|
||||||
|
if column == 2 then
|
||||||
|
Input.press("Left", 1)
|
||||||
|
else
|
||||||
|
if row == 2 then
|
||||||
|
Input.press("Up", 1)
|
||||||
|
else
|
||||||
|
--select move menu
|
||||||
|
Input.press("A", 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif battlemenu == 106 then
|
||||||
|
local midx = 1
|
||||||
|
if move then
|
||||||
|
midx = move
|
||||||
|
end
|
||||||
|
Menu.select(midx, true, "input")
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[[if main == 141 then
|
||||||
|
Input.press("A")
|
||||||
|
elseif main == 128 then
|
||||||
|
local column = Menu.getCol()
|
||||||
|
if column == 11 then
|
||||||
|
Menu.select(1, true)
|
||||||
|
elseif column == 10 or column == 12 then
|
||||||
|
local midx = 0
|
||||||
|
local menuSize = Memory.value("menu", "size")
|
||||||
|
if menuSize == 4 then
|
||||||
|
if move == "dig" then
|
||||||
|
midx = 1
|
||||||
|
elseif move == "surf" then
|
||||||
|
if Pokemon.inParty("paras") then
|
||||||
|
midx = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif menuSize == 5 then
|
||||||
|
if move == "dig" then
|
||||||
|
midx = 2
|
||||||
|
elseif move == "surf" then
|
||||||
|
midx = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Menu.select(midx, true)
|
||||||
|
else
|
||||||
|
Input.press("B")
|
||||||
|
end
|
||||||
|
elseif main == Menu.pokemon then
|
||||||
|
Menu.select(pokeName, true)
|
||||||
|
elseif main == 228 then
|
||||||
|
Input.press("B")
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end]]
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Pokemon.getDVs(name)
|
||||||
|
local index = Pokemon.indexOf(name)
|
||||||
|
local baseAddress = getAddress(index)
|
||||||
|
local attackDefense = Memory.raw(baseAddress + 0x1B)
|
||||||
|
local speedSpecial = Memory.raw(baseAddress + 0x1C)
|
||||||
|
return bit.rshift(attackDefense, 4), bit.band(attackDefense, 15), bit.rshift(speedSpecial, 4), bit.band(speedSpecial, 15)
|
||||||
|
end]]
|
||||||
|
|
||||||
|
return Pokemon
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
local Bridge = {}
|
||||||
|
|
||||||
|
local socket
|
||||||
|
if INTERNAL then
|
||||||
|
socket = require("socket")
|
||||||
|
end
|
||||||
|
|
||||||
|
local utils = require("util.utils")
|
||||||
|
|
||||||
|
local client = nil
|
||||||
|
local timeStopped = true
|
||||||
|
|
||||||
|
local function send(prefix, body)
|
||||||
|
if client then
|
||||||
|
local message = prefix
|
||||||
|
if body then
|
||||||
|
message = message..","..body
|
||||||
|
end
|
||||||
|
client:send(message.."\n")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function readln()
|
||||||
|
if client then
|
||||||
|
local s, status, partial = client:receive("*l")
|
||||||
|
if status == "closed" then
|
||||||
|
client = nil
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if s and s ~= "" then
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Wrapper functions
|
||||||
|
|
||||||
|
function Bridge.init()
|
||||||
|
if socket then
|
||||||
|
-- io.popen("java -jar Main.jar")
|
||||||
|
client = socket.connect("127.0.0.1", 13378)
|
||||||
|
if client then
|
||||||
|
client:settimeout(0.005)
|
||||||
|
client:setoption("keepalive", true)
|
||||||
|
print("Connected to Java!");
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
print("Error connecting to Java!");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.tweet(message)
|
||||||
|
if INTERNAL and STREAMING_MODE then
|
||||||
|
print("tweet::"..message)
|
||||||
|
return send("tweet", message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.pollForName()
|
||||||
|
Bridge.polling = true
|
||||||
|
send("poll_name")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.chat(message, extra, newLine)
|
||||||
|
if extra then
|
||||||
|
p(message.." || "..extra, newLine)
|
||||||
|
else
|
||||||
|
p(message, newLine)
|
||||||
|
end
|
||||||
|
return send("msg", "/me "..message)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.time(message)
|
||||||
|
if not timeStopped then
|
||||||
|
return send("time", message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.stats(message)
|
||||||
|
return send("stats", message)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.command(command)
|
||||||
|
return send("livesplit_command", command);
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.comparisonTime()
|
||||||
|
return send("livesplit_getcomparisontime");
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.process()
|
||||||
|
local response = readln()
|
||||||
|
if response then
|
||||||
|
-- print(">"..response)
|
||||||
|
if response:find("name:") then
|
||||||
|
return response:gsub("name:", "")
|
||||||
|
else
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.input(key)
|
||||||
|
send("input", key)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.caught(name)
|
||||||
|
if name then
|
||||||
|
send("caught", name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.hp(curr, max)
|
||||||
|
send("hp", curr..","..max)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.liveSplit()
|
||||||
|
send("start")
|
||||||
|
timeStopped = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.split(finished)
|
||||||
|
if finished then
|
||||||
|
timeStopped = true
|
||||||
|
end
|
||||||
|
send("split")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.encounter()
|
||||||
|
send("encounter")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.reset()
|
||||||
|
send("reset")
|
||||||
|
timeStopped = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bridge.close()
|
||||||
|
if client then
|
||||||
|
client:close()
|
||||||
|
client = nil
|
||||||
|
end
|
||||||
|
print("Bridge closed")
|
||||||
|
end
|
||||||
|
|
||||||
|
return Bridge
|
|
@ -0,0 +1,162 @@
|
||||||
|
local Input = {}
|
||||||
|
|
||||||
|
local Bridge = require "util.bridge"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
|
||||||
|
local lastSend
|
||||||
|
local currentButton, remainingFrames, setForFrame
|
||||||
|
local debug
|
||||||
|
local bCancel = true
|
||||||
|
|
||||||
|
local drawText = Utils.drawText
|
||||||
|
|
||||||
|
local Waiting = false
|
||||||
|
|
||||||
|
local function bridgeButton(btn)
|
||||||
|
if btn ~= lastSend then
|
||||||
|
lastSend = btn
|
||||||
|
Bridge.input(btn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--local function sendButton(button, ab, hold, newgame)
|
||||||
|
--local function sendButton(button, ab, hold)
|
||||||
|
local function sendButton(button, ab, slow)
|
||||||
|
local inputTable = {}
|
||||||
|
if slow ~= nil then
|
||||||
|
if slow == false then
|
||||||
|
inputTable = {[button]=true, B=true}
|
||||||
|
else
|
||||||
|
inputTable = {[button]=true}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inputTable = {[button]=true}
|
||||||
|
end
|
||||||
|
--else
|
||||||
|
--if not newgame then
|
||||||
|
-- inputTable = {[button]=true}
|
||||||
|
--else
|
||||||
|
-- inputTable = {Up=true, B=true, Select=true}
|
||||||
|
--end
|
||||||
|
--end
|
||||||
|
joypad.set(inputTable)
|
||||||
|
if debug then
|
||||||
|
if slow ~= nil then
|
||||||
|
if slow == true then
|
||||||
|
drawText(0, 60, button.."+B "..remainingFrames)
|
||||||
|
else
|
||||||
|
drawText(0, 60, button.." "..remainingFrames)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
drawText(0, 60, button.." "..remainingFrames)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ab then
|
||||||
|
button = "A,B"
|
||||||
|
end
|
||||||
|
bridgeButton(button)
|
||||||
|
setForFrame = button
|
||||||
|
end
|
||||||
|
|
||||||
|
function Input.isWaiting()
|
||||||
|
if setForFrame and not Waiting then
|
||||||
|
Waiting = true
|
||||||
|
elseif not setForFrame and Waiting then
|
||||||
|
Waiting = false
|
||||||
|
end
|
||||||
|
return Waiting
|
||||||
|
end
|
||||||
|
|
||||||
|
--function Input.press(button, frames, hold, newgame)
|
||||||
|
--function Input.press(button, frames, hold)
|
||||||
|
function Input.press(button, frames, slow)
|
||||||
|
if setForFrame then
|
||||||
|
print("ERR: Reassigning "..setForFrame.." to "..button)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if frames == nil or frames > 0 then
|
||||||
|
if button == currentButton then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not frames then
|
||||||
|
frames = 1
|
||||||
|
end
|
||||||
|
currentButton = button
|
||||||
|
remainingFrames = frames
|
||||||
|
else
|
||||||
|
remainingFrames = 0
|
||||||
|
end
|
||||||
|
bCancel = button ~= "B"
|
||||||
|
|
||||||
|
--sendButton(button, false)
|
||||||
|
sendButton(button, false, slow)
|
||||||
|
--sendButton(button, false, hold, newgame)
|
||||||
|
end
|
||||||
|
|
||||||
|
--function Input.cancel(accept)
|
||||||
|
function Input.cancel()
|
||||||
|
--if accept and Memory.value("menu", "shop_current") == 20 then
|
||||||
|
--if accept and Memory.value("menu", "shop_current") == 30 then
|
||||||
|
-- Input.press(accept)
|
||||||
|
--else
|
||||||
|
local button
|
||||||
|
if bCancel then
|
||||||
|
button = "B"
|
||||||
|
else
|
||||||
|
button = "A"
|
||||||
|
end
|
||||||
|
sendButton(button, true)
|
||||||
|
--sendButton(button, false)
|
||||||
|
bCancel = not bCancel
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Input.escape()
|
||||||
|
local rowSelected = Memory.value("battle", "menuY")
|
||||||
|
local columnSelected = Memory.value("battle", "menuX")
|
||||||
|
if not Input.isWaiting() then
|
||||||
|
if rowSelected == 1 then
|
||||||
|
Input.press("Down", 2)
|
||||||
|
else
|
||||||
|
if columnSelected == 1 then
|
||||||
|
Input.press("Right", 2)
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Input.clear()
|
||||||
|
currentButton = nil
|
||||||
|
remainingFrames = -1
|
||||||
|
end
|
||||||
|
|
||||||
|
function Input.update()
|
||||||
|
if currentButton then
|
||||||
|
remainingFrames = remainingFrames - 1
|
||||||
|
if remainingFrames >= 0 then
|
||||||
|
if remainingFrames > 0 then
|
||||||
|
sendButton(currentButton)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
currentButton = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
setForFrame = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function Input.advance()
|
||||||
|
if not setForFrame then
|
||||||
|
bridgeButton("e")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Input.setDebug(enabled)
|
||||||
|
debug = enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
return Input
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
local Memory = {}
|
||||||
|
|
||||||
|
local memoryNames = {
|
||||||
|
setting = {
|
||||||
|
text_speed = 0x5E0A, --139-136-128
|
||||||
|
battle_animation = 0x5E0C, --141=on 133=off
|
||||||
|
battle_style = 0x5E0E, --135=shift 132=set
|
||||||
|
sound_style = 0x5E10, --142=mono 145=stereo
|
||||||
|
button_style = 0x5E12, --
|
||||||
|
windows_style = 0x5E14, --0 to 7
|
||||||
|
},
|
||||||
|
text_inputing = {
|
||||||
|
column = 0x2065E,
|
||||||
|
row = 0x20660,
|
||||||
|
mode = 0x206A4,
|
||||||
|
},
|
||||||
|
--[[inventory = {
|
||||||
|
item_count = 0x1892,
|
||||||
|
item_base = 0x1893,
|
||||||
|
},]]
|
||||||
|
menu = {
|
||||||
|
row = 0x5E0A,
|
||||||
|
input_row = 0x5E08,
|
||||||
|
settings_row = 0x5E14,
|
||||||
|
start_menu_row = 0x3CD92,
|
||||||
|
hours_row = 0x5E0C, --(0-23)
|
||||||
|
minutes_row = 0x5E0E, --(0-59)
|
||||||
|
|
||||||
|
--item_row = 0x110C,
|
||||||
|
--item_row_size = 0x110D,
|
||||||
|
|
||||||
|
column = 0x3CE5D,
|
||||||
|
current = 0x0820, --
|
||||||
|
--size = 0x0FA3,
|
||||||
|
main_current = 0x5E00,
|
||||||
|
option_current = 0x0859,
|
||||||
|
settings_current = 0x5E01,
|
||||||
|
--shop_current = 0x0F87,
|
||||||
|
--selection = 0x0F78,
|
||||||
|
text_input = 0x20667, --1=inputing
|
||||||
|
text_length = 0x217FA, -- -7
|
||||||
|
main = 0x0819,
|
||||||
|
--pokemon = 0x0C51, --TO DO, USED WHILE EVOLVING
|
||||||
|
--selection_mode = 0x0C35, --TO DO, USED WHEN SWAPING MOVE
|
||||||
|
--transaction_current = 0x0F8B,--TODO, USED FOR SHOPPING
|
||||||
|
},
|
||||||
|
player = {
|
||||||
|
--name = 0x147D,
|
||||||
|
--name2 = 0x1493,
|
||||||
|
moving = 0x37593, --1 = moving
|
||||||
|
facing = 0x37368, --17=S // 34=N // 51=W // 68=E
|
||||||
|
--repel = 0x1CA1,
|
||||||
|
--party_size = 0x1CD7,
|
||||||
|
},
|
||||||
|
game = {
|
||||||
|
--battle = 0x122D, --1=wild 2=trainer
|
||||||
|
ingame = 0x0E08,
|
||||||
|
textbox = 0x0E40,
|
||||||
|
--textbox = 0x5DF0,
|
||||||
|
--textboxing = 0x5ECC,
|
||||||
|
},
|
||||||
|
time = {
|
||||||
|
--hours = 0x24A87,
|
||||||
|
--minutes = 0x24A88,
|
||||||
|
--seconds = 0x24A89,
|
||||||
|
--frames = 0x24A8A,
|
||||||
|
frames = 0x249C0,
|
||||||
|
},
|
||||||
|
--[[shop = {
|
||||||
|
--transaction_amount = 0x110C,
|
||||||
|
},]]
|
||||||
|
battle = {
|
||||||
|
text = 0x24068, --
|
||||||
|
menu = 0x5D60, --106=106(att) // 186=94(main) // 128=233(item) // 145=224(pkmon)
|
||||||
|
--menuX = 0x0FAA, --used for battle menu Row-X
|
||||||
|
--menuY = 0x0FA9, --used for battle menu Row-Y
|
||||||
|
--battle_turns = 0x06DD, --USED FOR DSUM ESCAPE??
|
||||||
|
|
||||||
|
opponent_id = 0x240DC, --or 0x1204??
|
||||||
|
opponent_level = 0x24106,
|
||||||
|
opponent_type1 = 0x240FD,
|
||||||
|
opponent_type2 = 0x240FE,
|
||||||
|
--opponent_move_id = 0x240E8, --used to get opponent moves ID's
|
||||||
|
--opponent_move_pp = 0x24100, --used to get opponent moves PP's
|
||||||
|
|
||||||
|
our_id = 0x24084,
|
||||||
|
--our_status = 0x063A,
|
||||||
|
our_level = 0x240AE,
|
||||||
|
our_type1 = 0x240A5,
|
||||||
|
our_type2 = 0x240A6,
|
||||||
|
--our_move_id = 0x24090, --used to get our moves ID's
|
||||||
|
--our_move_pp = 0x240A8, --used to get our moves PP's
|
||||||
|
|
||||||
|
--our_pokemon_list = 0x1288 --used to retract any of our Pokemons values (slot 1-6)
|
||||||
|
|
||||||
|
--attack_turns = 0x06DC, --NOT USED??
|
||||||
|
--accuracy = 0x0D1E, --NOT DONE YET
|
||||||
|
--x_accuracy = 0x1063, --NOT DONE YET
|
||||||
|
--disabled = 0x0CEE, --NOT DONE YET
|
||||||
|
--paralyzed = 0x1018, --NOT DONE YET
|
||||||
|
--critical = 0x105E, --NOT DONE YET
|
||||||
|
--miss = 0x105F, --NOT DONE YET
|
||||||
|
--our_turn = 0x1FF1, --NOT DONE YET
|
||||||
|
|
||||||
|
--opponent_next_move = 0xC6E4, --NOT USED??
|
||||||
|
--opponent_last_move = 0x0FCC, --NOT DONE YET AND NOT USED??
|
||||||
|
--opponent_bide = 0x106F, --NOT DONE YET AND NOT USED??
|
||||||
|
},
|
||||||
|
|
||||||
|
--[[pokemon = {
|
||||||
|
exp1 = 0x1179,
|
||||||
|
exp2 = 0x117A, --NOT DONE YET
|
||||||
|
exp3 = 0x117B,
|
||||||
|
},]]
|
||||||
|
}
|
||||||
|
|
||||||
|
local doubleNames = {
|
||||||
|
battle = {
|
||||||
|
opponent_hp = 0x24104,
|
||||||
|
opponent_max_hp = 0x24108,
|
||||||
|
opponent_attack = 0x240DE,
|
||||||
|
opponent_defense = 0x240E0,
|
||||||
|
opponent_speed = 0x240E2,
|
||||||
|
opponent_special_attack = 0x240E4,
|
||||||
|
opponent_special_defense = 0x240E6,
|
||||||
|
|
||||||
|
our_hp = 0x240AC,
|
||||||
|
our_max_hp = 0x240B0,
|
||||||
|
our_attack = 0x24086,
|
||||||
|
our_defense = 0x24088,
|
||||||
|
our_speed = 0x2408A,
|
||||||
|
our_special_attack = 0x2408C,
|
||||||
|
our_special_defense = 0x2408E,
|
||||||
|
},
|
||||||
|
|
||||||
|
game = {
|
||||||
|
map = 0x37359,
|
||||||
|
},
|
||||||
|
|
||||||
|
player = {
|
||||||
|
x = 0x37364,
|
||||||
|
y = 0x37366,
|
||||||
|
},
|
||||||
|
|
||||||
|
--[[pokemon = {
|
||||||
|
attack = 0x117E,
|
||||||
|
defense = 0x1181, --NOT DONE YET
|
||||||
|
speed = 0x1183,
|
||||||
|
special = 0x1185,
|
||||||
|
},]]
|
||||||
|
}
|
||||||
|
|
||||||
|
local function raw(address)
|
||||||
|
if string.len(tostring(address)) == 6 then
|
||||||
|
memory.usememorydomain("EWRAM")
|
||||||
|
else
|
||||||
|
memory.usememorydomain("IWRAM")
|
||||||
|
end
|
||||||
|
return memory.readbyte(address)
|
||||||
|
end
|
||||||
|
Memory.raw = raw
|
||||||
|
|
||||||
|
function Memory.string(first, last)
|
||||||
|
local a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ():;[]abcdefghijklmnopqrstuvwxyz?????????????????????????????????????????-???!.????????*?/.?0123456789"
|
||||||
|
local str = ""
|
||||||
|
while first <= last do
|
||||||
|
local v = raw(first) - 127
|
||||||
|
if v < 1 then
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
str = str..string.sub(a, v, v)
|
||||||
|
first = first + 1
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
||||||
|
function Memory.double(section, key)
|
||||||
|
local first = doubleNames[section][key]
|
||||||
|
return raw(first) + raw(first + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Memory.value(section, key)
|
||||||
|
local memoryAddress = memoryNames[section]
|
||||||
|
if key then
|
||||||
|
memoryAddress = memoryAddress[key]
|
||||||
|
end
|
||||||
|
return raw(memoryAddress)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Memory.getAddress(section, key)
|
||||||
|
local memoryAddress = memoryNames[section]
|
||||||
|
if key then
|
||||||
|
memoryAddress = memoryAddress[key]
|
||||||
|
end
|
||||||
|
return memoryAddress
|
||||||
|
end
|
||||||
|
|
||||||
|
return Memory
|
|
@ -0,0 +1,209 @@
|
||||||
|
local Menu = {}
|
||||||
|
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
|
||||||
|
local sliding = false
|
||||||
|
|
||||||
|
-- Private functions
|
||||||
|
|
||||||
|
--local function getRow(menuType, scrolls)
|
||||||
|
local function getRow(menuType)
|
||||||
|
if menuType then
|
||||||
|
menuType = menuType.."_row"
|
||||||
|
else
|
||||||
|
menuType = "row"
|
||||||
|
end
|
||||||
|
local row = Memory.value("menu", menuType)
|
||||||
|
return row
|
||||||
|
end
|
||||||
|
|
||||||
|
--local function setRow(desired, throttle, scrolls, menuType, loop)
|
||||||
|
local function setRow(desired, throttle, menuType, loop)
|
||||||
|
local currentRow = getRow(menuType)
|
||||||
|
if throttle == "accelerate" then
|
||||||
|
if sliding then
|
||||||
|
throttle = false
|
||||||
|
else
|
||||||
|
local dist = math.abs(desired - currentRow)
|
||||||
|
if dist < 15 then
|
||||||
|
throttle = true
|
||||||
|
else
|
||||||
|
throttle = false
|
||||||
|
sliding = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
sliding = false
|
||||||
|
end
|
||||||
|
return Menu.balance(currentRow, desired, true, loop, throttle)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function isCurrently(desired, menuType)
|
||||||
|
if menuType then
|
||||||
|
if menuType ~= "main" then
|
||||||
|
menuType = menuType.."_current"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
menuType = "current"
|
||||||
|
end
|
||||||
|
return Memory.value("menu", menuType) == desired
|
||||||
|
end
|
||||||
|
Menu.isCurrently = isCurrently
|
||||||
|
|
||||||
|
-- Menu
|
||||||
|
|
||||||
|
function Menu.getCol()
|
||||||
|
return Memory.value("menu", "column")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu.open(desired, atIndex, menuType)
|
||||||
|
if isCurrently(desired, menuType) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Menu.select(atIndex, false, menuType)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--function Menu.select(option, throttle, scrolls, menuType, dontPress, loop)
|
||||||
|
function Menu.select(option, throttle, menuType, dontPress, loop)
|
||||||
|
--Reset MenuType
|
||||||
|
local menuTypeSent
|
||||||
|
if menuType == "option" then
|
||||||
|
menuTypeSent = nil
|
||||||
|
else
|
||||||
|
menuTypeSent = menuType
|
||||||
|
end
|
||||||
|
if setRow(option, throttle, menuTypeSent, loop) then
|
||||||
|
local delay = 1
|
||||||
|
if throttle or menuType == "option" then
|
||||||
|
delay = 2
|
||||||
|
end
|
||||||
|
if not dontPress then
|
||||||
|
Input.press("A", delay)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu.cancel(desired, menuType)
|
||||||
|
if not isCurrently(desired, menuType) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Input.press("B")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Selections
|
||||||
|
|
||||||
|
function Menu.balance(current, desired, inverted, looping, throttle)
|
||||||
|
if current == desired then
|
||||||
|
sliding = false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if not throttle then
|
||||||
|
throttle = 0
|
||||||
|
else
|
||||||
|
throttle = 1
|
||||||
|
end
|
||||||
|
local goUp
|
||||||
|
if inverted then
|
||||||
|
if desired < current then
|
||||||
|
goUp = true
|
||||||
|
else
|
||||||
|
goUp = false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
goUp = false
|
||||||
|
end
|
||||||
|
if looping and math.abs(current - desired) > math.floor(looping / 2) then
|
||||||
|
goUp = not goUp
|
||||||
|
end
|
||||||
|
if goUp then
|
||||||
|
Input.press("Up", throttle)
|
||||||
|
else
|
||||||
|
Input.press("Down", throttle)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu.sidle(current, desired, looping, throttle)
|
||||||
|
if current == desired then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if not throttle then
|
||||||
|
throttle = 0
|
||||||
|
else
|
||||||
|
throttle = 1
|
||||||
|
end
|
||||||
|
local goLeft = current > desired
|
||||||
|
if looping and math.abs(current - desired) > math.floor(looping / 2) then
|
||||||
|
goLeft = not goLeft
|
||||||
|
end
|
||||||
|
if goLeft then
|
||||||
|
Input.press("Left", throttle)
|
||||||
|
else
|
||||||
|
Input.press("Right", throttle)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu.setCol(desired, looping, throttle)
|
||||||
|
return Menu.sidle(Menu.getCol(), desired, looping, throttle)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Options
|
||||||
|
|
||||||
|
function Menu.setOption(name, desired)
|
||||||
|
local rowFor = {
|
||||||
|
text_speed = 0,
|
||||||
|
battle_animation = 1,
|
||||||
|
battle_style = 2,
|
||||||
|
sound_style = 3,
|
||||||
|
button_style = 4,
|
||||||
|
windows_style = 5,
|
||||||
|
}
|
||||||
|
if Memory.value("setting", name) == desired then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if setRow(rowFor[name], 2, "input") then
|
||||||
|
Menu.setCol(desired, false, 2)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pause menu
|
||||||
|
|
||||||
|
function Menu.isOpen()
|
||||||
|
return Memory.value("game", "textbox") == 1 or Memory.value("menu", "current") == 79
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu.close()
|
||||||
|
if Memory.value("game", "textbox") == 0 and Memory.value("menu", "main") == 0 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Input.press("B")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Menu.pause()
|
||||||
|
if Memory.value("game", "textbox") == 1 then
|
||||||
|
--if Memory.value("battle", "menu") == 95 then
|
||||||
|
if Memory.value("battle", "text") == 3 then
|
||||||
|
Input.cancel()
|
||||||
|
--[[else
|
||||||
|
local main = Memory.value("menu", "main")
|
||||||
|
if main > 2 and main ~= 64 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
Input.press("B")]]
|
||||||
|
elseif Memory.value("battle", "text") == 11 then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
Input.press("B")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("Start", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Menu
|
|
@ -0,0 +1,56 @@
|
||||||
|
local Paint = {}
|
||||||
|
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Player = require "util.player"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
|
||||||
|
local Pokemon = require "storage.pokemon"
|
||||||
|
|
||||||
|
local encounters = 0
|
||||||
|
local elapsedTime = Utils.elapsedTime
|
||||||
|
local drawText = Utils.drawText
|
||||||
|
|
||||||
|
function Paint.draw(currentMap)
|
||||||
|
local px, py = Player.position()
|
||||||
|
drawText(0, 30, currentMap.." : "..px..", "..py)
|
||||||
|
drawText(0, 0, elapsedTime())
|
||||||
|
|
||||||
|
--[[if Memory.value("game", "battle") > 0 then
|
||||||
|
local curr_hp = Pokemon.index(0, "hp")
|
||||||
|
local hpStatus
|
||||||
|
if curr_hp == 0 then
|
||||||
|
hpStatus = "DEAD"
|
||||||
|
elseif curr_hp <= math.ceil(Pokemon.index(0, "max_hp") * 0.2) then
|
||||||
|
hpStatus = "RED"
|
||||||
|
end
|
||||||
|
if hpStatus then
|
||||||
|
drawText(0, 70, hpStatus)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local tidx = Pokemon.indexOf("totodile")
|
||||||
|
if tidx ~= -1 then
|
||||||
|
local attack = Pokemon.index(tidx, "attack")
|
||||||
|
local defense = Pokemon.index(tidx, "defense")
|
||||||
|
local speed = Pokemon.index(tidx, "speed")
|
||||||
|
local scl_att = Pokemon.index(tidx, "special_attack")
|
||||||
|
local scl_def = Pokemon.index(tidx, "special_defense")
|
||||||
|
drawText(0, 90, attack.." | "..defense.." | "..speed.." | "..scl_att.." | "..scl_def)
|
||||||
|
end]]
|
||||||
|
local enc = " encounter"
|
||||||
|
if encounters > 1 then
|
||||||
|
enc = enc.."s"
|
||||||
|
end
|
||||||
|
drawText(0, 115, encounters..enc)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Paint.wildEncounters(count)
|
||||||
|
encounters = count
|
||||||
|
end
|
||||||
|
|
||||||
|
function Paint.reset()
|
||||||
|
encounters = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return Paint
|
|
@ -0,0 +1,42 @@
|
||||||
|
local Player = {}
|
||||||
|
|
||||||
|
local Textbox = require "action.textbox"
|
||||||
|
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
|
||||||
|
local facingDirections = {Up=34, Right=68, Left=51, Down=17}
|
||||||
|
|
||||||
|
function Player.isFacing(direction)
|
||||||
|
return Memory.value("player", "facing") == facingDirections[direction]
|
||||||
|
end
|
||||||
|
|
||||||
|
function Player.face(direction)
|
||||||
|
if Player.isFacing(direction) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if Textbox.handle() then
|
||||||
|
Input.press(direction, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Player.interact(direction, opposite)
|
||||||
|
if Player.face(direction) then
|
||||||
|
if not opposite then
|
||||||
|
Input.press("A", 2)
|
||||||
|
else
|
||||||
|
Input.press("B", 2)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Player.isMoving()
|
||||||
|
return Memory.value("player", "moving") ~= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Player.position()
|
||||||
|
return Memory.double("player", "x"), Memory.double("player", "y")
|
||||||
|
end
|
||||||
|
|
||||||
|
return Player
|
|
@ -0,0 +1,122 @@
|
||||||
|
local Settings = {}
|
||||||
|
|
||||||
|
local Textbox = require "action.textbox"
|
||||||
|
|
||||||
|
local Bridge = require "util.bridge"
|
||||||
|
local Input = require "util.input"
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
local Menu = require "util.menu"
|
||||||
|
local Utils = require "util.utils"
|
||||||
|
|
||||||
|
local settings_done = false
|
||||||
|
local Setting_done = false
|
||||||
|
|
||||||
|
local desired = {}
|
||||||
|
desired.text_speed = GAME_TEXT_SPEED
|
||||||
|
desired.battle_animation = GAME_BATTLE_ANIMATION
|
||||||
|
desired.battle_style = GAME_BATTLE_STYLE
|
||||||
|
desired.sound_style = GAME_SOUND_STYLE
|
||||||
|
desired.button_style = GAME_BUTTON_STYLE
|
||||||
|
desired.windows_style = GAME_WINDOWS_STYLE
|
||||||
|
|
||||||
|
local function isEnabled(name)
|
||||||
|
return Memory.value("setting", name) == desired[name]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- PUBLIC
|
||||||
|
|
||||||
|
function Settings.set(...)
|
||||||
|
--set vars
|
||||||
|
local startMenu = Memory.value("menu", "main")
|
||||||
|
local menuRow = Memory.value("menu", "row")
|
||||||
|
|
||||||
|
--set settings
|
||||||
|
if not settings_done then
|
||||||
|
for i,name in ipairs(arg) do
|
||||||
|
if not isEnabled(name) then
|
||||||
|
--open settings menu
|
||||||
|
if startMenu ~= 51 then
|
||||||
|
if menuRow ~= 1 then
|
||||||
|
Input.press("Down", 2)
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
--set options
|
||||||
|
else
|
||||||
|
Menu.setOption(name, desired[name])
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--setting done
|
||||||
|
settings_done = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--close option menu
|
||||||
|
if startMenu == 51 then
|
||||||
|
Input.press("B", 2)
|
||||||
|
end
|
||||||
|
if startMenu ~= 51 then
|
||||||
|
settings_done = false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Settings.startNewAdventure(startWait)
|
||||||
|
local startMenu = Memory.value("menu", "main")
|
||||||
|
--local MenuCurrent = Memory.value("menu", "current")
|
||||||
|
local SettingsCurrent = Memory.value("menu", "settings_current")
|
||||||
|
local Row = Memory.value("menu", "row")
|
||||||
|
local GenderRow = Memory.value("menu", "settings_row")
|
||||||
|
|
||||||
|
--press A
|
||||||
|
if startMenu == 30 then
|
||||||
|
Input.press("A", 2)
|
||||||
|
--press Start
|
||||||
|
elseif startMenu == 180 or startMenu == 20 or startMenu == 23 then
|
||||||
|
if not Setting_done and math.random(0, startWait) == 0 then
|
||||||
|
Input.press("Start")
|
||||||
|
end
|
||||||
|
--set settings
|
||||||
|
elseif startMenu == 49 or startMenu == 51 then
|
||||||
|
if not Setting_done then
|
||||||
|
if Settings.set("text_speed", "battle_animation", "battle_style", "sound_style", "button_style", "windows_style") then
|
||||||
|
Setting_done = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if Row ~= 0 then
|
||||||
|
Input.press("Up", 2)
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--Set Gender
|
||||||
|
elseif startMenu == 19 then
|
||||||
|
if SettingsCurrent == 13 or SettingsCurrent == 14 then
|
||||||
|
if GenderRow == 1 and GAME_GENDER == 2 then
|
||||||
|
Input.press("Down", 2)
|
||||||
|
elseif GenderRow == 2 and GAME_GENDER == 1 then
|
||||||
|
Input.press("Up", 2)
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
--Set Name&start adventure
|
||||||
|
elseif startMenu == 31 then
|
||||||
|
if SettingsCurrent < 100 then
|
||||||
|
--reset setting not done
|
||||||
|
Setting_done = false
|
||||||
|
--set our name
|
||||||
|
Textbox.name(PLAYER_NAME, true)
|
||||||
|
else
|
||||||
|
--start adventure
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Input.press("A", 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Settings
|
|
@ -0,0 +1,159 @@
|
||||||
|
local Utils = {}
|
||||||
|
|
||||||
|
local Memory = require "util.memory"
|
||||||
|
|
||||||
|
local EMP = 1
|
||||||
|
|
||||||
|
-- GENERAL
|
||||||
|
|
||||||
|
function Utils.dist(x1, y1, x2, y2)
|
||||||
|
return math.sqrt(math.pow(x2 - x1, 2) + math.pow(y2 - y1, 2))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.each(table, func)
|
||||||
|
for key,val in pairs(table) do
|
||||||
|
func(key.." = "..tostring(val)..",")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.eachi(table, func)
|
||||||
|
for idx,val in ipairs(table) do
|
||||||
|
if val then
|
||||||
|
func(idx.." "..val)
|
||||||
|
else
|
||||||
|
func(idx)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.match(needle, haystack)
|
||||||
|
for i,val in ipairs(haystack) do
|
||||||
|
if needle == val then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.key(needle, haystack)
|
||||||
|
for key,val in pairs(haystack) do
|
||||||
|
if needle == val then
|
||||||
|
return key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.capitalize(string)
|
||||||
|
return string:sub(1, 1):upper()..string:sub(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- GAME
|
||||||
|
|
||||||
|
function Utils.canPotionWith(potion, forDamage, curr_hp, max_hp)
|
||||||
|
local potion_hp
|
||||||
|
if potion == "full_restore" then
|
||||||
|
potion_hp = 9001
|
||||||
|
elseif potion == "super_potion" then
|
||||||
|
potion_hp = 50
|
||||||
|
else
|
||||||
|
potion_hp = 20
|
||||||
|
end
|
||||||
|
return math.min(curr_hp + potion_hp, max_hp) >= forDamage - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.ingame()
|
||||||
|
return Memory.value("game", "ingame") > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.onPokemonSelect(battleMenu)
|
||||||
|
--return battleMenu == 8 or battleMenu == 48 or battleMenu == 184 or battleMenu == 224
|
||||||
|
return battleMenu == 145
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.drawText(x, y, message)
|
||||||
|
gui.text(x * EMP, y * EMP, message)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TIME
|
||||||
|
|
||||||
|
local Hours = 0
|
||||||
|
local Minutes = 0
|
||||||
|
local Seconds = 0
|
||||||
|
local Current_frame = 0
|
||||||
|
local Current_frame_changed = 0
|
||||||
|
|
||||||
|
function Utils.reset()
|
||||||
|
Hours = 0
|
||||||
|
Minutes = 0
|
||||||
|
Seconds = 0
|
||||||
|
Current_frame = 0
|
||||||
|
Current_frame_changed = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.igt()
|
||||||
|
local hours = Hours
|
||||||
|
local mins = Minutes
|
||||||
|
local secs = Seconds
|
||||||
|
return (hours * 60 + mins) * 60 + secs
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clockSegment(unit)
|
||||||
|
if unit < 10 then
|
||||||
|
unit = "0"..unit
|
||||||
|
end
|
||||||
|
return unit
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.timeSince(prevTime)
|
||||||
|
local currTime = Utils.igt()
|
||||||
|
local diff = currTime - prevTime
|
||||||
|
local timeString
|
||||||
|
if diff > 0 then
|
||||||
|
local secs = diff % 60
|
||||||
|
local mins = math.floor(diff / 60)
|
||||||
|
timeString = clockSegment(mins)..":"..clockSegment(secs)
|
||||||
|
end
|
||||||
|
return currTime, timeString
|
||||||
|
end
|
||||||
|
|
||||||
|
function Utils.elapsedTime()
|
||||||
|
if not Utils.ingame() then
|
||||||
|
return "0:00:00"
|
||||||
|
else
|
||||||
|
--local secs = Memory.value("time", "seconds")
|
||||||
|
--local mins = Memory.value("time", "minutes")
|
||||||
|
--local hours = Memory.value("time", "hours")
|
||||||
|
local frames = Memory.value("time", "frames")
|
||||||
|
if Current_frame ~= frames then
|
||||||
|
Current_frame = frames
|
||||||
|
Current_frame_changed = Current_frame_changed + 1
|
||||||
|
if Current_frame_changed == 60 then
|
||||||
|
Current_frame_changed = 0
|
||||||
|
Seconds = Seconds + 1
|
||||||
|
if Seconds == 60 then
|
||||||
|
Seconds = 0
|
||||||
|
Minutes = Minutes + 1
|
||||||
|
if Minutes == 60 then
|
||||||
|
Minutes = 0
|
||||||
|
Hours = Hours + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return Hours..":"..clockSegment(Minutes)..":"..clockSegment(Seconds)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[function Utils.frames()
|
||||||
|
if Utils.ingame() then
|
||||||
|
|
||||||
|
else
|
||||||
|
local totalFrames = Memory.value("time", "hours") * 60
|
||||||
|
totalFrames = (totalFrames + Memory.value("time", "minutes")) * 60
|
||||||
|
totalFrames = (totalFrames + Memory.value("time", "seconds")) * 60
|
||||||
|
totalFrames = totalFrames + Memory.value("time", "frames")
|
||||||
|
return totalFrames
|
||||||
|
end]]
|
||||||
|
|
||||||
|
return Utils
|
Loading…
Reference in New Issue