First-commit
This commit is contained in:
parent
f3347eec0a
commit
13fdfa8b5a
|
@ -0,0 +1,70 @@
|
|||
# PokeBot Changelog
|
||||
|
||||
## Version 2 - Update 3 (2.3) -- 9 April 2015
|
||||
* Start of the bot
|
||||
* Created the No save Corruption Bot under 6days (blue version only)
|
||||
* Included the Any% Speedrun Bot
|
||||
* Allow Custom Name for Player/Rival/Pokemon
|
||||
* Can choice Between Pidgey & PP Strats
|
||||
* He remove automatically the last game save to improve speedrun time
|
||||
* He can continue a game where you saved the last spot
|
||||
* Updated to version 1.3 of Kylecoburn PokeBot (where the 2.3 start from)
|
||||
|
||||
## Version 2 - Update 4 (2.4) -- 10 April 2015
|
||||
* Fixed Resetting issue
|
||||
* Fixed issue while using Custom Path (when resetting to continue, he was resetting for newgame)
|
||||
* Fixed Squirtle naming for the Any% run
|
||||
* Fixed Strats issue, was not resetting
|
||||
* Fixed Pidgey deposal if 16HP
|
||||
* Fixed Forest Grabing Potion if we got an Encounter ?
|
||||
* Updated the changelog
|
||||
* Updated timeRequirement on the no save corruption run
|
||||
* Updated the first startup "Print" text, being more comprehensible
|
||||
* Added Red Routing to the No save Corruption (Abra cost higher, need to get more coins)
|
||||
* Added 'PidgeyStrats.md'
|
||||
* Added 'PPStrats.md'
|
||||
* Added Back NoReset in Control, I miss removed it earlier
|
||||
* Make the Bot reboot if not already running
|
||||
* Renamed Glitchless repository to Any% which makes understanding easier, I hope
|
||||
* Can use Upper&lower case letters for settings "STRING" which make less errors for beginner
|
||||
* Removed Critical&Repel Painting for the No Save Corruption Run
|
||||
|
||||
## Version 2 - Update 5 (2.5) -- 10 April 2015
|
||||
* Fixed possibly the issue that the bot stop working if we got only 1 ball and we still not caught Pidgey
|
||||
* Fixed Red route for No save corruption was missing 10coins for abra
|
||||
* Added printing the seed at the start of a run
|
||||
* Updated 'Readme.md' file
|
||||
* Updated time-related constants to `memoryNames.time`
|
||||
|
||||
## Version 2 - Update 6 (2.6) -- 11 April 2015
|
||||
* Updated to the original PokeBot base code **v1.4**
|
||||
* Updated Memory values in the glitch runs strategies file `(0xD to 0x1)`
|
||||
* Updated custom path, continue game, remove game function
|
||||
* Updated `readme.md`
|
||||
* Fixed for good I hope the issue with Pidgey and 1 ball left in the inventory
|
||||
* Added Bulbasaur Stats Checkup at Viridian Mart for the No save corruption
|
||||
* Added Readme for Modified original files
|
||||
* Added Git Release and/or Git tags of versions
|
||||
* Cleaned control command (shouldCatch and CanCatch) no more need to use *"noReset"*
|
||||
* Relocated Strategies function and `strategies.lua`
|
||||
* Relocated Owners values
|
||||
* Relocated Glitch Dir to No save corruption
|
||||
* Removed *"local"* from any settings values, making understanding easier for beginner
|
||||
* Replaced *"Running4Skip"* to *"Runing4Continue"*
|
||||
* Will only buy 1 pokeball if we forced it to PP strats for the No save corruption run
|
||||
|
||||
## Version 2 - Update 6 (2.6.1 & 2.6.2) -- 11 April 2015
|
||||
* Fixed minor issue which tempDir was missing from `strategies.lua`
|
||||
* Updated `Readme_Modified_Files_List`
|
||||
|
||||
## Version 2 - Update 6 (2.6.3) -- 11 April 2015
|
||||
* Fixed again minor issue with tempDir in `strategies.lua`
|
||||
* Fixed issue with buffed attack in No save corruption run
|
||||
* Fixed running4newgame issue, was not making a new game, if a save file existed and we rebooted manually
|
||||
* Fixed Version values are now a string values instead of a number (can use exemple "2.6.3")
|
||||
|
||||
## Version 2 - Update 6 (2.6.4) -- 11 April 2015
|
||||
* Fixed minor Memory value issue for the No Save Corruption run
|
||||
|
||||
## Version 2 - Update 6 (2.6.5) -- 11 April 2015
|
||||
* Fixed minor Menu value issue for the No Save Corruption run
|
|
@ -0,0 +1,37 @@
|
|||
# Nidoran Stat Requirements
|
||||
|
||||
### Overview
|
||||
|
||||
We catch Nidoran at level 3 or 4, west of Viridian City (level 2's are not acceptable for the route). Level 4 Nidorans have a bit more exp to start, allowing them to level up slightly earlier in a couple places - mostly helpful on Route 3.
|
||||
|
||||
Upon defeating Brock, our Nidoran reaches level 8 via exp sharing, and we can check his stats definitively for the first time. While possible to see them earlier by pausing, we can't tell what kind of stats they will become until we have observed a few level ups.
|
||||
|
||||
### Stats
|
||||
|
||||
Pokémon stats are described by HP, attack, defense, speed, and special. Special is used as both an attack and defense measurement for attacks designated as "special" internally.
|
||||
|
||||
The minimum stats at level 8 are **25** HP, **14** attack, **11** defense, **12** speed, **11** special.
|
||||
|
||||
The maximum stats at level 8 are **27** HP, **16** attack, **14** defense, **15** speed, **13** special.
|
||||
|
||||
HP and defense are almost irrelevant to the route. Having better than 11 defense is helpful for Shorts Kid's Ratatta - as we are in the process of catching up Nidoran's level, and he has high attack, this fight is quite dangerous.
|
||||
|
||||
### Requirements
|
||||
|
||||
We have stringent requirements for Nidoran's stats. High stats make the run significantly faster, and greatly increases our chances of survival.
|
||||
|
||||
The general requirements are **15-16** attack, **14-15** speed, **12-13** special. In addition, either attack must be 16 or speed must be 15. The reason for this is that if we reach Misty with a 15 attack, 14 speed Nidoran, our chances of survival are very bad. In this case, it is very likely that Starmie will both outspeed us, and require 3 hits from thrash.
|
||||
|
||||
### Probability
|
||||
|
||||
The following is the probability of a Nidoran stats being acceptable after defeating Brock. They are complicated slightly since we require 16 attack AND/OR 15 speed.
|
||||
|
||||
Equations are written as: probability of each *Attack* x *Speed* x *Special* multiplied together.
|
||||
|
||||
Chance of a **16 attack, 15 speed** Nidoran: 5/16 x 4/16 x 12/16 = 5.859375%
|
||||
|
||||
Chance of a **16 attack, 14 speed** Nidoran: 5/16 x 6/16 x 12/16 = 8.7890625%
|
||||
|
||||
Chance of a **15 attack, 15 speed** Nidoran: 6/16 x 4/16 x 12/16 = 7.03125%
|
||||
|
||||
Summed together gives us our chances of an acceptable Nidoran: 21.6796875% ≈ **22%**
|
|
@ -0,0 +1,39 @@
|
|||
# PP Stat Requirements
|
||||
|
||||
|
||||
### Overview
|
||||
|
||||
We need a certain kind of PP attack available, on certain kind of attack, at certain kind of position.
|
||||
|
||||
Seems odd to read this like so? but you will understand my sentence below fast.
|
||||
|
||||
|
||||
### Stats
|
||||
|
||||
Bulbasaur need to be at level 8 or 10 otherwise it's not working. The bot will reset if he reach the level 9.
|
||||
|
||||
It would take too much time to hit the level 10 with again the perfect amount of PP available.
|
||||
|
||||
|
||||
### Requirements
|
||||
|
||||
About the PP we need 16PP available on Tackle, 36PP on Growl and any other attack learned.
|
||||
|
||||
We need to tranfert Tackle at the Position 2 and Growl at the Position 3, that's why we need a 3rd attack.
|
||||
|
||||
The PP amount of the 3rd attack (now in position 1) should not mind, but the bot use Leech Seed which is
|
||||
|
||||
sometimes learned to Bulbasaur when he reach level 7 or 8, and he dont use any PP on it so 10PP to leech seed.
|
||||
|
||||
|
||||
### Probability
|
||||
|
||||
The probability of working here are extremely high, the only know issue it's if we start battling Weedle
|
||||
|
||||
at level 6 and we got a little exp earned, we might go directly to level 8 which makig Bulbasaur not neccesary
|
||||
|
||||
learning leech seed and will result into a reset because we don't have 3 attacks. Sometimes he can use too much
|
||||
|
||||
tackle before being in Pewter City, which also result in a reset because it would take too much time to heal and
|
||||
|
||||
perform the "PP strat" after the healing. After all, I could say the probability are nearly 80-90% chance of work.
|
|
@ -0,0 +1,33 @@
|
|||
# Pidgey Stat Requirements
|
||||
|
||||
|
||||
### Overview
|
||||
|
||||
We need to catch a Pidgey, at north of Viridian City.
|
||||
|
||||
But it's not that much easy since we need specials stats and requirements
|
||||
|
||||
|
||||
### Stats
|
||||
|
||||
Pidgey don't need any special stats for the glitch to work. Only need some kind of HP.
|
||||
|
||||
But Bulbasaur need to be at 16special otherwise it'll not work.
|
||||
|
||||
|
||||
### Requirements
|
||||
|
||||
Pidgey only need to have his HP (health) at the proper amount.
|
||||
|
||||
It will work if he got 8, 10, 13, 15, 16 or 17HP.
|
||||
|
||||
At 8 or 13HP we don't need to Hold B while going to Saffron City, otherwise we need to Hold B while moving.
|
||||
|
||||
At 16HP we need to PC Save at Saffron City (by swaping box) to continue the run.
|
||||
|
||||
|
||||
### Probability
|
||||
|
||||
Catching a Pidgey with the needed amount of health it's easy and it's 100% probable to get one without reset for time.
|
||||
|
||||
But because Bulbasaur need to have a Special of 16 it result in a probability nearly 40%.
|
|
@ -0,0 +1,53 @@
|
|||
# PokéBot V2
|
||||
|
||||
An automated computer program that speedruns Pokémon Red, Blue, or Yellow.
|
||||
|
||||
Pokémon Red Any%: [1:51:11](https://www.youtube.com/watch?v=M4pOlQ-mIoc) (23 June 2014)
|
||||
|
||||
## Watch live
|
||||
|
||||
### [twitch.tv/thepokebot](http://www.twitch.tv/thepokebot)
|
||||
|
||||
PokéBot’s official streaming channel on Twitch. Consider following there to find out when we’re streaming, or follow the [Twitter feed](https://twitter.com/thepokebot) for announcements when we get personal best pace runs going.
|
||||
|
||||
### Run the bot locally
|
||||
|
||||
Running the PokéBot on your own machine is easy. You will need a Windows environment (it runs great in VMs on Mac/Linux too).
|
||||
|
||||
1. First, clone this repository (or download and unzip it) to your computer.
|
||||
|
||||
2. Download the [BizHawk 1.6.1](http://sourceforge.net/projects/bizhawk/files/BizHawk/BizHawk-1.6.1.zip/download) emulator and extract the ZIP file anywhere you like to “install” it.
|
||||
|
||||
**Note:** BizHawk v1.6.1 (Windows only) is the only version known to work. Later versions like v1.7.2a do not seem to work, due to differences with reading bytes from memory.
|
||||
|
||||
3. Run [the BizHawk prerequisites installer](http://sourceforge.net/projects/bizhawk/files/Prerequisites/bizhawk_prereqs_v1.1.zip/download), which should update a C++ distributable needed by BizHawk.
|
||||
|
||||
4. Procure a ROM file of Pokémon Red, Blue or Yellow english version (japan might not work and you should personally own the game).
|
||||
|
||||
5. Open the ROM file with BizHawk (drag the `.gb` file onto EmuHawk), and Pokémon should start up. Otherwise select Open ROM in EmuHawk.
|
||||
|
||||
6. The colors may look weird. To fix this, go to _GB_ → _Palette Editor_, and then find the `POKEMON ***.pal` file which should be under _Gameboy_ → _Palettes_ in the directory where BizHawk was extracted.
|
||||
|
||||
7. If you want to test the full run, set [`RESET_FOR_TIME` in `main.lua`](https://github.com/kylecoburn/PokeBot/blob/0fd1258ca17f7d74edbac72fa0afc2b5c6d58bb3/main.lua#L3) to `false` instead of `true`.
|
||||
|
||||
8. Then, under the _Tools_ menu, select _Lua Console_. Click the “open folder” button, and navigate to the PokéBot folder you downloaded. Select `main.lua` and press “open”. The bot should start running!
|
||||
|
||||
## Seeds
|
||||
|
||||
PokéBot comes with a built-in run recording feature that takes advantage of random number seeding to reproduce runs in their entirety. Any time the bot resets or beats the game, it will log a number to the Lua console that is the seed for the run. If you set `CUSTOM_SEED` in `main.lua` to that number, the bot will reproduce your run, allowing you to [share your times with others](Seeds.md). Note that making any other modifications will prevent this from working. So if you want to make changes to the bot and share your time, be sure to fork the repo and push your changes.
|
||||
|
||||
## Credits
|
||||
|
||||
### Developers
|
||||
|
||||
Kyle Coburn: Original concept, Red routing
|
||||
|
||||
Michael Jondahl: Combat algorithm, Java bridge for connecting the bot to Twitch chat, LiveSplit, Twitter, etc.
|
||||
|
||||
Marc-Andre Boulet(Bouletmarc): PokeBot V2, create No save corruption runs, added fews options, etc.
|
||||
|
||||
### Special thanks
|
||||
|
||||
To LiveSplit for providing custom component for integrating in-game time splits.
|
||||
|
||||
To the Pokémon speedrunning community members who inspired the idea, and shared ways to improve the bot.
|
|
@ -0,0 +1,85 @@
|
|||
# Modified files from the original bot
|
||||
|
||||
|
||||
## Not modified files :
|
||||
|
||||
**Action :**
|
||||
|
||||
`action/battle.lua`
|
||||
|
||||
`action/shop.lua`
|
||||
|
||||
|
||||
**Ai :**
|
||||
|
||||
`ai/combat.lua`
|
||||
|
||||
**Data :**
|
||||
|
||||
`data/any%/red-blue/paths.lua`
|
||||
|
||||
`data/any%/yellow/paths.lua`
|
||||
|
||||
`data/movelist.lua`
|
||||
|
||||
`data/opponents.lua`
|
||||
|
||||
|
||||
**Util :**
|
||||
|
||||
`util/any%/paint.lua`
|
||||
|
||||
`util/bridge.lua`
|
||||
|
||||
`util/memory.lua`
|
||||
|
||||
`util/menu.lua`
|
||||
|
||||
`util/utils.lua`
|
||||
|
||||
|
||||
## Modified files (with description) :
|
||||
|
||||
`main.lua` --Added tons of settings also newGame and continueGame function
|
||||
|
||||
|
||||
**Action :**
|
||||
|
||||
`action/textbox.lua` --Added 1-7 letters naming function
|
||||
|
||||
`action/walk.lua` --Added Custom path function + holding B on walk function
|
||||
|
||||
|
||||
**Ai :**
|
||||
|
||||
`ai/any%/strategies.lua` --Added reset running values for newGame and continueGame
|
||||
|
||||
`ai/any%/red-blue/strategies.lua` --Added Squirtle custom name function
|
||||
|
||||
`ai/control.lua` --Added NoSaveCorruption Exp, Catch pidgey and require function at the bottom
|
||||
|
||||
|
||||
**Storage :**
|
||||
|
||||
`storage/inventory.lua` --Added burn_heal and coin_case to the list
|
||||
|
||||
`storage/pokemon.lua` --Added Abra and Bulbasaur, added attack leech_seed and teleport
|
||||
|
||||
|
||||
**Util :**
|
||||
|
||||
`util/input.lua` --Added hold B, removeGame and waiting functions
|
||||
|
||||
`util/player.lua` --Added player disinteract command (pressing B instead of A)
|
||||
|
||||
`util/settings.lua` --Added battle_style = SET if not yellow, newGame, continueGame and setName function
|
||||
|
||||
|
||||
## Modified folder path in files (dir) :
|
||||
|
||||
`main.lua` -- strategies.lua and paint.lua
|
||||
|
||||
`action/walk.lua` -- paths.lua
|
||||
|
||||
`ai/control.lua` -- strategies.lua and paint.lua
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# Seeds for epic runs
|
||||
|
||||
PokéBot comes with a built-in run recording feature that takes advantage of random number seeding to reproduce runs in their entirety. Any time the bot resets or beats the game, it logs a number to the Lua console that is the seed for the run. This seed allows you to easily share the run with others.
|
||||
|
||||
Have you found a seed that results in a run of `1:53:00` or better? [Let us know](https://github.com/kylecoburn/PokeBot/issues/4), and we’ll add it to the list!
|
||||
|
||||
| Time | Frames | Seed | Bot version | Found by |
|
||||
|---------|--------|--------------|-------------|----------|
|
||||
| 1:50:37 | 398226 | `1428414915` | v1.3.0 | Gofigga |
|
||||
|
||||
To reproduce any of these runs, set [`CUSTOM_SEED` in `main.lua`](https://github.com/kylecoburn/PokeBot/blob/0ec69a6a958d15b3a9dccb492fa83e4a1dcae2e0/main.lua#L5) to the seed number and run the bot.
|
|
@ -0,0 +1,284 @@
|
|||
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
|
||||
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
|
||||
return true
|
||||
elseif battleMenu == 94 then
|
||||
local rowSelected = Memory.value("menu", "row")
|
||||
if col == 9 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)
|
||||
end
|
||||
end
|
||||
|
||||
function movePP(name)
|
||||
local midx = Pokemon.battleMove(name)
|
||||
if not midx then
|
||||
return 0
|
||||
end
|
||||
return Memory.raw(0x102C + 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
|
||||
if Memory.value("menu", "text_length") == 127 then
|
||||
Input.press("B")
|
||||
else
|
||||
Input.cancel()
|
||||
end
|
||||
elseif Textbox.handle() then
|
||||
local selected = Memory.value("menu", "selection")
|
||||
if selected == 239 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,177 @@
|
|||
local Textbox = {}
|
||||
|
||||
local Input = require "util.input"
|
||||
local Memory = require "util.memory"
|
||||
local Menu = require "util.menu"
|
||||
|
||||
local alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ *():;[]ab-?!mf/.,"
|
||||
-- local alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ *():;[]ポモ-?!♂♀/.,"
|
||||
|
||||
local nidoName = "A"
|
||||
local nidoIdx = 1
|
||||
|
||||
local TableNumber = 1
|
||||
local ActualUpper = 1
|
||||
|
||||
local function getLetterAt(index)
|
||||
return alphabet:sub(index, index)
|
||||
end
|
||||
|
||||
local function getIndexForLetter(letter)
|
||||
return alphabet:find(letter, 1, true)
|
||||
end
|
||||
|
||||
function Textbox.name(letter, randomize)
|
||||
local inputting = Memory.value("menu", "text_input") == 240
|
||||
if inputting then
|
||||
-- Values
|
||||
local lidx
|
||||
local crow
|
||||
local drow
|
||||
local ccol
|
||||
local dcol
|
||||
local NameTable = {}
|
||||
local Waiting
|
||||
|
||||
if letter then
|
||||
RUNNING4NEWGAME = false --make sure it's not running if we begin a game
|
||||
local StringLenght = string.len(letter)
|
||||
letter:gsub(".",function(letter2)
|
||||
table.insert(NameTable,letter2)
|
||||
|
||||
if NameTable[TableNumber] then
|
||||
local GetUpper
|
||||
--Set Special Chars & Get UpperCase
|
||||
if NameTable[TableNumber] == "<" then
|
||||
GetUpper = true
|
||||
lidx = 35
|
||||
elseif NameTable[TableNumber] == ">" then
|
||||
GetUpper = true
|
||||
lidx = 36
|
||||
elseif NameTable[TableNumber] == "{" then
|
||||
GetUpper = true
|
||||
lidx = 40
|
||||
elseif NameTable[TableNumber] == "}" then
|
||||
GetUpper = true
|
||||
lidx = 41
|
||||
else
|
||||
GetUpper = string.match(NameTable[TableNumber], '%u')
|
||||
lidx = getIndexForLetter(string.upper(NameTable[TableNumber]))
|
||||
end
|
||||
--Check For Waiting
|
||||
Waiting = Input.isWaiting()
|
||||
--Proceed
|
||||
if not Waiting then
|
||||
--Get/set Lower/Upper
|
||||
if GetUpper == nil and ActualUpper == 1 or GetUpper ~= nil and ActualUpper == 0 then
|
||||
crow = Memory.value("menu", "input_row")
|
||||
if Menu.balance(crow, 6, true, 6, true) then
|
||||
ccol = math.floor(Memory.value("menu", "column") / 2)
|
||||
if Menu.sidle(ccol, 0, 9, true) then
|
||||
Input.press("A")
|
||||
if ActualUpper == 1 then
|
||||
ActualUpper = 0
|
||||
elseif ActualUpper == 0 then
|
||||
ActualUpper = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
--Get/Set Letter
|
||||
else
|
||||
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")
|
||||
if Memory.value("menu", "text_length") == TableNumber then
|
||||
TableNumber = TableNumber + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
Waiting = Input.isWaiting()
|
||||
if TableNumber > StringLenght and not Waiting then
|
||||
if Memory.value("menu", "text_length") > 0 then
|
||||
Input.press("Start")
|
||||
TableNumber = 1
|
||||
ActualUpper = 1
|
||||
NameTable = {}
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
if Memory.value("menu", "text_length") > 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
|
||||
-- TODO cancel when menu isn't up
|
||||
|
||||
--Reset Values
|
||||
TableNumber = 1
|
||||
ActualUpper = 1
|
||||
NameTable = {}
|
||||
|
||||
if Memory.raw(0x10B7) == 3 then
|
||||
Input.press("A", 2)
|
||||
elseif randomize then
|
||||
Input.press("A", math.random(1, 5))
|
||||
else
|
||||
Input.cancel()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Textbox.getName()
|
||||
if nidoName == "a" then
|
||||
return "ポ"
|
||||
end
|
||||
if nidoName == "b" then
|
||||
return "モ"
|
||||
end
|
||||
if nidoName == "m" then
|
||||
return "♂"
|
||||
end
|
||||
if nidoName == "f" then
|
||||
return "♀"
|
||||
end
|
||||
return nidoName
|
||||
end
|
||||
|
||||
function Textbox.setName(index)
|
||||
if index >= 0 and index < #alphabet then
|
||||
nidoIdx = index + 1
|
||||
nidoName = getLetterAt(index)
|
||||
end
|
||||
end
|
||||
|
||||
function Textbox.isActive()
|
||||
return Memory.value("game", "textbox") == 1
|
||||
end
|
||||
|
||||
function Textbox.handle()
|
||||
if not Textbox.isActive() then
|
||||
return true
|
||||
end
|
||||
Input.cancel()
|
||||
end
|
||||
|
||||
return Textbox
|
|
@ -0,0 +1,195 @@
|
|||
local Walk = {}
|
||||
|
||||
local lowerGameRun = string.lower(GAME_RUN)
|
||||
local lowerGameName = string.lower(GAME_NAME)
|
||||
local secondStratDir = string.lower(GAME_NAME)
|
||||
if lowerGameRun == "any%" then
|
||||
if lowerGameName == "red" or lowerGameName == "blue" then
|
||||
secondStratDir = ".red-blue"
|
||||
end
|
||||
end
|
||||
|
||||
local Control = require "ai.control"
|
||||
local Paths = require("data."..lowerGameRun.."."..secondStratDir..".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
|
||||
local pathIdx = 0
|
||||
local customIdx = 1
|
||||
local customDir = 1
|
||||
local custom_done = false
|
||||
|
||||
-- Private functions
|
||||
|
||||
local function setPath(index, region)
|
||||
if PRINT_PATH then
|
||||
print("Path Idx : "..index.." *******")
|
||||
end
|
||||
pathIdx = index
|
||||
stepIdx = 2
|
||||
currentMap = region
|
||||
path = Paths[index]
|
||||
end
|
||||
|
||||
local function setPathCustom(index, region, Idx)
|
||||
if PRINT_PATH then
|
||||
print("Path Idx : "..index.." *******")
|
||||
end
|
||||
if PRINT_STEP then
|
||||
print("Step Idx : "..stepIdx)
|
||||
end
|
||||
pathIdx = index
|
||||
stepIdx = Idx
|
||||
currentMap = region
|
||||
path = Paths[index]
|
||||
custom_done = true
|
||||
end
|
||||
|
||||
local function completeStep(region)
|
||||
if PRINT_STEP then
|
||||
print("Step Idx : "..stepIdx)
|
||||
end
|
||||
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, hold)
|
||||
local px, py = Player.position()
|
||||
if px == dx and py == dy then
|
||||
return true
|
||||
end
|
||||
Input.press(dir(px, py, dx, dy), 0, hold)
|
||||
end
|
||||
Walk.step = step
|
||||
|
||||
-- Table functions
|
||||
|
||||
function Walk.reset()
|
||||
path = nil
|
||||
pathIdx = 0
|
||||
customIdx = 1
|
||||
customDir = 1
|
||||
currentMap = nil
|
||||
Walk.strategy = nil
|
||||
end
|
||||
|
||||
function Walk.init()
|
||||
local region = Memory.value("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[2]
|
||||
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
|
||||
if PATH_IDX ~= 0 and STEP_IDX ~= 0 and not custom_done then
|
||||
setPathCustom(PATH_IDX, region, STEP_IDX)
|
||||
newIndex = pathIdx
|
||||
else
|
||||
setPath(pathIdx + 1, region)
|
||||
newIndex = pathIdx
|
||||
end
|
||||
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]) 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
|
||||
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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,995 @@
|
|||
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
|
||||
|
||||
local status = {tries = 0, canProgress = nil, initialized = false}
|
||||
local stats = {}
|
||||
Strategies.status = status
|
||||
Strategies.stats = stats
|
||||
Strategies.updates = {}
|
||||
Strategies.deepRun = false
|
||||
|
||||
local strategyFunctions
|
||||
|
||||
-- RISK/RESET
|
||||
|
||||
function Strategies.getTimeRequirement(name)
|
||||
return Strategies.timeRequirements[name]()
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
function Strategies.death(extra)
|
||||
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
|
||||
|
||||
function Strategies.setYolo(name)
|
||||
if not RESET_FOR_TIME then
|
||||
return false
|
||||
end
|
||||
local minimumTime = Strategies.getTimeRequirement(name)
|
||||
local shouldYolo = Strategies.overMinute(minimumTime)
|
||||
if Control.yolo ~= shouldYolo then
|
||||
Control.yolo = shouldYolo
|
||||
Control.setYolo(shouldYolo)
|
||||
local prefix
|
||||
if Control.yolo then
|
||||
prefix = "en"
|
||||
else
|
||||
prefix = "dis"
|
||||
end
|
||||
print("YOLO "..prefix.."abled at "..Control.areaName)
|
||||
end
|
||||
return Control.yolo
|
||||
end
|
||||
|
||||
-- HELPERS
|
||||
|
||||
function Strategies.tweetProgress(message, progress)
|
||||
if progress then
|
||||
Strategies.updates[progress] = true
|
||||
message = message.." http://www.twitch.tv/thepokebot"
|
||||
end
|
||||
Bridge.tweet(message)
|
||||
end
|
||||
|
||||
function Strategies.initialize()
|
||||
if not status.initialized then
|
||||
status.initialized = true
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function Strategies.canHealFor(damage)
|
||||
local curr_hp = Pokemon.index(0, "hp")
|
||||
local max_hp = Pokemon.index(0, "max_hp")
|
||||
if max_hp - curr_hp > 3 then
|
||||
local healChecks = {"full_restore", "super_potion", "potion"}
|
||||
for idx,potion in ipairs(healChecks) do
|
||||
if Inventory.contains(potion) and Utils.canPotionWith(potion, damage, curr_hp, max_hp) then
|
||||
return potion
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Strategies.hasHealthFor(opponent, extra)
|
||||
if not extra then
|
||||
extra = 0
|
||||
end
|
||||
local afterHealth = math.min(Pokemon.index(0, "hp") + extra, Pokemon.index(0, "max_hp"))
|
||||
return afterHealth > Combat.healthFor(opponent)
|
||||
end
|
||||
|
||||
function Strategies.damaged(factor)
|
||||
if not factor then
|
||||
factor = 1
|
||||
end
|
||||
return Pokemon.index(0, "hp") * factor < Pokemon.index(0, "max_hp")
|
||||
end
|
||||
|
||||
function Strategies.opponentDamaged(factor)
|
||||
if not factor then
|
||||
factor = 1
|
||||
end
|
||||
return Memory.double("battle", "opponent_hp") * factor < Memory.double("battle", "opponent_max_hp")
|
||||
end
|
||||
|
||||
function Strategies.buffTo(buff, defLevel)
|
||||
if Battle.isActive() then
|
||||
status.canProgress = true
|
||||
local forced
|
||||
if defLevel and Memory.double("battle", "opponent_defense") > defLevel then
|
||||
forced = buff
|
||||
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
|
||||
|
||||
function Strategies.completedMenuFor(data)
|
||||
local count = Inventory.count(data.item)
|
||||
if count == 0 or (status.startCount and count + (data.amount or 1) <= status.startCount) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Strategies.closeMenuFor(data)
|
||||
if (not status.menuOpened and not data.close) or data.chain then
|
||||
return true
|
||||
end
|
||||
return Menu.close()
|
||||
end
|
||||
|
||||
function Strategies.useItem(data)
|
||||
local main = Memory.value("menu", "main")
|
||||
if not status.startCount then
|
||||
status.startCount = Inventory.count(data.item)
|
||||
if status.startCount == 0 then
|
||||
if Strategies.closeMenuFor(data) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
if Strategies.completedMenuFor(data) then
|
||||
if Strategies.closeMenuFor(data) then
|
||||
return true
|
||||
end
|
||||
elseif Menu.pause() then
|
||||
status.menuOpened = true
|
||||
Inventory.use(data.item, data.poke)
|
||||
end
|
||||
end
|
||||
|
||||
local function completedSkillFor(data)
|
||||
if data.map then
|
||||
if data.map ~= Memory.value("game", "map") then
|
||||
return true
|
||||
end
|
||||
elseif data.x or data.y then
|
||||
local px, py = Player.position()
|
||||
if data.x == px or data.y == py then
|
||||
return true
|
||||
end
|
||||
elseif data.done then
|
||||
if Memory.raw(data.done) > (data.val or 0) then
|
||||
return true
|
||||
end
|
||||
elseif status.tries > 0 and not Menu.isOpen() then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Strategies.isPrepared(...)
|
||||
if not status.preparing then
|
||||
return false
|
||||
end
|
||||
for i,name in ipairs(arg) do
|
||||
local currentCount = Inventory.count(name)
|
||||
if currentCount > 0 then
|
||||
local previousCount = status.preparing[name]
|
||||
if previousCount == nil or currentCount == previousCount then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Strategies.prepare(...)
|
||||
if not status.preparing then
|
||||
status.preparing = {}
|
||||
end
|
||||
local item
|
||||
for idx,name in ipairs(arg) do
|
||||
local currentCount = Inventory.count(name)
|
||||
local needsItem = currentCount > 0
|
||||
local previousCount = status.preparing[name]
|
||||
if previousCount == nil then
|
||||
status.preparing[name] = currentCount
|
||||
elseif needsItem then
|
||||
needsItem = currentCount == previousCount
|
||||
end
|
||||
if needsItem then
|
||||
item = name
|
||||
break
|
||||
end
|
||||
end
|
||||
if not item then
|
||||
return true
|
||||
end
|
||||
if Battle.isActive() then
|
||||
Inventory.use(item, nil, true)
|
||||
else
|
||||
Input.cancel()
|
||||
end
|
||||
end
|
||||
|
||||
-- GENERALIZED STRATEGIES
|
||||
|
||||
Strategies.functions = {
|
||||
|
||||
startFrames = function()
|
||||
Strategies.frames = 0
|
||||
return true
|
||||
end,
|
||||
|
||||
reportFrames = function()
|
||||
print("FR "..Strategies.frames)
|
||||
local repels = Memory.value("player", "repel")
|
||||
if repels > 0 then
|
||||
print("S "..repels)
|
||||
end
|
||||
Strategies.frames = nil
|
||||
return true
|
||||
end,
|
||||
|
||||
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,
|
||||
|
||||
item = function(data)
|
||||
if Battle.handleWild() then
|
||||
if data.full and not Inventory.isFull() then
|
||||
if Strategies.closeMenuFor(data) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
return Strategies.useItem(data)
|
||||
end
|
||||
end,
|
||||
|
||||
potion = function(data)
|
||||
local curr_hp = Pokemon.index(0, "hp")
|
||||
if curr_hp == 0 then
|
||||
return false
|
||||
end
|
||||
local toHP
|
||||
if Control.yolo and data.yolo ~= nil then
|
||||
toHP = data.yolo
|
||||
else
|
||||
toHP = data.hp
|
||||
end
|
||||
if type(toHP) == "string" then
|
||||
toHP = Combat.healthFor(toHP)
|
||||
end
|
||||
local toHeal = toHP - curr_hp
|
||||
if toHeal > 0 then
|
||||
local toPotion
|
||||
if data.forced then
|
||||
toPotion = Inventory.contains(data.forced)
|
||||
else
|
||||
local p_first, p_second, p_third
|
||||
if toHeal > 50 then
|
||||
if data.full then
|
||||
p_first = "full_restore"
|
||||
else
|
||||
p_first = "super_potion"
|
||||
end
|
||||
p_second, p_third = "super_potion", "potion"
|
||||
else
|
||||
if toHeal > 20 then
|
||||
p_first, p_second = "super_potion", "potion"
|
||||
else
|
||||
p_first, p_second = "potion", "super_potion"
|
||||
end
|
||||
if data.full then
|
||||
p_third = "full_restore"
|
||||
end
|
||||
end
|
||||
toPotion = Inventory.contains(p_first, p_second, p_third)
|
||||
end
|
||||
if toPotion then
|
||||
if Menu.pause() then
|
||||
Inventory.use(toPotion)
|
||||
status.menuOpened = true
|
||||
end
|
||||
return false
|
||||
end
|
||||
--TODO report wanted potion
|
||||
end
|
||||
if Strategies.closeMenuFor(data) then
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
teach = function(data)
|
||||
if data.full and not Inventory.isFull() then
|
||||
return true
|
||||
end
|
||||
local itemName
|
||||
if data.item then
|
||||
itemName = data.item
|
||||
else
|
||||
itemName = data.move
|
||||
end
|
||||
if Pokemon.hasMove(data.move) then
|
||||
local main = Memory.value("menu", "main")
|
||||
if main == 128 then
|
||||
if data.chain then
|
||||
return true
|
||||
end
|
||||
Input.press("B")
|
||||
elseif Menu.close() then
|
||||
return true
|
||||
end
|
||||
else
|
||||
if Strategies.initialize() then
|
||||
if not Inventory.contains(itemName) then
|
||||
return Strategies.reset("Unable to teach move "..itemName.." to "..data.poke, nil, true)
|
||||
end
|
||||
end
|
||||
local replacement
|
||||
if data.replace then
|
||||
replacement = Pokemon.moveIndex(data.replace, data.poke) - 1
|
||||
else
|
||||
replacement = 0
|
||||
end
|
||||
if Inventory.teach(itemName, data.poke, replacement, data.alt) then
|
||||
status.menuOpened = true
|
||||
else
|
||||
Menu.pause()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
skill = function(data)
|
||||
if completedSkillFor(data) then
|
||||
if not Textbox.isActive() then
|
||||
return true
|
||||
end
|
||||
Input.press("B")
|
||||
elseif not data.dir or Player.face(data.dir) then
|
||||
if Pokemon.use(data.move) then
|
||||
status.tries = status.tries + 1
|
||||
else
|
||||
Menu.pause()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
fly = function(data)
|
||||
if Memory.value("game", "map") == data.map then
|
||||
return true
|
||||
end
|
||||
local cities = {
|
||||
pallet = {62, "Up"},
|
||||
viridian = {63, "Up"},
|
||||
lavender = {66, "Down"},
|
||||
celadon = {68, "Down"},
|
||||
fuchsia = {69, "Down"},
|
||||
cinnabar = {70, "Down"},
|
||||
}
|
||||
|
||||
local main = Memory.value("menu", "main")
|
||||
if main == 228 then
|
||||
local currentFly = Memory.raw(0x1FEF)
|
||||
local destination = cities[data.dest]
|
||||
local press
|
||||
if destination[1] - currentFly == 0 then
|
||||
press = "A"
|
||||
else
|
||||
press = destination[2]
|
||||
end
|
||||
Input.press(press)
|
||||
elseif not Pokemon.use("fly") then
|
||||
Menu.pause()
|
||||
end
|
||||
end,
|
||||
|
||||
bicycle = function()
|
||||
if Memory.raw(0x1700) == 1 then
|
||||
if Textbox.handle() then
|
||||
return true
|
||||
end
|
||||
else
|
||||
return Strategies.useItem({item="bicycle"})
|
||||
end
|
||||
end,
|
||||
|
||||
swap = function(data)
|
||||
if Strategies.initialize() then
|
||||
if not Inventory.contains(data.item) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
local itemIndex = Inventory.indexOf(data.item)
|
||||
local destIndex = data.dest
|
||||
if type(destIndex) == "string" then
|
||||
destIndex = Inventory.indexOf(destIndex)
|
||||
end
|
||||
if itemIndex == destIndex then
|
||||
if Strategies.closeMenuFor(data) then
|
||||
return true
|
||||
end
|
||||
else
|
||||
local main = Memory.value("menu", "main")
|
||||
if main == 128 then
|
||||
if Menu.getCol() ~= 5 then
|
||||
Menu.select(2, true)
|
||||
else
|
||||
local selection = Memory.value("menu", "selection_mode")
|
||||
if selection == 0 then
|
||||
if Menu.select(destIndex, "accelerate", true, nil, true) then
|
||||
Input.press("Select")
|
||||
end
|
||||
else
|
||||
if Menu.select(itemIndex, "accelerate", true, nil, true) then
|
||||
Input.press("Select")
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
Menu.pause()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
wait = function()
|
||||
print("Please save state")
|
||||
Input.press("Start", 999999999)
|
||||
end,
|
||||
|
||||
emuSpeed = function(data)
|
||||
-- client.speedmode = data.percent
|
||||
return true
|
||||
end,
|
||||
|
||||
waitToTalk = function()
|
||||
if Battle.isActive() then
|
||||
status.canProgress = false
|
||||
Battle.automate()
|
||||
elseif Textbox.isActive() then
|
||||
status.canProgress = true
|
||||
Input.cancel()
|
||||
elseif status.canProgress then
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
waitToPause = function()
|
||||
local main = Memory.value("menu", "main")
|
||||
if main == 128 then
|
||||
if status.canProgress then
|
||||
return true
|
||||
end
|
||||
elseif Battle.isActive() then
|
||||
status.canProgress = false
|
||||
Battle.automate()
|
||||
elseif main == 123 then
|
||||
status.canProgress = true
|
||||
Input.press("B")
|
||||
elseif Textbox.handle() then
|
||||
Input.press("Start", 2)
|
||||
end
|
||||
end,
|
||||
|
||||
waitToFight = function(data)
|
||||
if Battle.isActive() then
|
||||
status.canProgress = true
|
||||
Battle.automate()
|
||||
elseif status.canProgress then
|
||||
return true
|
||||
elseif Textbox.handle() then
|
||||
if data.dir then
|
||||
Player.interact(data.dir)
|
||||
else
|
||||
Input.cancel()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
allowDeath = function(data)
|
||||
Control.canDie(data.on)
|
||||
return true
|
||||
end,
|
||||
|
||||
leer = function(data)
|
||||
local bm = Combat.bestMove()
|
||||
if not bm or bm.minTurns < 3 then
|
||||
if Battle.isActive() then
|
||||
status.canProgress = true
|
||||
elseif status.canProgress then
|
||||
return true
|
||||
end
|
||||
Battle.automate()
|
||||
return false
|
||||
end
|
||||
local opp = Battle.opponent()
|
||||
local defLimit = 9001
|
||||
for i,poke in ipairs(data) do
|
||||
if opp == poke[1] then
|
||||
local minimumAttack = poke[3]
|
||||
if not minimumAttack or stats.nidoran.attack > minimumAttack then
|
||||
defLimit = poke[2]
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
return Strategies.buffTo("leer", defLimit)
|
||||
end,
|
||||
|
||||
-- ROUTE
|
||||
|
||||
swapNidoran = function()
|
||||
local main = Memory.value("menu", "main")
|
||||
local nidoranIndex = Pokemon.indexOf("nidoran")
|
||||
if nidoranIndex == 0 then
|
||||
if Menu.close() then
|
||||
return true
|
||||
end
|
||||
elseif Menu.pause() then
|
||||
if yellow then
|
||||
if Inventory.contains("potion") and Pokemon.info("nidoran", "hp") < 15 then
|
||||
Inventory.use("potion", "nidoran")
|
||||
return false
|
||||
end
|
||||
else
|
||||
if Pokemon.info("squirtle", "status") > 0 then
|
||||
Inventory.use("antidote", "squirtle")
|
||||
return false
|
||||
end
|
||||
if Inventory.contains("potion") and Pokemon.info("squirtle", "hp") < 15 then
|
||||
Inventory.use("potion", "squirtle")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local column = Menu.getCol()
|
||||
if main == 128 then
|
||||
if column == 11 then
|
||||
Menu.select(1, true)
|
||||
elseif column == 12 then
|
||||
Menu.select(1, true)
|
||||
else
|
||||
Input.press("B")
|
||||
end
|
||||
elseif main == Menu.pokemon then --TODO check loop
|
||||
if Memory.value("menu", "selection_mode") == 1 then
|
||||
Menu.select(nidoranIndex, true)
|
||||
else
|
||||
Menu.select(0, true)
|
||||
end
|
||||
else
|
||||
Input.press("B")
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
swapHornAttack = function()
|
||||
if Pokemon.battleMove("horn_attack") == 1 then
|
||||
return true
|
||||
end
|
||||
Battle.swapMove(1, 3)
|
||||
end,
|
||||
|
||||
dodgePalletBoy = function()
|
||||
return Strategies.dodgeUp(0x0223, 14, 14, 15, 7)
|
||||
end,
|
||||
|
||||
evolveNidorino = function()
|
||||
if Pokemon.inParty("nidorino") then
|
||||
Bridge.caught("nidorino")
|
||||
return true
|
||||
end
|
||||
if Battle.isActive() then
|
||||
status.tries = 0
|
||||
status.canProgress = true
|
||||
if Memory.double("battle", "opponent_hp") == 0 then
|
||||
Input.press("A")
|
||||
else
|
||||
Battle.automate()
|
||||
end
|
||||
elseif status.tries > 3600 then
|
||||
print("Broke from Nidorino on tries")
|
||||
return true
|
||||
else
|
||||
if status.canProgress then
|
||||
status.tries = status.tries + 1
|
||||
end
|
||||
Input.press("A")
|
||||
end
|
||||
end,
|
||||
|
||||
catchFlierBackup = function()
|
||||
if Strategies.initialize() then
|
||||
Control.canDie(true)
|
||||
end
|
||||
if not Control.canCatch() then
|
||||
return true
|
||||
end
|
||||
local caught = Pokemon.inParty("pidgey", "spearow")
|
||||
if Battle.isActive() then
|
||||
if Memory.double("battle", "our_hp") == 0 then
|
||||
if Pokemon.info("squirtle", "hp") == 0 then
|
||||
Control.canDie(false)
|
||||
elseif Utils.onPokemonSelect(Memory.value("battle", "menu")) then
|
||||
Menu.select(Pokemon.indexOf("squirtle"), true)
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
else
|
||||
Battle.handle()
|
||||
end
|
||||
else
|
||||
local birdPath
|
||||
local px, py = Player.position()
|
||||
if caught then
|
||||
if px > 33 then
|
||||
return true
|
||||
end
|
||||
local startY = 9
|
||||
if px > 28 then
|
||||
startY = py
|
||||
end
|
||||
birdPath = {{32,startY}, {32,11}, {34,11}}
|
||||
elseif px == 37 then
|
||||
if py == 10 then
|
||||
py = 11
|
||||
else
|
||||
py = 10
|
||||
end
|
||||
Walk.step(px, py)
|
||||
else
|
||||
birdPath = {{32,10}, {32,11}, {34,11}, {34,10}, {37,10}}
|
||||
end
|
||||
if birdPath then
|
||||
Walk.custom(birdPath)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
evolveNidoking = function(data)
|
||||
if Battle.handleWild() then
|
||||
local usedMoonStone = not Inventory.contains("moon_stone")
|
||||
if Strategies.initialize() then
|
||||
if usedMoonStone then
|
||||
return true
|
||||
end
|
||||
if data.early then
|
||||
if not Control.getMoonExp then
|
||||
return true
|
||||
end
|
||||
if data.poke then
|
||||
if stats.nidoran.attack > 15 or not Pokemon.inParty(data.poke) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if data.exp and Pokemon.getExp() > data.exp then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
if usedMoonStone then
|
||||
if not status.canProgress then
|
||||
Bridge.caught("nidoking")
|
||||
status.canProgress = true
|
||||
end
|
||||
if Menu.close() then
|
||||
return true
|
||||
end
|
||||
elseif not Inventory.use("moon_stone") then
|
||||
Menu.pause()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
helix = function()
|
||||
if Battle.handleWild() then
|
||||
if Inventory.contains("helix_fossil") then
|
||||
return true
|
||||
end
|
||||
Player.interact("Up")
|
||||
end
|
||||
end,
|
||||
|
||||
reportMtMoon = function()
|
||||
if Battle.pp("horn_attack") == 0 then
|
||||
print("ERR: Ran out of Horn Attacks")
|
||||
end
|
||||
if Control.moonEncounters then
|
||||
local catchPokemon = yellow and "sandshrew" or "paras"
|
||||
local capsName = Utils.capitalize(catchPokemon)
|
||||
local parasStatus
|
||||
local conjunction = "but"
|
||||
local goodEncounters = Control.moonEncounters < 10
|
||||
local catchDescription
|
||||
if Pokemon.inParty(catchPokemon) then
|
||||
catchDescription = catchPokemon
|
||||
if goodEncounters then
|
||||
conjunction = "and"
|
||||
end
|
||||
parasStatus = "we caught a "..capsName.."!"
|
||||
else
|
||||
catchDescription = "no_"..catchPokemon
|
||||
if not goodEncounters then
|
||||
conjunction = "and"
|
||||
end
|
||||
parasStatus = "we didn't catch a "..capsName.." :("
|
||||
end
|
||||
Bridge.caught(catchDescription)
|
||||
Bridge.chat(Control.moonEncounters.." Moon encounters, "..conjunction.." "..parasStatus)
|
||||
Control.moonEncounters = nil
|
||||
end
|
||||
|
||||
Strategies.resetTime("mt_moon", "complete Mt. Moon", true)
|
||||
return true
|
||||
end,
|
||||
|
||||
dodgeCerulean = function()
|
||||
return dodgeH{
|
||||
npc = 0x0242,
|
||||
sx = 14, sy = 18,
|
||||
dodge = 19,
|
||||
offset = 10,
|
||||
dist = 4
|
||||
}
|
||||
end,
|
||||
|
||||
dodgeCeruleanLeft = function()
|
||||
return dodgeH{
|
||||
npc = 0x0242,
|
||||
sx = 16, sy = 18,
|
||||
dodge = 17,
|
||||
offset = 10,
|
||||
dist = -7,
|
||||
left = true
|
||||
}
|
||||
end,
|
||||
|
||||
playPokeflute = function()
|
||||
if Battle.isActive() then
|
||||
return true
|
||||
end
|
||||
if Memory.value("battle", "menu") == 95 then
|
||||
Input.press("A")
|
||||
elseif Menu.pause() then
|
||||
Inventory.use("pokeflute")
|
||||
end
|
||||
end,
|
||||
|
||||
push = function(data)
|
||||
local pos
|
||||
if data.dir == "Up" or data.dir == "Down" then
|
||||
pos = data.y
|
||||
else
|
||||
pos = data.x
|
||||
end
|
||||
local newP = Memory.raw(pos)
|
||||
if not status.startPosition then
|
||||
status.startPosition = newP
|
||||
elseif status.startPosition ~= newP then
|
||||
return true
|
||||
end
|
||||
Input.press(data.dir, 0)
|
||||
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
|
||||
Strategies.initGame(midGame)
|
||||
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
|
|
@ -0,0 +1,331 @@
|
|||
local lowerGameRun = string.lower(GAME_RUN)
|
||||
|
||||
local Strategies = require("ai."..lowerGameRun..".strategies")
|
||||
|
||||
local Combat = require "ai.combat"
|
||||
local Control = require "ai.control"
|
||||
|
||||
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 stats = Strategies.stats
|
||||
|
||||
local strategyFunctions = Strategies.functions
|
||||
|
||||
-- TIME CONSTRAINTS
|
||||
|
||||
Strategies.timeRequirements = {
|
||||
|
||||
nidoran = function()
|
||||
local timeLimit = 8
|
||||
if Pokemon.inParty("pidgey") then
|
||||
timeLimit = timeLimit + 0.67
|
||||
end
|
||||
return timeLimit
|
||||
end,
|
||||
|
||||
mt_moon = function()
|
||||
local timeLimit = 30
|
||||
if stats.nidoran.attack > 15 and stats.nidoran.speed > 14 then
|
||||
timeLimit = timeLimit + 0.25
|
||||
end
|
||||
if Pokemon.inParty("sandshrew") then
|
||||
timeLimit = timeLimit + 0.25
|
||||
end
|
||||
return timeLimit
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
-- HELPERS
|
||||
|
||||
local function depositPikachu()
|
||||
if not Textbox.isActive() then
|
||||
Player.interact("Up")
|
||||
else
|
||||
local pc = Memory.value("menu", "size")
|
||||
if Memory.value("battle", "menu") ~= 19 then
|
||||
local menuColumn = Menu.getCol()
|
||||
if menuColumn == 5 then
|
||||
Menu.select(Pokemon.indexOf("pikachu"))
|
||||
elseif menuColumn == 10 then
|
||||
Input.press("A")
|
||||
elseif pc == 3 then
|
||||
Menu.select(0)
|
||||
elseif pc == 5 then
|
||||
Menu.select(1)
|
||||
else
|
||||
Input.cancel()
|
||||
end
|
||||
else
|
||||
Input.cancel()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function takeCenter(pp, startMap, entranceX, entranceY, finishX)
|
||||
local px, py = Player.position()
|
||||
local currentMap = Memory.value("game", "map")
|
||||
local sufficientPP = Pokemon.pp(0, "horn_attack") > pp
|
||||
if currentMap == startMap then
|
||||
if not sufficientPP then
|
||||
if px ~= entranceX then
|
||||
px = entranceX
|
||||
else
|
||||
py = entranceY
|
||||
end
|
||||
else
|
||||
if px == finishX then
|
||||
return true
|
||||
end
|
||||
px = finishX
|
||||
end
|
||||
else
|
||||
if Pokemon.inParty("pikachu") then
|
||||
if py > 5 then
|
||||
py = 5
|
||||
elseif px < 13 then
|
||||
px = 13
|
||||
elseif py ~= 4 then
|
||||
py = 4
|
||||
else
|
||||
return depositPikachu()
|
||||
end
|
||||
else
|
||||
if px ~= 3 then
|
||||
if Menu.close() then
|
||||
px = 3
|
||||
end
|
||||
elseif sufficientPP then
|
||||
if Textbox.handle() then
|
||||
py = 8
|
||||
end
|
||||
elseif py > 3 then
|
||||
py = 3
|
||||
else
|
||||
strategyFunctions.confirm({dir="Up"})
|
||||
end
|
||||
end
|
||||
end
|
||||
Walk.step(px, py)
|
||||
end
|
||||
|
||||
-- STRATEGIES
|
||||
|
||||
-- dodgePalletBoy
|
||||
|
||||
strategyFunctions.shopViridianPokeballs = function()
|
||||
return Shop.transaction{
|
||||
buy = {{name="pokeball", index=0, amount=4}, {name="potion", index=1, amount=6}}
|
||||
}
|
||||
end
|
||||
|
||||
strategyFunctions.catchNidoran = function()
|
||||
if not Control.canCatch() then
|
||||
return true
|
||||
end
|
||||
local pokeballs = Inventory.count("pokeball")
|
||||
local caught = Memory.value("player", "party_size") > 1
|
||||
if pokeballs < (caught and 1 or 2) then
|
||||
return Strategies.reset("Ran too low on PokeBalls", pokeballs)
|
||||
end
|
||||
if Battle.isActive() then
|
||||
local isNidoran = Pokemon.isOpponent("nidoran")
|
||||
if isNidoran and Memory.value("battle", "opponent_level") == 6 then
|
||||
if Strategies.initialize() then
|
||||
Bridge.pollForName()
|
||||
end
|
||||
end
|
||||
status.tries = nil
|
||||
if Memory.value("menu", "text_input") == 240 then
|
||||
Textbox.name()
|
||||
elseif Memory.value("battle", "menu") == 95 then
|
||||
if isNidoran then
|
||||
Input.press("A")
|
||||
else
|
||||
Input.cancel()
|
||||
end
|
||||
else
|
||||
Battle.handle()
|
||||
end
|
||||
else
|
||||
Pokemon.updateParty()
|
||||
local hasNidoran = Pokemon.inParty("nidoran")
|
||||
if hasNidoran then
|
||||
Bridge.caught("nidoran")
|
||||
return true
|
||||
end
|
||||
|
||||
local timeLimit = Strategies.getTimeRequirement("nidoran")
|
||||
local resetMessage = "find a suitable Nidoran"
|
||||
if Strategies.resetTime(timeLimit, resetMessage) then
|
||||
return true
|
||||
end
|
||||
local px, py = Player.position()
|
||||
if py > 48 then
|
||||
py = 48
|
||||
elseif px < 9 then
|
||||
px = 9
|
||||
else
|
||||
px = 8
|
||||
end
|
||||
Walk.step(px, py) --TODO DSum
|
||||
end
|
||||
end
|
||||
|
||||
-- leer
|
||||
|
||||
strategyFunctions.checkNidoStats = function()
|
||||
local nidx = Pokemon.indexOf("nidoran")
|
||||
if Pokemon.index(nidx, "level") == 8 then
|
||||
local att = Pokemon.index(nidx, "attack")
|
||||
local def = Pokemon.index(nidx, "defense")
|
||||
local spd = Pokemon.index(nidx, "speed")
|
||||
local scl = Pokemon.index(nidx, "special")
|
||||
Bridge.stats(att.." "..def.." "..spd.." "..scl)
|
||||
stats.nidoran = {
|
||||
attack = att,
|
||||
defense = def,
|
||||
speed = spd,
|
||||
special = scl,
|
||||
}
|
||||
|
||||
local statDiff = (16 - att) + (15 - spd) + (13 - scl)
|
||||
local resets = att < 15 or spd < 14 or scl < 12 --RISK
|
||||
local nStatus = "Att: "..att..", Def: "..def..", Speed: "..spd..", Special: "..scl
|
||||
if resets then
|
||||
return Strategies.reset("Bad Nidoran - "..nStatus)
|
||||
end
|
||||
-- if def < 12 then
|
||||
-- statDiff = statDiff + 1
|
||||
-- end
|
||||
local superlative
|
||||
local exclaim = "!"
|
||||
if statDiff == 0 then
|
||||
if def == 14 then
|
||||
superlative = "God"
|
||||
exclaim = "! Kreygasm"
|
||||
else
|
||||
superlative = "Perfect"
|
||||
end
|
||||
elseif att == 16 and spd == 15 then
|
||||
if statDiff == 1 then
|
||||
superlative = "Great"
|
||||
elseif statDiff == 2 then
|
||||
superlative = "Good"
|
||||
else
|
||||
superlative = "Okay"
|
||||
end
|
||||
elseif statDiff == 1 then
|
||||
superlative = "Good"
|
||||
elseif statDiff == 2 then
|
||||
superlative = "Okay"
|
||||
exclaim = "."
|
||||
else
|
||||
superlative = "Min stat"
|
||||
exclaim = "."
|
||||
end
|
||||
nStatus = superlative.." Nidoran"..exclaim.." "..nStatus
|
||||
Bridge.chat(nStatus)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.centerViridian = function()
|
||||
return takeCenter(15, 2, 13, 25, 18)
|
||||
end
|
||||
|
||||
strategyFunctions.fightBrock = function()
|
||||
local curr_hp = Pokemon.info("nidoran", "hp")
|
||||
if curr_hp == 0 then
|
||||
return Strategies.death()
|
||||
end
|
||||
if Battle.isActive() then
|
||||
status.canProgress = true
|
||||
local __, turnsToKill, turnsToDie = Combat.bestMove()
|
||||
if turnsToDie and turnsToDie < 2 and Inventory.contains("potion") then
|
||||
Inventory.use("potion", "nidoran", true)
|
||||
else
|
||||
local bideTurns = Memory.value("battle", "opponent_bide")
|
||||
if bideTurns > 0 then
|
||||
local onixHP = Memory.double("battle", "opponent_hp")
|
||||
if status.tries == 0 then
|
||||
status.tries = onixHP
|
||||
status.startBide = bideTurns
|
||||
end
|
||||
if turnsToKill then
|
||||
local forced
|
||||
if turnsToKill < 2 or status.startBide - bideTurns > 1 then
|
||||
-- elseif turnsToKill < 3 and status.startBide == bideTurns then
|
||||
elseif onixHP == status.tries then
|
||||
forced = "leer"
|
||||
end
|
||||
Battle.fight(forced)
|
||||
else
|
||||
Input.cancel()
|
||||
end
|
||||
else
|
||||
status.tries = 0
|
||||
strategyFunctions.leer({{"onix", 13}})
|
||||
end
|
||||
end
|
||||
elseif status.canProgress then
|
||||
return true
|
||||
elseif Textbox.handle() then
|
||||
Player.interact("Up")
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.centerMoon = function()
|
||||
return takeCenter(5, 15, 11, 5, 12)
|
||||
end
|
||||
|
||||
-- reportMtMoon
|
||||
|
||||
-- PROCESS
|
||||
|
||||
function Strategies.initGame(midGame)
|
||||
if not STREAMING_MODE then
|
||||
-- Strategies.setYolo("")
|
||||
if Pokemon.inParty("nidoking") then
|
||||
stats.nidoran = {
|
||||
attack = 55,
|
||||
defense = 45,
|
||||
speed = 50,
|
||||
special = 45,
|
||||
}
|
||||
else
|
||||
stats.nidoran = {
|
||||
attack = 16,
|
||||
defense = 12,
|
||||
speed = 15,
|
||||
special = 13,
|
||||
level4 = true,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Strategies.completeGameStrategy()
|
||||
status = Strategies.status
|
||||
end
|
||||
|
||||
function Strategies.resetGame()
|
||||
status = Strategies.status
|
||||
stats = Strategies.stats
|
||||
end
|
||||
|
||||
return Strategies
|
|
@ -0,0 +1,406 @@
|
|||
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_I
|
||||
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, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=1.0, ice=1.0, dragon=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, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=0.5, ice=2.0, dragon=1.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, fire=1.0, water=1.0, grass=2.0, electric=0.5, psychic=1.0, ice=1.0, dragon=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, fire=1.0, water=1.0, grass=2.0, electric=1.0, psychic=1.0, ice=1.0, dragon=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, fire=2.0, water=1.0, grass=0.5, electric=2.0, psychic=1.0, ice=1.0, dragon=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, fire=2.0, water=1.0, grass=1.0, electric=1.0, psychic=1.0, ice=2.0, dragon=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, fire=0.5, water=1.0, grass=2.0, electric=1.0, psychic=2.0, ice=1.0, dragon=1.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, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=0.0, ice=1.0, dragon=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, fire=0.5, water=0.5, grass=2.0, electric=1.0, psychic=1.0, ice=2.0, dragon=0.5, },
|
||||
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, fire=2.0, water=0.5, grass=0.5, electric=1.0, psychic=1.0, ice=1.0, dragon=0.5, },
|
||||
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, fire=0.5, water=2.0, grass=0.5, electric=1.0, psychic=1.0, ice=1.0, dragon=0.5, },
|
||||
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, fire=1.0, water=2.0, grass=0.5, electric=0.5, psychic=1.0, ice=1.0, dragon=0.5, },
|
||||
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, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=0.5, ice=1.0, dragon=1.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, fire=1.0, water=0.5, grass=2.0, electric=1.0, psychic=1.0, ice=0.5, dragon=2.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, fire=1.0, water=1.0, grass=1.0, electric=1.0, psychic=1.0, ice=1.0, dragon=2.0, },
|
||||
}
|
||||
|
||||
local types = {}
|
||||
types[0] = "normal"
|
||||
types[1] = "fighting"
|
||||
types[2] = "flying"
|
||||
types[3] = "poison"
|
||||
types[4] = "ground"
|
||||
types[5] = "rock"
|
||||
types[7] = "bug"
|
||||
types[8] = "ghost"
|
||||
types[20] = "fire"
|
||||
types[21] = "water"
|
||||
types[22] = "grass"
|
||||
types[23] = "electric"
|
||||
types[24] = "psychic"
|
||||
types[25] = "ice"
|
||||
types[26] = "dragon"
|
||||
|
||||
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
|
||||
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 = 0x0FED
|
||||
else
|
||||
base = 0x101C
|
||||
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.raw(0x102D + idx)
|
||||
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"),
|
||||
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 booster = toBoost.mp
|
||||
if (currSpec < 140) == (booster > 1) then
|
||||
ours.spec = 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", "opponent_special"),
|
||||
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
|
||||
end
|
||||
Combat.isSleeping = isSleeping
|
||||
|
||||
local function isConfused()
|
||||
return Memory.raw(0x106B) > 0
|
||||
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,399 @@
|
|||
local Control = {}
|
||||
|
||||
local lowerGameRun = string.lower(GAME_RUN)
|
||||
local lowerGameName = string.lower(GAME_NAME)
|
||||
local secondStratDir = ""
|
||||
local secondPaintDir = ""
|
||||
if lowerGameRun == "no save corruption" then
|
||||
if lowerGameName == "red" or lowerGameName == "blue" then
|
||||
secondStratDir = ".red-blue"
|
||||
secondPaintDir = secondStratDir
|
||||
end
|
||||
else
|
||||
if lowerGameName == "yellow" then
|
||||
secondStratDir = ".yellow"
|
||||
else
|
||||
secondStratDir = ".red-blue"
|
||||
end
|
||||
end
|
||||
|
||||
local Battle
|
||||
local Combat = require "ai.combat"
|
||||
local Strategies
|
||||
|
||||
local Bridge = require "util.bridge"
|
||||
local Memory = require "util.memory"
|
||||
local Paint = require("util."..lowerGameRun..secondPaintDir..".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
|
||||
|
||||
local yellow = YELLOW
|
||||
|
||||
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,
|
||||
|
||||
viridianExpGlitch = function()
|
||||
minExp = 236
|
||||
shouldFight = {{name="rattata"}, {name="pidgey",lvl={2,3}}}
|
||||
end,
|
||||
|
||||
viridianBackupExpGlitch = function()
|
||||
minExp = 236
|
||||
shouldFight = {{name="rattata"}, {name="pidgey",lvl={2,3}}}
|
||||
end,
|
||||
|
||||
nidoranBackupExp = function()
|
||||
minExp = 210
|
||||
shouldFight = {{name="rattata"}, {name="pidgey"}, {name="nidoran"}, {name="nidoranf",lvl={2}}}
|
||||
end,
|
||||
|
||||
pidgeyBackupExp = function()
|
||||
minExp = 236
|
||||
shouldFight = {{name="rattata"}, {name="pidgey"}, {name="nidoran"}, {name="nidoranf"}}
|
||||
end,
|
||||
|
||||
startMtMoon = function()
|
||||
Control.moonEncounters = 0
|
||||
Control.canDie(false)
|
||||
Control.getMoonExp = true
|
||||
if not yellow then
|
||||
local nidoStats = Strategies.stats.nidoran
|
||||
if nidoStats.attack == 16 and not nidoStats.level4 then
|
||||
Control.getMoonExp = false
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
moon1Exp = function()
|
||||
if Control.getMoonExp then
|
||||
minExp = 2704
|
||||
local levels = Strategies.stats.nidoran.level4 and {9, 10} or {10}
|
||||
shouldFight = {{name="zubat",lvl=levels}}
|
||||
oneHits = true
|
||||
end
|
||||
end,
|
||||
|
||||
moon2Exp = function()
|
||||
if Control.getMoonExp then
|
||||
minExp = 3011
|
||||
shouldFight = {{name="zubat"}, {name="paras"}}
|
||||
oneHits = not withinOneKill(minExp)
|
||||
end
|
||||
end,
|
||||
|
||||
moon3Exp = function()
|
||||
if Control.getMoonExp then
|
||||
local expTotal = Pokemon.getExp()
|
||||
minExp = 3798
|
||||
if withinOneKill(minExp) then
|
||||
shouldFight = {{name="zubat"}, {name="paras"}}
|
||||
else
|
||||
shouldFight = nil
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
-- CATCH
|
||||
|
||||
catchPidgey = function()
|
||||
shouldCatch = {{name="pidgey"}}
|
||||
end,
|
||||
|
||||
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,
|
||||
|
||||
catchParas = function()
|
||||
shouldCatch = {{name="paras",hp=16}}
|
||||
end,
|
||||
|
||||
catchOddish = function()
|
||||
shouldCatch = {{name="oddish",alt="paras",hp=26}}
|
||||
end,
|
||||
|
||||
-- YELLOW
|
||||
|
||||
catchNidoranYellow = function()
|
||||
shouldCatch = {{name="nidoran",lvl={6}}}
|
||||
end,
|
||||
|
||||
moonExpYellow = function()
|
||||
minExp = 2704 --TODO
|
||||
shouldFight = {{name="geodude"}, {name="clefairy",lvl={12,13}}}
|
||||
oneHits = true
|
||||
end,
|
||||
|
||||
catchSandshrew = function()
|
||||
shouldCatch = {{name="sandshrew"}}
|
||||
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 = (yellow and 3 or 4) - partySize
|
||||
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 = battleState == 1
|
||||
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
|
||||
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()
|
||||
Battle = require("action.battle")
|
||||
Strategies = require("ai."..lowerGameRun..secondStratDir..".strategies")
|
||||
end
|
||||
|
||||
return Control
|
|
@ -0,0 +1,929 @@
|
|||
local lowerGameRun = string.lower(GAME_RUN)
|
||||
|
||||
local Strategies = require("ai."..lowerGameRun..".strategies")
|
||||
|
||||
local Combat = require "ai.combat"
|
||||
local Control = require "ai.control"
|
||||
|
||||
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.grabPCPotion = function()
|
||||
if Inventory.contains("potion") then
|
||||
return true
|
||||
end
|
||||
Player.interact("Up")
|
||||
end
|
||||
|
||||
strategyFunctions.checkStrats = function()
|
||||
UsingSTRATS = STRATS
|
||||
return true
|
||||
end
|
||||
|
||||
strategyFunctions.bulbasaurIChooseYou = function()
|
||||
if Pokemon.inParty("bulbasaur") then
|
||||
Bridge.caught("bulbasaur")
|
||||
return true
|
||||
end
|
||||
if Player.face("Up") then
|
||||
Textbox.name(BULBASAUR_NAME)
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.fightCharmander = function()
|
||||
if status.tries < 9000 and Pokemon.index(0, "level") == 6 then
|
||||
if status.tries > 200 then
|
||||
bulbasaurScl = Pokemon.index(0, "special")
|
||||
if bulbasaurScl < 12 then
|
||||
if UsingSTRATS == "Pidgey" then
|
||||
return Strategies.reset("Bad Bulbasaur for pidgey strats - "..bulbasaurScl.." special")
|
||||
else
|
||||
UsingSTRATS = "PP"
|
||||
end
|
||||
end
|
||||
status.tries = 9001
|
||||
return true
|
||||
else
|
||||
status.tries = status.tries + 1
|
||||
end
|
||||
end
|
||||
if Battle.isActive() and Memory.double("battle", "opponent_hp") > 0 and Strategies.resetTime(Strategies.getTimeRequirement("charmander"), "kill Charmander") then
|
||||
return true
|
||||
end
|
||||
Battle.automate()
|
||||
end
|
||||
|
||||
strategyFunctions.dodgePalletBoy = function()
|
||||
return Strategies.dodgeUp(0x0223, 14, 14, 15, 7)
|
||||
end
|
||||
|
||||
strategyFunctions.shopViridian = function()
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = 5
|
||||
end
|
||||
bulbasaurScl = Pokemon.index(0, "special")
|
||||
if bulbasaurScl == 16 then
|
||||
if UsingSTRATS == "Pidgey" then
|
||||
return Strategies.reset("We are already at 16special, we got no chance for Weedle")
|
||||
else
|
||||
UsingSTRATS = "PP"
|
||||
end
|
||||
end
|
||||
if UsingSTRATS == "PP" then
|
||||
status.tempDir = 1
|
||||
end
|
||||
return Shop.transaction{
|
||||
buy = {{name="pokeball", index=0, amount=status.tempDir}, {name="paralyze_heal", index=2, amount=1}, {name="burn_heal", index=3, amount=1}}
|
||||
}
|
||||
end
|
||||
|
||||
strategyFunctions.dodgeViridianOldMan = function()
|
||||
if UsingSTRATS == "PP" then
|
||||
local bidx = Pokemon.indexOf("bulbasaur")
|
||||
if Memory.raw(0x101E) ~= 73 then
|
||||
if Pokemon.index(bidx, "level") >= 7 then
|
||||
return Strategies.reset("We need leech seed for the brock skip glitch")
|
||||
end
|
||||
end
|
||||
end
|
||||
return Strategies.dodgeUp(0x0273, 18, 6, 17, 9)
|
||||
end
|
||||
|
||||
strategyFunctions.healTreePotion = function()
|
||||
if Battle.handleWild() then
|
||||
if Inventory.contains("potion") then
|
||||
if Pokemon.info("bulbasaur", "hp") <= 12 then
|
||||
if Menu.pause() then
|
||||
Inventory.use("potion", "bulbasaur")
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
elseif Menu.close() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.catchPidgey = function()
|
||||
if UsingSTRATS == "PP" then
|
||||
local px, py = Player.position()
|
||||
if px < 10 and py < 46 then
|
||||
px = 10
|
||||
elseif px == 10 and py < 46 then
|
||||
py = 46
|
||||
elseif px > 8 and py == 46 then
|
||||
px = 8
|
||||
elseif px == 8 and py == 46 then
|
||||
return true
|
||||
end
|
||||
Walk.step(px, py)
|
||||
else
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
status.tries = nil
|
||||
local bidx = Pokemon.indexOf("bulbasaur")
|
||||
local scl = Pokemon.index(bidx, "special")
|
||||
if scl == 16 then
|
||||
if UsingSTRATS == "" then
|
||||
UsingSTRATS = "PP"
|
||||
return true
|
||||
else
|
||||
return Strategies.reset("We are already at 16special, we got no chance for Weedle")
|
||||
end
|
||||
end
|
||||
end
|
||||
if Battle.isActive() then
|
||||
local isPidgey = Pokemon.isOpponent("pidgey")
|
||||
status.tries = nil
|
||||
if isPidgey then
|
||||
local pidgeyHP = Memory.raw(0xCFE7)
|
||||
gui.text(100, 134, pidgeyHP.."HP")
|
||||
if Memory.value("menu", "text_input") == 240 then
|
||||
Textbox.name(PIDGEY_NAME, true)
|
||||
elseif Memory.value("battle", "menu") == 95 then
|
||||
Input.press("A")
|
||||
elseif status.tempDir then
|
||||
local pokeballs = Inventory.count("pokeball")
|
||||
if pokeballs < 2 then
|
||||
if Memory.value("menu", "selection") == 233 then
|
||||
Input.press("Right", 2)
|
||||
elseif Memory.value("menu", "selection") == 239 then
|
||||
Input.press("A", 2)
|
||||
end
|
||||
--Battle.run()
|
||||
elseif not Control.shouldCatch(3) then
|
||||
Battle.run()
|
||||
end
|
||||
else
|
||||
local pidgeyHPtable = {17, 16, 15, 13, 10, 8}
|
||||
if Utils.match(pidgeyHP, pidgeyHPtable) then
|
||||
status.tempDir = true
|
||||
elseif not Utils.match(pidgeyHP, pidgeyHPtable) and pidgeyHP > 8 then
|
||||
Battle.fight("tackle", false, true) --perform tackle
|
||||
else
|
||||
Battle.run()
|
||||
end
|
||||
end
|
||||
else
|
||||
if Memory.value("battle", "menu") == 95 then
|
||||
Input.cancel()
|
||||
elseif not Control.shouldCatch() then
|
||||
if Control.shouldFight() then
|
||||
Battle.fight()
|
||||
else
|
||||
Battle.run()
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local hasPidgey = Pokemon.inParty("pidgey")
|
||||
Pokemon.updateParty()
|
||||
if hasPidgey then
|
||||
if status.tempDir then
|
||||
Bridge.caught("pidgey")
|
||||
status.tempDir = false
|
||||
end
|
||||
return true
|
||||
end
|
||||
local pokeballs = Inventory.count("pokeball")
|
||||
if pokeballs < 2 then
|
||||
if not hasPidgey then
|
||||
if UsingSTRATS == "Pidgey" then
|
||||
return Strategies.reset("Ran too low on PokeBalls", pokeballs)
|
||||
else
|
||||
UsingSTRATS = "PP"
|
||||
print("Ran too low on PokeBalls, going to PP-Strats")
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
local timeLimit = Strategies.getTimeRequirement("pidgey")
|
||||
local resetMessage = "find a Pidgey"
|
||||
if Strategies.resetTime(timeLimit, resetMessage, false, true) then
|
||||
return true
|
||||
end
|
||||
pidgeyDSum()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.grabAntidote = function()
|
||||
local px, py = Player.position()
|
||||
if py < 11 then
|
||||
return true
|
||||
end
|
||||
if Inventory.contains("antidote") then
|
||||
py = 10
|
||||
else
|
||||
Player.interact("Up")
|
||||
end
|
||||
Walk.step(px, py)
|
||||
end
|
||||
|
||||
strategyFunctions.grabForestPotion = function()
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
end
|
||||
if Battle.handleWild() then
|
||||
if not Textbox.isActive() and not status.tempDir then
|
||||
Input.press("A", 2)
|
||||
elseif Textbox.isActive() and not status.tempDir then
|
||||
Input.press("A", 2)
|
||||
status.tempDir = true
|
||||
elseif not Textbox.isActive() and status.tempDir then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.fightWeedle = function()
|
||||
if Battle.isTrainer() then
|
||||
status.canProgress = true
|
||||
return Strategies.buffTo("growl", 0, 39) --Peform 1x Growl
|
||||
elseif status.canProgress then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.checkSpec = function()
|
||||
if Strategies.initialize() then
|
||||
local WillReset
|
||||
if not Inventory.contains("potion") then WillReset = true end
|
||||
if not Inventory.contains("pokeball") then WillReset = true end
|
||||
if not Inventory.contains("antidote") then WillReset = true end
|
||||
if not Inventory.contains("paralyze_heal") then WillReset = true end
|
||||
if not Inventory.contains("burn_heal") then WillReset = true end
|
||||
if WillReset then
|
||||
return Strategies.reset("We need 5 items for the brock skip glitch")
|
||||
end
|
||||
end
|
||||
if UsingSTRATS == "" then
|
||||
local bidx = Pokemon.indexOf("bulbasaur")
|
||||
local scl = Pokemon.index(bidx, "special")
|
||||
local hasPidgey = Pokemon.inParty("pidgey")
|
||||
if hasPidgey then
|
||||
if scl == 16 then
|
||||
UsingSTRATS = "Pidgey"
|
||||
print("Performing Pidgey Strats")
|
||||
return true
|
||||
else
|
||||
UsingSTRATS = "PP"
|
||||
end
|
||||
else
|
||||
UsingSTRATS = "PP"
|
||||
end
|
||||
elseif UsingSTRATS == "Pidgey" then
|
||||
local bidx = Pokemon.indexOf("bulbasaur")
|
||||
local scl = Pokemon.index(bidx, "special")
|
||||
if scl == 16 then
|
||||
print("Performing Pidgey Strats")
|
||||
return true
|
||||
else
|
||||
return Strategies.reset("We need 16special on Bulbasaur for the brock skip glitch")
|
||||
end
|
||||
elseif UsingSTRATS == "PP" then
|
||||
local bidx = Pokemon.indexOf("bulbasaur")
|
||||
if Memory.raw(0x101E) ~= 73 then
|
||||
if Pokemon.index(bidx, "level") >= 7 then
|
||||
return Strategies.reset("We need leech seed for the brock skip glitch")
|
||||
end
|
||||
end
|
||||
print("Performing PP Strats")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.equipForGlitch = function()
|
||||
if UsingSTRATS == "Pidgey" then
|
||||
return true
|
||||
else
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
end
|
||||
local TacklePP = Memory.raw(0x102D)
|
||||
local GrowlPP = Memory.raw(0x102E)
|
||||
local bidx = Pokemon.indexOf("bulbasaur")
|
||||
--in Battle
|
||||
if Battle.isActive() then
|
||||
status.tries = nil
|
||||
if Memory.value("battle", "menu") == 95 then
|
||||
Input.press("A")
|
||||
else
|
||||
TacklePP = Memory.raw(0x102D)
|
||||
if not status.tempDir then
|
||||
if GrowlPP > 36 then
|
||||
Battle.fight("growl", false, true) --perform 3x Growl
|
||||
else
|
||||
if TacklePP > 16 then --perform tackle until 16pp
|
||||
Battle.fight()
|
||||
elseif TacklePP == 16 then
|
||||
if Memory.raw(0x101E) ~= 73 then
|
||||
return Strategies.reset("We need leech seed for the brock skip glitch")
|
||||
else
|
||||
status.tempDir = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if status.tempDir then
|
||||
if Pokemon.battleMove("tackle") == 1 then
|
||||
Battle.swapMove(1, 3)
|
||||
elseif Pokemon.battleMove("tackle") == 3 then
|
||||
Battle.swapMove(3, 2)
|
||||
elseif Pokemon.battleMove("tackle") == 2 then
|
||||
if Memory.value("battle", "menu") == 106 then
|
||||
Input.press("B")
|
||||
else
|
||||
if Pokemon.index(bidx, "level") ~= 8 then
|
||||
status.tempDir = false
|
||||
return Strategies.reset("Can't be Lvl"..Pokemon.index(bidx, "level").." for the brock skip glitch with the PP Strats")
|
||||
else
|
||||
Battle.run()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else --out battle
|
||||
TacklePP = Memory.raw(0x102D)
|
||||
if not status.tempDir then
|
||||
if TacklePP == 16 then
|
||||
if Pokemon.index(bidx, "level") ~= 8 then
|
||||
return Strategies.reset("Can't be Lvl"..Pokemon.index(bidx, "level").." for the brock skip glitch with the PP Strats")
|
||||
end
|
||||
if Memory.raw(0x101E) ~= 73 then
|
||||
return Strategies.reset("We need leech seed for the brock skip glitch")
|
||||
end
|
||||
status.tempDir = true
|
||||
elseif TacklePP < 16 then
|
||||
return Strategies.reset("Ran too low on Tackle for the PP Strats "..TacklePP.."PP available")
|
||||
end
|
||||
end
|
||||
if status.tempDir then
|
||||
if Pokemon.battleMove("tackle") == 2 then
|
||||
status.tempDir = false
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local timeLimit = Strategies.getTimeRequirement("glitch")
|
||||
local resetMessage = "perform enough Tackle for the PP Strats glitch"
|
||||
if Strategies.resetTime(timeLimit, resetMessage) then
|
||||
return true
|
||||
end
|
||||
tackleDSum()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.checkInventory = function()
|
||||
if Strategies.initialize() then
|
||||
local WillReset
|
||||
if not Inventory.contains("potion") then WillReset = true end
|
||||
if not Inventory.contains("pokeball") then WillReset = true end
|
||||
if not Inventory.contains("antidote") then WillReset = true end
|
||||
if not Inventory.contains("paralyze_heal") then WillReset = true end
|
||||
if not Inventory.contains("burn_heal") then WillReset = true end
|
||||
if WillReset then
|
||||
return Strategies.reset("We need 5 items for the brock skip glitch")
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.checkForPidgey = function()
|
||||
if UsingSTRATS == "Pidgey" then
|
||||
return true
|
||||
else
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
local hasPidgey = Pokemon.inParty("pidgey")
|
||||
if not hasPidgey then
|
||||
return true
|
||||
end
|
||||
end
|
||||
local map = Memory.value("game", "map")
|
||||
local px, py = Player.position()
|
||||
if not status.tempDir then --go to pc to depose
|
||||
if map == 2 then
|
||||
if px > 13 then
|
||||
px = 13
|
||||
else
|
||||
if py > 25 then
|
||||
py = 25
|
||||
end
|
||||
end
|
||||
elseif map == 58 then
|
||||
if py > 5 then
|
||||
py = 5
|
||||
else
|
||||
if px < 13 then
|
||||
px = 13
|
||||
else
|
||||
if py > 4 then
|
||||
py = 4
|
||||
else -- deposit pidgey
|
||||
if Memory.value("player", "party_size") == 1 then
|
||||
if Menu.close() then
|
||||
status.tempDir = true
|
||||
end
|
||||
else
|
||||
if not Textbox.isActive() then
|
||||
Player.interact("Up")
|
||||
else
|
||||
local pc = Memory.value("menu", "size")
|
||||
if Memory.value("battle", "menu") ~= 95 and (pc == 2 or pc == 4) then
|
||||
local menuColumn = Menu.getCol()
|
||||
if menuColumn == 10 then
|
||||
Input.press("A")
|
||||
elseif menuColumn == 5 then
|
||||
Menu.select(1) -- select pidgey
|
||||
else
|
||||
Menu.select(1) -- select deposit box
|
||||
end
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else --get back to the spot
|
||||
if map == 58 then
|
||||
if px > 4 then
|
||||
px = 4
|
||||
else
|
||||
if py < 8 then
|
||||
py = 8
|
||||
end
|
||||
end
|
||||
elseif map == 2 then
|
||||
if px < 18 then
|
||||
px = 18
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
Walk.step(px, py, true)
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.prepareSave = function()
|
||||
local main = Memory.value("menu", "main")
|
||||
local row = Memory.value("menu", "row")
|
||||
if main == 128 then
|
||||
if row == 4 then
|
||||
Input.press("B")
|
||||
else
|
||||
Input.press("Down")
|
||||
end
|
||||
else
|
||||
if row == 4 then
|
||||
return true
|
||||
end
|
||||
Input.press("Start")
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.performSkip = function()
|
||||
local current = Memory.value("menu", "current")
|
||||
local selection = Memory.value("menu", "selection")
|
||||
local skip = Memory.value("menu", "pokemon")
|
||||
if current == 15 then
|
||||
if Memory.value("menu", "pokemon") ~= 0 then
|
||||
Input.press("Start", 0)
|
||||
else
|
||||
Player.disinteract("left")
|
||||
end
|
||||
else
|
||||
if selection == 115 then
|
||||
Input.press("A")
|
||||
elseif selection == 65 then
|
||||
if skip == 207 then
|
||||
return true
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
else
|
||||
Input.press("Start", 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.performReset = function()
|
||||
local skip = Memory.value("menu", "pokemon")
|
||||
if skip == 197 or skip == 204 then
|
||||
return Strategies.SkipReset()
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.openPokemonMenu = function()
|
||||
if UsingSTRATS == "Pidgey" then
|
||||
if Textbox.isActive() then
|
||||
return true
|
||||
else
|
||||
Input.press("Start")
|
||||
end
|
||||
else
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
end
|
||||
local main = Memory.value("menu", "main")
|
||||
local row = Memory.value("menu", "row")
|
||||
if main == 128 then
|
||||
if status.tempDir then
|
||||
Input.press("B")
|
||||
else
|
||||
if row == 0 then
|
||||
Input.press("Down")
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
elseif main == 103 then
|
||||
status.tempDir = true
|
||||
Input.press("B")
|
||||
elseif main == 8 then
|
||||
status.tempDir = false
|
||||
return true
|
||||
else
|
||||
if status.tempDir then
|
||||
Input.press("B")
|
||||
else
|
||||
Input.press("Start")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.speakToGlithGuy = function()
|
||||
local main = Memory.value("menu", "main")
|
||||
if not Textbox.isActive() then
|
||||
Player.interact("Left")
|
||||
else
|
||||
if main == 167 then
|
||||
return true
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.leaveGlitchGuy = function()
|
||||
local map = Memory.value("game", "map")
|
||||
local px, py = Player.position()
|
||||
if map == 2 then --Pewter City
|
||||
if py == 16 then
|
||||
px = 40
|
||||
end
|
||||
elseif map == 14 then --Route3
|
||||
if px < 17 then
|
||||
px = 17
|
||||
else
|
||||
if py > 7 then
|
||||
py = 7
|
||||
else
|
||||
if px < 60 then
|
||||
px = 60
|
||||
else
|
||||
if py > -1 then
|
||||
py = -1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif map == 15 then --Center Route
|
||||
if px < 90 then
|
||||
px = 90
|
||||
end
|
||||
elseif map == 3 then --Cerulean City
|
||||
if px < 8 then
|
||||
px = 8
|
||||
else
|
||||
if py < 36 then
|
||||
py = 36
|
||||
end
|
||||
end
|
||||
elseif map == 16 then --Out of Cerulean
|
||||
if py < 36 then
|
||||
py = 36
|
||||
end
|
||||
elseif map == 10 then --Saffron City
|
||||
if py < 29 then
|
||||
py = 29
|
||||
else
|
||||
if px < 9 then
|
||||
px = 9
|
||||
end
|
||||
end
|
||||
elseif map == 182 then --Saffron City Poke Center
|
||||
return true
|
||||
end
|
||||
Walk.step(px, py, true)
|
||||
end
|
||||
|
||||
strategyFunctions.checkPidgeyHP = function()
|
||||
if UsingSTRATS == "PP" then
|
||||
return true
|
||||
else
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
status.canProgress = true
|
||||
end
|
||||
local pidx = Pokemon.indexOf("pidgey")
|
||||
local hp = Pokemon.index(pidx, "hp")
|
||||
if hp ~= 16 and status.canProgress then
|
||||
return true
|
||||
else
|
||||
status.canProgress = false
|
||||
local px, py = Player.position()
|
||||
if px < 13 then
|
||||
Walk.step(13, py)
|
||||
else
|
||||
if Memory.value("player", "party_size") == 2 then --Depose Pidgey
|
||||
if not Textbox.isActive() then
|
||||
Player.interact("Up")
|
||||
else
|
||||
local pc = Memory.value("menu", "size")
|
||||
if Memory.value("battle", "menu") ~= 95 and (pc == 2 or pc == 4) then
|
||||
local menuColumn = Menu.getCol()
|
||||
if menuColumn == 10 then
|
||||
Input.press("A")
|
||||
elseif menuColumn == 5 then
|
||||
Menu.select(1) --select pidgey
|
||||
else
|
||||
Menu.select(1) --select deposit box
|
||||
end
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
else
|
||||
if not status.tempDir then --swap box for saving
|
||||
if Memory.value("menu", "shop_current") == 20 or Memory.value("menu", "shop_current") == 73 then
|
||||
if Memory.value("menu", "column") == 1 then
|
||||
if Memory.value("menu", "row") ~= 3 then
|
||||
Input.press("Down")
|
||||
else
|
||||
Input.press("A", 2)
|
||||
end
|
||||
elseif Memory.value("menu", "column") == 15 then --select yes to save
|
||||
Input.press("A", 2)
|
||||
elseif Memory.value("menu", "column") == 12 then --select box
|
||||
if Memory.value("menu", "row") ~= 1 then
|
||||
--Menu.select(1) --select box2
|
||||
Input.press("Down")
|
||||
else
|
||||
Input.press("A")
|
||||
status.tempDir = true
|
||||
end
|
||||
end
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
else --Resetting
|
||||
if Memory.value("menu", "selection") == 65 then
|
||||
return Strategies.SkipReset()
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.walkBack = function()
|
||||
local px, py = Player.position()
|
||||
if px > 3 then
|
||||
Walk.step(3, py)
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.getAbra = function()
|
||||
local party_size = Memory.value("player", "party_size")
|
||||
local text_input = Memory.value("menu", "text_input")
|
||||
local textbox_active = Memory.value("game", "textbox")
|
||||
local hasAbra = Pokemon.inParty("abra")
|
||||
if textbox_active == 1 then
|
||||
if party_size == 1 then
|
||||
Input.press("A")
|
||||
else
|
||||
if text_input == 240 then
|
||||
Textbox.name(ABRA_NAME, true)
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
else
|
||||
if hasAbra then
|
||||
return true
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.performTeleportGlitch = function()
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
end
|
||||
local map = Memory.value("game", "map")
|
||||
local main = Memory.value("menu", "main")
|
||||
local px, py = Player.position()
|
||||
if not status.tempDir then
|
||||
if px == 5 then
|
||||
status.tempDir = true
|
||||
Walk.step(4, py, true)
|
||||
end
|
||||
else
|
||||
if main ~= 128 then
|
||||
Input.press("Start", 0)
|
||||
else
|
||||
status.tempDir = false
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.fightGymGuy = function()
|
||||
local abraHP = Pokemon.info("abra", "hp")
|
||||
if abraHP == 0 then
|
||||
return true
|
||||
end
|
||||
if Battle.isTrainer() then
|
||||
status.canProgress = true
|
||||
return Strategies.buffTo("teleport", 0, 1) --Perform teleport
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.closingAutomation = function()
|
||||
if Memory.value("menu", "shop_current") == 0 then
|
||||
return Strategies.reset("We need need to encounter a MissingNo, Not a Trainer")
|
||||
else
|
||||
if Memory.value("menu", "main") == 123 then
|
||||
Input.press("B")
|
||||
elseif Memory.value("menu", "main") == 32 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
strategyFunctions.battleMissingNo = function()
|
||||
if Battle.isActive() then
|
||||
Battle.run()
|
||||
else
|
||||
if Textbox.isActive() then
|
||||
Input.press("A")
|
||||
else
|
||||
local px, py = Player.position()
|
||||
if py < 1 then
|
||||
py = 1
|
||||
else
|
||||
return true
|
||||
end
|
||||
Walk.step(px, py, true)
|
||||
end
|
||||
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,545 @@
|
|||
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
|
||||
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,
|
||||
|
||||
teleport = function(data)
|
||||
if Memory.value("game", "map") == data.map then
|
||||
return true
|
||||
end
|
||||
if not Pokemon.use("teleport") then
|
||||
Menu.pause()
|
||||
end
|
||||
end,
|
||||
|
||||
speak = function()
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
end
|
||||
if Textbox.isActive() then
|
||||
Input.press("A")
|
||||
status.tempDir = true
|
||||
else
|
||||
if status.tempDir then
|
||||
status.tempDir = false
|
||||
return true
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
deposeAll = function(data)
|
||||
if Memory.value("player", "party_size") == 1 then
|
||||
if Menu.close() then
|
||||
return true
|
||||
end
|
||||
else
|
||||
if not Textbox.isActive() then
|
||||
Player.interact("Up")
|
||||
else
|
||||
local pc = Memory.value("menu", "size")
|
||||
if Memory.value("battle", "menu") ~= 95 and (pc == 2 or pc == 4) then
|
||||
local menuColumn = Menu.getCol()
|
||||
if menuColumn == 10 then
|
||||
Input.press("A")
|
||||
elseif menuColumn == 5 then
|
||||
local depositIndex = 0
|
||||
if Pokemon.indexOf(data.keep) == 0 then
|
||||
depositIndex = 1
|
||||
end
|
||||
Menu.select(depositIndex)
|
||||
else
|
||||
Menu.select(1)
|
||||
end
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
swapItem = function(data)
|
||||
if Strategies.initialize() then
|
||||
status.tempDir = false
|
||||
end
|
||||
if not data.pos2 then -- 1x position mode + item name
|
||||
itemPos1 = Inventory.indexOf(data.item)
|
||||
itemPos2 = data.pos1-1
|
||||
else -- 2x position mode
|
||||
itemPos1 = data.pos1-1
|
||||
itemPos2 = data.pos2-1
|
||||
end
|
||||
local main = Memory.value("menu", "main")
|
||||
local selection = Memory.value("menu", "selection_mode")
|
||||
if status.tempDir and selection == 0 then
|
||||
return true
|
||||
end
|
||||
if main == 128 then
|
||||
if Menu.getCol() ~= 5 then
|
||||
Menu.select(2, true)
|
||||
else
|
||||
if selection == 0 then
|
||||
if Menu.select(itemPos1, 1, true, nil, true) then
|
||||
Input.press("Select")
|
||||
end
|
||||
else
|
||||
if Menu.select(itemPos2, 1, true, nil, true) then
|
||||
Input.press("Select")
|
||||
status.tempDir = true
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
Menu.pause()
|
||||
end
|
||||
end,
|
||||
|
||||
tossItem = function(data)
|
||||
if Strategies.initialize() then
|
||||
status.canProgress = false
|
||||
if not data.item then
|
||||
itemPos1 = data.pos-1
|
||||
status.tempDir = Memory.raw(0x131E+itemPos1*2+1)
|
||||
else
|
||||
status.tempDir = Inventory.count(data.item)
|
||||
end
|
||||
if data.amount then
|
||||
itemNumber = data.amount
|
||||
else
|
||||
itemNumber = status.tempDir
|
||||
end
|
||||
end
|
||||
if not data.pos then --tossing by item name
|
||||
itemPos1 = Inventory.indexOf(data.item)
|
||||
else --tossing by item position
|
||||
itemPos1 = data.pos-1
|
||||
end
|
||||
local main = Memory.value("menu", "main")
|
||||
if main == 60 and Memory.value("menu", "shop_current") == 20 and status.canProgress then
|
||||
return true
|
||||
end
|
||||
if main == 128 or Menu.getCol() == 14 and main ~= 209 then
|
||||
if Menu.getCol() ~= 5 and Menu.getCol() ~= 14 then
|
||||
Menu.select(2, true)
|
||||
else
|
||||
if Memory.value("menu", "text_input") == 146 then
|
||||
if Memory.value("menu", "row") == 0 then
|
||||
Menu.select(1, true)
|
||||
else
|
||||
if Memory.value("menu", "shop_current") ~= 248 then
|
||||
Input.press("A")
|
||||
else
|
||||
local currAmount = Memory.value("shop", "transaction_amount")
|
||||
if Menu.balance(currAmount, itemNumber, false, 99, true) then
|
||||
Input.press("A")
|
||||
status.canProgress = true
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if Menu.select(itemPos1, 1, true, nil, true) then
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif main == 209 then
|
||||
Input.press("A")
|
||||
else
|
||||
Menu.pause()
|
||||
end
|
||||
end,
|
||||
|
||||
tossTM = function(data)
|
||||
if Strategies.initialize() then
|
||||
status.canProgress = false
|
||||
status.tries = 0
|
||||
if data.amount then
|
||||
itemNumber = data.amount
|
||||
else
|
||||
itemPos1 = data.pos-1
|
||||
status.tempDir = Memory.raw(0x131E+itemPos1*2+1)
|
||||
itemNumber = status.tempDir
|
||||
end
|
||||
end
|
||||
if not data.pos then --tossing by item name
|
||||
itemPos1 = Inventory.indexOf(data.item)
|
||||
else --tossing by item position
|
||||
itemPos1 = data.pos-1
|
||||
end
|
||||
local main = Memory.value("menu", "main")
|
||||
if main == 60 and Memory.value("menu", "shop_current") == 20 and status.canProgress then
|
||||
return true
|
||||
end
|
||||
if status.tries == 0 then
|
||||
if main == 128 or Menu.getCol() == 14 and main ~= 209 then
|
||||
if Menu.getCol() ~= 5 and Menu.getCol() ~= 14 then
|
||||
Menu.select(2, true)
|
||||
else
|
||||
if Memory.value("menu", "text_input") == 146 then
|
||||
if Memory.value("menu", "row") == 0 then
|
||||
Menu.select(1, true, false, nil, true)
|
||||
else
|
||||
if main == 128 then
|
||||
Input.press("A")
|
||||
else
|
||||
status.tries = 1
|
||||
end
|
||||
end
|
||||
else
|
||||
if Menu.select(itemPos1, 1, true, nil, true) then
|
||||
Input.press("A")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if main == 128 or Menu.getCol() == 14 and main ~= 209 then
|
||||
local currAmount = Memory.value("shop", "transaction_amount")
|
||||
if Menu.balance(currAmount, itemNumber, false, 99, true) then
|
||||
Input.press("A")
|
||||
status.canProgress = true
|
||||
end
|
||||
else
|
||||
Input.press("A")
|
||||
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
|
|
@ -0,0 +1,453 @@
|
|||
local Paths = {
|
||||
|
||||
-- Red's room
|
||||
{38, {3,6}, {5,6}, {5,1}, {7,1}},
|
||||
-- Red's house
|
||||
{39, {7,1}, {7,6}, {3,6}, {3,8}},
|
||||
-- Into the Wild
|
||||
{0, {5,6}, {10,6}, {10,1}},
|
||||
-- Choose your character!
|
||||
{40, {5,3}, {c="a",a="Pallet Rival"}, {5,4}, {7,4}, {s="squirtleIChooseYou"}, {5,4}, {5,6}, {s="fightBulbasaur"}, {s="split"}, {5,12}},
|
||||
|
||||
-- 1: RIVAL 1
|
||||
|
||||
-- Let's try this escape again
|
||||
{0, {12,12}, {c="a",a="Pallet Town"}, {c="viridianExp"}, {c="encounters",limit=4}, {9,12}, {9,2}, {10,2}, {10,-1}},
|
||||
-- First encounters
|
||||
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
|
||||
-- To the Mart
|
||||
{1, {21,35}, {21,30}, {19,30}, {19,20}, {29,20}, {29,19}},
|
||||
-- Viridian Mart
|
||||
{42, {2,5}, {3,5}, {3,8}},
|
||||
-- Backtracking
|
||||
{1, {29,20}, {c="encounters",limit=5}, {29,21}, {26,21}, {26,30}, {20,30}, {20,36}},
|
||||
-- Parkour
|
||||
{12, {10, 0}, {10,3}, {8,3}, {8,18}, {9,18}, {9,22}, {12,22}, {12,24}, {10,24}, {10,36}},
|
||||
-- To Oak's lab
|
||||
{0, {10,0}, {10,7}, {9,7}, {9,12}, {12,12}, {12,11}},
|
||||
-- Parcel delivery
|
||||
{40, {5,11}, {5,3}, {4,3}, {4,1}, {5,1}, {s="interact",dir="Down"}, {4,1}, {4,12}},
|
||||
-- Leaving home
|
||||
{0, {12,12}, {c="viridianBackupExp"}, {9,12}, {9,2}, {10,2}, {10,-1}},
|
||||
-- The grass again!?
|
||||
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
|
||||
-- Back to the Mart
|
||||
{1, {21,35}, {21,30}, {19,30}, {19,20}, {29,20}, {29,19}},
|
||||
-- Viridian Mart redux
|
||||
{42, {3,7}, {3,5}, {2,5}, {s="shopViridianPokeballs"}, {3,5}, {3,8}},
|
||||
-- Sidequest
|
||||
{1, {29,20}, {15,20}, {15,17}, {-1, 17}},
|
||||
-- Nidoran
|
||||
{33, {39, 9}, {c="a",a="Nidoran grass"}, {c="nidoranBackupExp"}, {c="encounters",limit=7,extra="spearow"}, {35, 9}, {35,12}, {33,12}, {c="catchNidoran"}, {s="catchNidoran"}, {33,12}, {s="split"}, {37,12}, {37,9}, {40,9}},
|
||||
|
||||
-- 2: NIDORAN
|
||||
|
||||
-- Out of Viridian City
|
||||
{1, {0,17}, {c="encounters",limit=10,extra="spearow"}, {16,17}, {16,16}, {18,16}, {18,6}, {s="dodgeViridianOldMan"}, {17,4}, {s="grabTreePotion"}, {17,4}, {17, 0}, {17, -1}},
|
||||
-- To the Forest
|
||||
{13, {7,71}, {7,57}, {4,57}, {4,52}, {10,52}, {10,44}, {3,44}, {3,43}},
|
||||
-- Forest entrance
|
||||
{50, {4,7}, {c="a",a="Viridian Forest"}, {4,1}, {5,1}, {5,0}},
|
||||
-- Viridian Forest
|
||||
{51, {17,47}, {17,43}, {26,43}, {26,34}, {25,34}, {25,32}, {27,32}, {27,20}, {25,20}, {25,12}, {s="grabAntidote"}, {25,9}, {17,9}, {17,16}, {13,16}, {13,3}, {7,3}, {7,22}, {1,22}, {1,19}, {s="grabForestPotion"}, {1,18}, {s="fightWeedle"}, {c="encounters",limit=22,extra="paras"}, {1,16}, {c="potion",b=false}, {s="equipForBrock",anti=true}, {1,5}, {s="equipForBrock"}, {1,-1}},
|
||||
-- Forest exit
|
||||
{47, {4,7}, {4,1}, {5,1}, {5,0}},
|
||||
-- Road to Pewter City
|
||||
{13, {3,11}, {c="a",a="Pewter City"}, {3,8}, {8,8}, {8,-1}},
|
||||
-- Pewter City
|
||||
{2, {18,35}, {18,22}, {19,22}, {19,13}, {10,13}, {10,18}, {16,18}, {16,17}},
|
||||
-- Brock
|
||||
{54, {4,13}, {c="a",a="Brock's Gym"}, {4,8}, {1,8}, {1,4}, {4,4}, {4,2}, {s="interact",dir="Up"}, {s="fightBrock"}, {s="split"}, {s="emuSpeed",percent=100}, {4,14}},
|
||||
|
||||
-- 3: BROCK
|
||||
|
||||
-- To Pewter Mart
|
||||
{2, {16,18}, {c="potion",b=true}, {10,18}, {10,13}, {21,13}, {21,18}, {23,18}, {23,17}},
|
||||
-- Pewter Mart
|
||||
{56, {3,7}, {3,5}, {2,5}, {s="shopPewterMart"}, {2,6}, {3,6}, {3,8}},
|
||||
-- Leaving Pewter City
|
||||
{2, {23,18}, {40,18}},
|
||||
-- Route 3
|
||||
{14, {0,10}, {c="a",a="Route 3"}, {c="catchFlier"}, {c="pp",on=true}, {s="battleModeSet"}, {8,10}, {8,8}, {11,8}, {11,6}, {s="bugCatcher"}, {11,4}, {12,4}, {s="potion",hp=19}, {13,4}, {s="interact",dir="Right"}, {s="shortsKid"}, {s="tweetAfterBrock"}, {13,5}, {s="potionBeforeCocoons"}, {18,5}, {s="interact",dir="Right"}, {s="swapHornAttack"}, {18,6}, {22,6}, {22,5}, {s="potion",hp=4}, {24,5}, {s="interact",dir="Down"}, {s="fightMetapod"}, {27,5}, {27,9}, {s="catchFlierBackup"}, {37,8}, {37,5}, {49,5}, {49,10}, {57,10}, {57,8}, {59,8}, {59,-1}},
|
||||
-- To the Center
|
||||
{15, {9,16}, {c="pp",on=false}, {12,16}, {12,6}, {11,6}, {11,5}},
|
||||
-- PP up
|
||||
{68, {3,7}, {3,3}, {s="confirm",dir="Up"}, {3,8}},
|
||||
-- Enter Mt. Moon
|
||||
{15, {11,6}, {c="a",a="Mt. Moon"}, {18,6}, {s="split"}, {18,5}},
|
||||
|
||||
-- 4: ROUTE 3
|
||||
|
||||
-- Mt. Moon F1
|
||||
{59, {14,35}, {c="startMtMoon"}, {c="catchParas"}, {14,22}, {21,22}, {21,15}, {24,15}, {24,27}, {25,27}, {25,31}, {s="interact",dir="Left"}, {25,32}, {33,32}, {33,31}, {34,31}, {s="interact",dir="Right"}, {35,31}, {35,23}, {s="interact",dir="Right"}, {35,7}, {30,7}, {s="evolveNidorino"}, {c="moon1Exp"}, {28,7}, {16,7}, {16,17}, {2,17}, {2,3}, {s="interact",dir="Up"}, {5,3}, {5,5}},
|
||||
-- Mt. Moon B2
|
||||
{60, {5,5}, {5,17}, {21,17}},
|
||||
-- Mt. Moon B3
|
||||
{61, {21,17}, {22,17}, {s="evolveNidoking",early=true,poke="paras"}, {23,17}, {23,14}, {27,14}, {27,16}, {33,16}, {33,14}, {36,14}, {36,24}, {32, 24}, {32,31}, {10,31}, {10,18}, {s="evolveNidoking"}, {c="encounters",limit=nil}, {10,17}, {12,17}, {c="moon2Exp"}, {12,9}, {s="potion",hp=7}, {s="interact",dir="Up"}, {13,9}, {c="moon3Exp"}, {13,7}, {s="helix"}, {13,5}, {12,5}, {12,4}, {3,4}, {3,7}, {5,7}},
|
||||
-- Mt. Moon escape
|
||||
{60, {23,3}, {27,3}},
|
||||
|
||||
-- 5: MT. MOON
|
||||
|
||||
-- To Cerulean
|
||||
{15, {24,6}, {s="reportMtMoon"}, {s="split"}, {24,8}, {35,8}, {35,10}, {61,10}, {61,8}, {79,8}, {79,10}, {90,10}},
|
||||
-- Enter Cerulean
|
||||
{3, {0,18}, {c="a",a="Cerulean"}, {14,18}, {s="dodgeCerulean"}, {19,18}, {19,17}},
|
||||
-- Cerulean Center
|
||||
{64, {3,7}, {3,3}, {s="confirm",dir="Up"}, {3,8}},
|
||||
-- To the house
|
||||
{3, {19,18}, {16,18}, {s="dodgeCeruleanLeft"}, {8,16}, {8,12}, {9,12}, {9,11}},
|
||||
-- In the house
|
||||
{230, {2,7}, {2,0}},
|
||||
-- Outback
|
||||
{3, {9,9}, {9,8}, {14,8}, {s="interact",dir="Right"}, {9,8}, {9,10}},
|
||||
-- Out the house
|
||||
{230, {2,1}, {2,8}},
|
||||
-- Rival 2
|
||||
{3, {9,12}, {c="a",a="Cerulean Rival"}, {21,12}, {21,6}, {s="rivalSandAttack"}, {21,-1}},
|
||||
-- Nugget bridge
|
||||
--TODO RC early strat
|
||||
{35, {11,35}, {c="a",a="Nugget Bridge"}, {11,32}, {s="interact",dir="Up"}, {10,32}, {10,29}, {s="interact",dir="Up"}, {11,29}, {11,27}, {s="potion",hp=4}, {11,26}, {s="interact",dir="Up"}, {10,26}, {10,24}, {s="teachThrash"}, {s="potion",hp=4}, {10,23}, {s="interact",dir="Up"}, {11,23}, {11,21}, {s="teachThrash"}, {s="potionForMankey"}, {11,20}, {s="interact",dir="Up"}, {s="redbarMankey"}, {10,20}, {10,19}, {s="teachThrash"}, {10,15}, {s="waitToFight"}, {s="teachThrash"}, {s="split"}, {10,8}, {20,8}},
|
||||
|
||||
-- 6: NUGGET BRIDGE
|
||||
|
||||
-- To Bill's
|
||||
{36, {0,8}, {9,8}, {9,6}, {9,6}, {8,6}, {8,5}, {s="interact",dir="Up"}, {s="thrashGeodude"}, {10,5}, {s="hikerElixer"}, {10,4}, {13,4}, {13,6}, {15,6}, {15,4}, {17,4}, {17,7}, {18,7}, {s="interact",dir="Down"}, {20,7}, {20,8}, {22,8}, {22,6}, {35,6}, {35,4}, {36,4}, {s="interact",dir="Right"}, {36,5}, {38,5}, {38,4}, {s="lassEther"}, {45,4}, {45,3}},
|
||||
-- Save Bill
|
||||
{88, {2,7}, {2,5}, {5,5}, {s="confirm",dir="Right"}, {1,5}, {s="interact",dir="Up"}, {4,5}, {s="interact",dir="Up"}, {s="waitToTalk"}, {s="potionBeforeGoldeen"}, {s="item",item="escape_rope"}},
|
||||
-- To Misty
|
||||
{3, {19,18}, {19,20}, {30,20}, {30,19}},
|
||||
-- Misty
|
||||
{65, {4,13}, {c="a",a="Misty's Gym"}, {c="potion",b=false}, {4,8}, {2,8}, {2,5}, {7,5}, {7,3}, {6,3}, {5,3}, {s="waitToFight"}, {s="potionBeforeMisty"}, {5,2}, {s="interact",dir="Left"}, {s="fightMisty"}, {s="split"}, {s="tweetMisty"}, {5,3}, {7,3}, {7,5}, {5,5}, {5,14}},
|
||||
|
||||
-- 7: MISTY
|
||||
|
||||
-- Past the policeman
|
||||
{3, {30,20}, {c="potion",b=true,yolo=true}, {8,20}, {8,12}, {27,12}, {27,11}},
|
||||
-- Wrecked house
|
||||
{62, {2,7}, {2,2}, {3,2}, {3,0}},
|
||||
-- Cerulean Rocket
|
||||
{3, {27,9}, {28,9}, {s="potionBeforeRocket"}, {33,9}, {33,18}, {36,18}, {36,31}, {25,31}, {25,36}},
|
||||
-- Out of Cerulean
|
||||
{16, {15,0}, {15,28}, {17,28}, {17,27}},
|
||||
-- Underground entrance
|
||||
{71, {3,7}, {3,4}, {4,4}},
|
||||
-- Underground to Vermilion
|
||||
{119, {5,4}, {4,4}, {s="jingleSkip"}, {2,4}, {2,41}},
|
||||
-- Underground exit
|
||||
{74, {4,4}, {3,8}},
|
||||
-- Oddish
|
||||
{17, {17,14}, {c="a",a="Vermilion City"}, {c="catchOddish"}, {17,15}, {s="potion",hp=10,yolo=7}, {17,19}, {s="catchOddish"}, {11,29}, {s="potion",hp=10,yolo=7}, {11,29}, {s="waitToFight",dir="Down"}, {10,29}, {10,30}, {s="potion",hp=10,yolo=7}, {10,31}, {9,31}, {9,36}},
|
||||
-- Enter Vermilion
|
||||
{5, {19,0}, {c="disableCatch"}, {19,6}, {21,6}, {21,14}, {23,14}, {23,13}},
|
||||
-- Vermilion mart
|
||||
{91, {3,7}, {3,5}, {2,5}, {s="shopVermilionMart"}, {3,5}, {3,8}},
|
||||
-- To S.S. Anne
|
||||
{5, {23,14}, {30,14}, {30,26}, {18,26}, {18,31}},
|
||||
-- Mew
|
||||
{94, {14,0}, {c="a",a="S.S. Anne"}, {14,3}},
|
||||
-- First deck
|
||||
{95, {27,0}, {27,1}, {26,1}, {26,7}, {2,7}, {2,6}},
|
||||
-- Rival 3
|
||||
{96, {2,4}, {2,11}, {3,11}, {3,12}, {37,12}, {37,9}, {s="swap",item="potion",dest=2,chain=true}, {s="potion",hp=23,yolo=16,chain=true}, {s="teach",move="bubblebeam",replace="tackle",close=true}, {37,8}, {s="rivalSandAttack"}, {37,5}, {36,5}, {36,4}},
|
||||
-- Old man Cut
|
||||
{101, {0,7}, {0,4}, {4,4}, {4,3}, {s="interact",dir="Up"}, {4,5}, {0,5}, {0,7}},
|
||||
-- Second deck out
|
||||
{96, {36,4}, {36,12}, {3,12}, {3,11}, {2,11}, {2,4}},
|
||||
-- First deck out
|
||||
{95, {2,6}, {2,7}, {26,7}, {26,-1}},
|
||||
-- Departure
|
||||
{94, {14,2}},
|
||||
-- To Surge
|
||||
{5, {18,29}, {18,26}, {30,26}, {30,14}, {15,14}, {15,17}, {s="potionBeforeSurge"}, {s="swap",item="repel",dest=0,chain=true}, {s="teach",move="cut",poke="oddish",alt="paras",chain=true}, {s="teach",move="dig",poke="paras",alt="squirtle",chain=true}, {s="skill",move="cut",done=0x0D4D}, {15,20}, {12,20}, {12,19}},
|
||||
-- Trashcans
|
||||
{92, {4,17}, {c="a",a="Surge's Gym"}, {4,16}, {2,16}, {2,11}, {s="trashcans"}, {4,6}, {4,3}, {5,3}, {5,2}, {s="interact",dir="Up"}, {s="fightSurge"}, {s="split"}, {s="tweetSurge"}, {4,2}, {4,13}, {5,13}, {5,18}},
|
||||
|
||||
-- 8: SURGE
|
||||
|
||||
-- To bicycle house
|
||||
{5, {12,20}, {c="a",a="Bicycle Shop"}, {15,20}, {15,19}, {s="skill",move="cut",done=0x0D4D}, {15,14}, {9,14}, {9,13}},
|
||||
-- Bicycle cert
|
||||
{90, {2,7}, {2,5}, {0,5}, {0,1}, {2,1}, {s="confirm",dir="Right"}, {s="skill",move="dig",map=90}},
|
||||
-- Cerulean warp
|
||||
{3, {19,18}, {19,23}, {16,23}, {16,26}, {13,26}, {13,25}},
|
||||
-- Bicycle shop
|
||||
{66, {2,7}, {2,3}, {4,3}, {4,2}, {s="procureBicycle"}, {4,7}, {3,7}, {3,8}},
|
||||
-- Bicycle out of Cerulean
|
||||
{3, {13,26}, {s="swap",item="bicycle",dest=1,chain=true}, {s="teach",move="thunderbolt",replace="horn_attack",chain=true}, {s="bicycle"}, {19,26}, {19,27}, {s="skill",move="cut",done=0x0D4D}, {19,29}, {36,29}, {36,16}, {40,16}},
|
||||
-- TPP's Bane
|
||||
{20, {0,8}, {c="a",a="Route 9"}, {4,8}, {s="skill",move="cut",done=0x0C17,val=2}, {13,8}, {13,9}, {s="interact",dir="Down"}, {12,9}, {12,12}, {23,12}, {23,11}, {29,11}, {29,12}, {41,12}, {41,10}, {40,10}, {40,9}, {s="interact",dir="Up"}, {41,9}, {41,6}, {39,6}, {39,4}, {45,4}, {45,3}, {51,3}, {51,8}, {60,8}},
|
||||
-- To the cave
|
||||
{21, {0,8}, {3,8}, {3,10}, {13,10}, {13,15}, {14,15}, {14,26}, {3,26}, {3,18}, {7,18}, {s="item",item="repel"}, {8,18}, {8,17}},
|
||||
-- Rock tunnel
|
||||
{82, {15,3}, {c="a",a="Rock Tunnel"}, {c="potion",b=false}, {15,6}, {23,6}, {23,7}, {s="interact",dir="Down"}, {s="redbarCubone"}, {22,7}, {22,10}, {37,10}, {37,3}},
|
||||
-- B1
|
||||
{232, {33,25}, {33,30}, {27,30}, {s="interact",dir="Left"}, {27,31}, {14,31}, {14,29}, {s="interact",dir="Up"}, {17,29}, {17,24}, {25,24}, {25,16}, {37,16}, {37,11}, {s="item",item="repel"}, {37,3}, {27,3}},
|
||||
-- B2
|
||||
{82, {5,3}, {5,9}, {11,9}, {11,14}, {17,14}, {17,11}},
|
||||
-- B1
|
||||
{232, {23,11}, {14,11}, {14,17}, {8,17}, {8,10}, {7,10}, {s="interact",dir="Left"}, {7,11}, {5,11}, {s="item",item="repel"}, {5,3}, {3,3}},
|
||||
-- Out of the Tunnel
|
||||
{82, {37,17}, {32,17}, {32,23}, {37,23}, {37,28}, {28,28}, {26,24}, {23,24}, {s="interact",dir="Left"}, {23,27}, {15,27}, {15,33}},
|
||||
-- To Lavender Town
|
||||
{21, {8,54}, {c="a",a="Lavender Town"}, {15,54}, {15,65}, {11,65}, {11,69}, {6,69}, {6,72}},
|
||||
-- Through Lavender
|
||||
{4, {6,0}, {6,6}, {0,6}, {0,8}, {-1,8}},
|
||||
-- Leave Lavender
|
||||
{19, {59,8}, {52,8}, {52,13}, {47,13}, {s="interact",dir="Left"}, {47,14}, {42,14}, {42,7}, {40,7}, {40,6}, {29,6}, {29,7}, {23,7}, {23,12}, {14,12}, {14,4}, {13,4}, {13,3}},
|
||||
-- Underground entrance
|
||||
{80, {3,7}, {3,6}, {4,6}, {4,4}},
|
||||
-- Underground
|
||||
{121, {47,2}, {s="bicycle"}, {47,5}, {22,5}, {s="undergroundElixer"}, {2,5}},
|
||||
-- Underground exit
|
||||
{77, {4,4}, {4,8}},
|
||||
-- To Celadon
|
||||
{18, {5,14}, {s="bicycle"}, {8,14}, {8,8}, {4,8}, {4,3}, {-1,3}},
|
||||
-- Celadon
|
||||
{6, {49,11}, {c="a",a="Celadon Mart"}, {14,11}, {14,14}, {10,14}, {10,13}},
|
||||
-- F1: Department store
|
||||
{122, {16,7}, {c="potion",b=true,yolo=true}, {c="pp",on=true}, {16,3}, {12,3}, {12,1}},
|
||||
-- F2
|
||||
{123, {12,2}, {8,2}, {8,5}, {6,5}, {s="shopTM07"}, {5,5}, {s="shopRepels"}, {9,5}, {s="dodgeDepartment"}, {15,2}, {16,2}, {16,1}},
|
||||
-- F3
|
||||
{124, {16,2}, {12,2}, {12,1}},
|
||||
-- F4: Poke Doll
|
||||
{125, {12,2}, {10,2}, {10,5}, {5,5}, {s="shopPokeDoll"}, {11,5}, {11,2}, {16,2}, {16,1}},
|
||||
-- F5
|
||||
{136, {16,2}, {12,2}, {12,1}},
|
||||
-- Roof
|
||||
{126, {15,3}, {12,3}, {s="shopVending"}, {6,3}, {6,4}, {s="giveWater"}, {6,4}, {7,3}, {12,3}, {s="shopExtraWater"}, {15,3}, {15,2}},
|
||||
-- F5: Buffs
|
||||
{136, {12,2}, {8,2}, {8,5}, {5,5}, {s="shopBuffs"}, {1,5}, {1,1}},
|
||||
-- Elevator
|
||||
{127, {1,3}, {1,2}, {3,2}, {3,1}, {s="deptElevator"}, {2,1}, {2,4}},
|
||||
-- F1: Exit department store
|
||||
{122, {1, 2}, {1,7}, {2,7}, {2,8}},
|
||||
-- Leave Celadon
|
||||
{6, {8,14}, {s="bicycle"}, {8,15}, {2,15}, {2,18}, {-1,18}},
|
||||
-- Cut out of Celadon
|
||||
{27, {39,10}, {34,10}, {s="teach",move="horn_drill",replace="bubblebeam",full=true,chain=true}, {s="skill",move="cut",dir="Up",done=0x0D4D}, {34,6}, {27,6}, {27,4}, {23,4}},
|
||||
-- Old man's hall
|
||||
{186, {7,2}, {-1,2}},
|
||||
-- To the Fly house
|
||||
{27, {17,4}, {c="a",a="HM02 Fly"}, {10,4}, {10,6}, {7,6}, {7,5}},
|
||||
-- Fly house
|
||||
{188, {2,7}, {2,4}, {s="interact",dir="Up"}, {2,5}, {s="split"}, {2,8}},
|
||||
|
||||
-- 9: FLY
|
||||
|
||||
-- Fly to Lavender
|
||||
{27, {7,6}, {s="swap",item="super_repel",dest=1,chain=true}, {s="potion",hp=10,chain=true}, {s="teach",move="horn_drill",replace="bubblebeam",chain=true}, {s="item",item="super_repel",chain=true}, {s="swap",item="x_accuracy",dest=2,chain=true}, {s="teach",move="fly",poke="spearow",alt="pidgey",chain=true}, {s="teach",move="rock_slide",replace="poison_sting",chain=true}, {s="fly",dest="lavender",map=4}},
|
||||
-- To the tower
|
||||
{4, {3,6}, {c="a",a="Pokemon Tower"}, {14,6}, {14,5}},
|
||||
-- Pokemon Tower
|
||||
{142, {10,17}, {10,10}, {18,10}, {18,9}},
|
||||
-- F2: Rival
|
||||
{143, {18,9}, {c="setThrash",disable=true}, {18,7}, {16,7}, {16,5}, {15,5}, {s="lavenderRival"}, {5,5}, {5,8}, {3,8}, {3,9}},
|
||||
-- F3
|
||||
{144, {3,9}, {3,10}, {6,10}, {6,13}, {8,13}, {8,6}, {17,6}, {17,9}, {18,9}},
|
||||
-- F4
|
||||
{145, {18,9}, {s="allowDeath",on=true}, {c="potion",b=false}, {18,7}, {16,7}, {s="interact",dir="Left"}, {s="digFight"}, {16,9}, {c="potion",b=true,yolo=true}, {14,9}, {14,10}, {13,10}, {s="interact",dir="Left"}, {14,10}, {14,8}, {11,8}, {11,9}, {10,9}, {10,12}, {7,12}, {7,11}, {4,11}, {4,10}, {3,10}, {3,9}},
|
||||
-- F5
|
||||
{146, {3,9}, {4,9}, {4,11}, {s="interact",dir="Down"}, {4,6}, {13,6}, {13,9}, {9,9}, {9,12}, {14,12}, {14,10}, {18,10}, {s="allowDeath",on=false}, {18,9}},
|
||||
-- F6
|
||||
{147, {18,9}, {18,7}, {15,7}, {15,3}, {11,3}, {11,5}, {10,5}, {s="interact",dir="Left"}, {10,6}, {6,6}, {6,7}, {s="interact",dir="Down"}, {6,14}, {10,14}, {10,16}, {s="pokeDoll"}, {9,16}},
|
||||
-- F7: Top
|
||||
{148, {9,16}, {10,16}, {10,9}, {s="fightXAccuracy"}, {c="setThrash",disable=false}, {10,7}, {s="thunderboltFirst"}, {10,4}, {s="interact",dir="Up"}},
|
||||
-- Old man's house
|
||||
{149, {3,7}, {3,6}, {2,6}, {2,1}, {s="interact",dir="Right"}, {2,8}},
|
||||
|
||||
-- 10: POKéFLUTE
|
||||
|
||||
-- Lavender -> Celadon
|
||||
{4, {7,10}, {s="split"}, {s="fly",dest="celadon",map=6}},
|
||||
-- To Celadon Center
|
||||
{6, {41,10}, {41,9}},
|
||||
-- Celadon Center
|
||||
{133, {3,7}, {3,3}, {s="confirm",dir="Up"}, {3,8}},
|
||||
-- Leave Celadon
|
||||
{6, {41,10}, {c="a",a="Snorlax"}, {s="item",item="super_repel",chain=true}, {s="bicycle"}, {41,11}, {14,11}, {14,14}, {2,14}, {2,18}, {-1,18}},
|
||||
-- トトロだ!
|
||||
{27, {39,10}, {27,10}, {s="swapXSpeeds"}, {s="playPokeflute"}, {23,10}},
|
||||
-- Snorlax pass
|
||||
{186, {7,8}, {-1,8}},
|
||||
-- Bicycle road
|
||||
{27, {17,10}, {c="a",a="Bicycle Road"}, {12,10}, {12,13}, {11,13}, {11,18}},
|
||||
-- Forced down inputs
|
||||
{28, {11,0}, {11,5}, {15,5}, {15,12}, {s="drivebyRareCandy"}, {15,14}, {18,14}, {18,122}, {13,122}, {13,143}},
|
||||
-- Cycling road exit
|
||||
{29, {13,0}, {13,8}, {34,8}},
|
||||
-- Exit building
|
||||
{190, {0,4}, {8,4}},
|
||||
-- Enter Safari City
|
||||
{29, {40,8}, {s="item",item="super_repel",chain=true}, {s="teach",move="ice_beam",replace="rock_slide",chain=true}, {s="bicycle"}, {50,8}},
|
||||
-- Safari City
|
||||
{7, {0,16}, {c="a",a="Safari Zone"}, {3,16}, {3,20}, {23,20}, {23,14}, {29,14}, {29,15}, {35,15}, {35,8}, {37,8}, {37,2}, {22,2}, {22,4}, {18,4}, {18,3}},
|
||||
-- Safari entrance
|
||||
{156, {3,5}, {3,2}, {4,2}, {s="confirm",dir="Right"}},
|
||||
-- Safari 1
|
||||
{220, {15,25}, {s="bicycle"}, {15,16}, {28,16}, {28,11}, {30,11}},
|
||||
-- Safari 2
|
||||
{217, {0,23}, {4,23}, {4,24}, {20,24}, {20,20}, {s="safariCarbos"}, {12,20}, {12,22}, {11,22}, {10,22}, {s="item",item="super_repel",chain=true}, {s="item",item="carbos",poke="nidoking",close=true}, {9,22}, {9,8}, {12,8}, {12,6}, {17,6}, {17,8}, {20,8}, {s="centerSkipFullRestore"}, {20,3}, {7,3}, {7,5}, {-1,5}},
|
||||
-- Safari 3
|
||||
{218, {39,31}, {22,31}, {22,22}, {16,22}, {16,28}, {13,28}, {13,9}, {28,9}, {28,3}, {3,3}, {3,36}},
|
||||
-- Safari 4
|
||||
{219, {21,0}, {21,5}, {19,5}, {19,6}, {s="interact",dir="Down"}, {19,5}, {7,5}, {7,6}, {3,6}, {3,3}},
|
||||
-- Warden
|
||||
{222, {2,7}, {2,6}, {3,6}, {3,4}, {s="interact",dir="Up"}, {3,8}},
|
||||
-- Safari Warp
|
||||
{219, {3,4}, {s="skill",move="dig",map=219}},
|
||||
-- Celadon again
|
||||
{6, {41,10}, {s="bicycle"}, {41,11}, {50,11}},
|
||||
-- To Saffron
|
||||
{18, {0,3}, {c="a",a="Saffron City"}, {4,3}, {4,9}, {10,9}, {10,10}, {12,10}},
|
||||
-- Thirsty guard
|
||||
{76, {0,4}, {6,4}},
|
||||
-- Saffron entry
|
||||
{18, {18,10}, {s="bicycle"}, {20,10}},
|
||||
-- Saffron City
|
||||
{10, {0,18}, {3,18}, {3,22}, {18,22}, {18,21}},
|
||||
-- Silph Co
|
||||
{181, {10,17}, {c="a",a="Silph Co."}, {10,9}, {8,9}, {8,1}, {20,1}, {20,0}},
|
||||
-- Elivator
|
||||
{236, {1,3}, {1,2}, {3,2}, {3,1}, {s="silphElevator"}, {2,1}, {2,4}},
|
||||
-- F10
|
||||
{234, {12,1}, {12,3}, {4,3}, {4,9}, {s="fightSilphMachoke"}, {6,9}, {6,11}, {s="silphCarbos"}, {6,16}, {3,16}, {3,14}, {s="interact",dir="Right"}, {3,15}, {1,15}, {1,13}, {s="item",item="carbos",poke="nidoking",full=true}, {1,12}, {s="interact",dir="Right"}, {1,16}, {3,16}, {s="swapXSpecials"}, {s="teach",move="surf",poke="squirtle",replace="tail_whip",chain=true}, {s="teach",move="earthquake",replace="thrash",chain=true}, {s="item",item="carbos",poke="nidoking",close=true}, {6,16}, {6,9}, {4,9}, {4,1}, {8,1}, {8,0}},
|
||||
-- F9
|
||||
{233, {14,1}, {14,3}, {24,3}, {24,16}, {17,16}, {17,15}},
|
||||
-- Warped
|
||||
{210, {9,15}, {9,16}, {20,16}, {s="interact",dir="Right"}, {9,16}, {9,15}},
|
||||
-- Warp back
|
||||
{233, {17,15}, {17,14}, {17,15}},
|
||||
-- First card
|
||||
{210, {9,15}, {9,13}, {8,13}, {s="interact",dir="Left"}, {6,13}, {6,16}, {3,16}, {3,15}},
|
||||
-- Warp down
|
||||
{208, {3,15}, {3,14}, {18,14}, {18,9}, {s="interact",dir="Left"}, {14,9}, {14,11}, {11,11}},
|
||||
-- Rival 5
|
||||
{212, {5,3}, {c="a",a="Silph Rival"}, {4,3}, {4,2}, {3,2}, {c="potion",b=false}, {s="silphRival"}, {3,7}, {c="potion",b=true,yolo=true}, {5,7}},
|
||||
-- Giovanni
|
||||
{235, {3,2}, {c="a",a="Silph Giovanni"}, {3,11}, {2,11}, {2,15}, {s="rareCandyGiovanni"}, {2,16}, {s="interact",dir="Right"}, {2,15}, {5,15}, {s="potion",hp=17,yolo=12}, {6,15}, {6,14}, {s="interact",dir="Up"}, {6,13}, {s="fightXAccuracy"}, {s="fightSilphGiovanni"}, {s="split"}, {s="waitToPause"}, {s="skill",move="dig",map=235}},
|
||||
|
||||
-- 11: SILPH CO.
|
||||
|
||||
-- Fly to Fuschia
|
||||
{6, {41,10}, {s="fly",dest="fuchsia",map=7}},
|
||||
-- To Koga
|
||||
{7, {19,28}, {c="a",a="Koga's Gym"}, {5,28}, {5,27}},
|
||||
-- Koga
|
||||
{157, {4,17}, {9,17}, {9,9}, {7,9}, {s="interact",dir="Up"}, {9,9}, {9,1}, {1,1}, {1,2}, {s="earthquakeElixer",min=2,chain=true}, {s="potionBeforeHypno"}, {1,3}, {2,3}, {2,5}, {1,5}, {c="potion",b=false}, {1,7}, {s="fightHypno"}, {1,9}, {2,9}, {s="earthquakeElixer",min=4}, {4,9}, {s="interact",dir="Down"}, {s="fightKoga"}, {s="split"}, {1,9}, {1,5}, {2,5}, {2,3}, {1,3}, {1,1}, {9,1}, {9,16}, {5,16}, {5,18}},
|
||||
|
||||
-- 12: KOGA
|
||||
|
||||
-- To the Warden
|
||||
{7, {5,28}, {s="bicycle"}, {6,28}, {6,30}, {24,30}, {30,30}, {30,28}, {27,28}, {27,27}},
|
||||
-- HM04 Strength
|
||||
{155, {4,7}, {4,6}, {2,6}, {2,4}, {s="interact",dir="Up"}, {4,4}, {4,8}},
|
||||
-- Fly home
|
||||
{7, {27,28}, {s="fly",dest="pallet",map=0}},
|
||||
-- Pallet to Cinnabar
|
||||
{0, {5,6}, {s="item",item="super_repel",chain=true}, {s="item",item="rare_candy",amount=3,poke="nidoking",chain=true}, {s="bicycle"}, {s="allowDeath",on=false}, {3,6}, {s="dodgeGirl"}, {3,17}, {s="skill",move="surf",dir="Right",x=4}, {4,18}},
|
||||
-- To Cinnabar
|
||||
{32, {4,0}, {4,14}, {3,14}, {3,90}},
|
||||
-- Enter Cinnabar Mansion
|
||||
{8, {3,0}, {c="a",a="Cinnabar Mansion"}, {3,4}, {6,4}, {6,3}},
|
||||
-- F1
|
||||
{165, {5,27}, {5,10}},
|
||||
-- F2
|
||||
{214, {5,11}, {10,11}, {10,5}, {6,5}, {6,1}},
|
||||
-- F3
|
||||
{215, {6,2}, {11,2}, {11,6}, {10,6}, {s="confirm",dir="Up"}, {14,6}, {14,11}, {16,11}, {16,14}},
|
||||
-- F1 drop
|
||||
{165, {16,14}, {16,15}, {13,15}, {13,20}, {s="cinnabarCarbos"}, {21,23}},
|
||||
-- B1
|
||||
--TODO menu cancel for RC
|
||||
{216, {23,22}, {23,15}, {21,15}, {s="item",item="super_repel",chain=true}, {s="item",item="carbos",poke="nidoking",close=true}, {17,15}, {17,19}, {18,19}, {18,23}, {17,23}, {17,26}, {18,26}, {s="confirm",dir="Up"}, {14,26}, {14,22}, {12,22}, {12,15}, {24,15}, {24,18}, {26,18}, {26,6}, {24,6}, {24,4}, {20,4}, {s="confirm",dir="Up"}, {24,4}, {24,6}, {12,6}, {12,2}, {11,2}, {s="interact",dir="Left"}, {12,2}, {12,7}, {4,7}, {4,9}, {2,9}, {s="interact",dir="Left"}, {5,9}, {5,10}, {s="teach",move="strength",poke="squirtle",replace="tackle",chain=true}, {s="item",item="rare_candy",amount=2,poke="nidoking",close=true}, {5,12}, {s="interact",dir="Down"}, {5,12}, {s="skill",move="dig",map=216}},
|
||||
-- Celadon once again
|
||||
{6, {41,10}, {s="bicycle"}, {41,13}, {36,13}, {36,23}, {25,23}, {25,30}, {35,30}, {35,31}, {s="skill",move="cut",dir="Down",done=0x0D4D}, {35,34}, {5,34}, {5,29}, {12,29}, {12,27}},
|
||||
-- Erika
|
||||
{134, {4,17}, {c="a",a="Erika's Gym"}, {4,16}, {1,16}, {1,9}, {0,9}, {0,4}, {1,4}, {s="skill",move="cut",done=0x0D4D}, {4,4}, {s="interact",dir="Up"}, {s="fightErika"}, {s="split"}, {4,5}, {5,5}, {5,6}, {s="skill",move="cut",dir="Down",done=0x0D4D}, {5,18}},
|
||||
|
||||
-- 13: ERIKA
|
||||
|
||||
-- Fly to Cinnabar
|
||||
{6, {12,28}, {s="fly",dest="cinnabar",map=8}},
|
||||
-- Cinnabar
|
||||
{8, {11,12}, {s="earthquakeElixer",min=4,chain=true}, {s="bicycle"}, {18,12}, {18,3}},
|
||||
-- Cinnabar Gym
|
||||
{166, {16,17}, {c="a",a="Blaine's Gym"}, {16,14}, {18,14}, {18,10}, {15,10}, {15,8}, {s="confirm",dir="Up"}, {16,8}, {16,7}, {18,7}, {18,1}, {12,1}, {12,2}, {10,2}, {s="confirm",dir="Up",type="B"}, {12,2}, {12,7}, {10,7}, {10,8}, {9,8}, {s="confirm",dir="Up",type="B"}, {9,11}, {12,11}, {12,13}, {10,13}, {10,14}, {9,14}, {s="confirm",dir="Up",type="B"}, {9,16}, {1,16}, {1,14}, {s="confirm",dir="Up"}, {2,14}, {2,13}, {4,13}, {4,9}, {1,9}, {1,8}, {s="confirm",dir="Up",type="B"}, {2,8}, {2,7}, {4,7}, {4,5}, {3,5}, {3,4}, {c="potion",b=false}, {s="waitToFight",dir="Up"}, {s="split"}, {s="waitToReceive"}, {s="skill",move="dig",map=166}},
|
||||
|
||||
-- 14: BLAINE
|
||||
|
||||
-- Celadon too many times
|
||||
{6, {41,10}, {c="potion",b=true,yolo=true}, {s="bicycle"}, {41,11}, {50,11}},
|
||||
-- Exit Celadon
|
||||
{18, {0,3}, {4,3}, {4,9}, {10,9}, {10,10}, {12,10}},
|
||||
-- Saffron gate
|
||||
{76, {0,4}, {c="a",a="Saffron City"}, {6,4}},
|
||||
-- Saffron edge
|
||||
{18, {18,10}, {s="earthquakeElixer",min=4,chain=true}, {s="bicycle"}, {20,10}},
|
||||
-- Saffron again
|
||||
{10, {0,18}, {3,18}, {3,6}, {31,6}, {31,4}, {34,4}, {34,3}},
|
||||
-- Sabrina
|
||||
{178, {8,17}, {c="a",a="Sabrina's Gym"}, {8,16}, {11,16}, {11,15}, {16,17}, {16,15}, {15,15}, {18,3}, {18,5}, {15,5}, {1,5}, {11,11}, {11,8}, {10,8}, {s="waitToFight",dir="Left"}, {s="split"}, {11,8}, {11,11}, {s="earthquakeElixer",min=4,chain=true}, {s="skill",move="dig",map=178}},
|
||||
|
||||
-- 15: SABRINA
|
||||
|
||||
-- Celadon
|
||||
{6, {41,10}, {s="fly",dest="viridian",map=1}},
|
||||
-- Viridian again
|
||||
{1, {23,26}, {s="bicycle"}, {19,26}, {19,4}, {27,4}, {27,3}, {34,3}, {34,8}, {32,8}, {32,7}},
|
||||
-- Giovanni Gym
|
||||
{45, {16,17}, {c="potion",b=false}, {c="a",a="Giovanni's Gym"}, {16,16}, {14,16}, {14,9}, {13,9}, {13,7}, {15,7}, {15,4}, {12,4}, {12,5}, {10,5}, {c="a",a="Machoke"}, {10,4}, {s="fightGiovanniMachoke"}, {10,5}, {c="a",a="Giovanni's Gym"}, {13,5}, {13,4}, {15,4}, {15,7}, {13,7}, {13,11}, {14,11}, {14,16}, {16,16}, {16,18}},
|
||||
-- Reset Gym
|
||||
{1, {32,8}, {32,7}},
|
||||
-- Giovanni
|
||||
{45, {16,17}, {c="potion",b=false}, {16,16}, {14,16}, {14,9}, {13,9}, {13,7}, {15,7}, {15,4}, {12,4}, {12,5}, {10,5}, {10,2}, {7,2}, {7,4}, {2,4}, {s="checkGiovanni"}, {2,2}, {s="interact",dir="Up"}, {s="fightGiovanni"}, {s="split"}, {2,4}, {7,4}, {7,2}, {10,2}, {10,5}, {12,5}, {12,4}, {15,4}, {15,7}, {13,7}, {13,11}, {14,11}, {14,16}, {16,16}, {16,18}},
|
||||
|
||||
-- 16: GIOVANNI
|
||||
|
||||
-- Leave Viridian
|
||||
{1, {32,8}, {s="bicycle"}, {32,12}, {17,12}, {17,16}, {16,16}, {16,17}, {-1,17}},
|
||||
-- To Pokemon League
|
||||
{33, {39,9}, {c="a",a="Viridian Rival"}, {35,9}, {35,12}, {31,12}, {31,5}, {29,5}, {s="viridianRival"}, {16,5}, {16,12}, {5,12}, {5,10}, {11,10}, {11,6}, {8,6}, {8,5}},
|
||||
-- Pokemon League 1
|
||||
{193, {4,7}, {4,0}},
|
||||
-- PL 2
|
||||
{34, {7,139}, {s="checkEther"}, {s="ether",max=true,chain=true}, {s="bicycle"}, {7,132}, {14,132}, {14,124}, {9,124}, {9,116}, {10,116}, {10,104}, {s="skill",move="surf",y=103}, {10,92}, {7,92}, {7,90}, {s="grabMaxEther"}, {7,72}, {8,72}, {8,71}, {s="item",item="super_repel",chain=true}, {s="bicycle"}, {8,66}, {10,66}, {10,57}, {12,57}, {12,48}, {6,48}, {6,32}, {4,32}, {4,31}},
|
||||
-- Victory Road
|
||||
{108, {8,17}, {c="a",a="Victory Road"}, {s="tweetVictoryRoad"}, {8,16}, {4,16}, {4,14}, {5,14}, {s="skill",move="strength"}, {5,15}, {4,15}, {4,16}, {7,16}, {s="push",dir="Right",x=0x0255,y=0x0254}, {7,17}, {9,17}, {9,15}, {8,15}, {8,14}, {15,14}, {15,15}, {16,15}, {16,14}, {s="push",dir="Up",x=0x0255,y=0x0254}, {14,14}, {14,12}, {16,12}, {16,11}, {17,11}, {17,12}, {14,12}, {14,14}, {8,14}, {8,16}, {5,16}, {5,12}, {11,12}, {11,6}, {7,6}, {7,8}, {3,8}, {3,5}, {2,5}, {2,1}, {1,1}},
|
||||
-- F2
|
||||
{194, {0,8}, {0,9}, {3,9}, {3,13}, {5,13}, {5,14}, {s="item",item="super_repel",chain=true}, {s="skill",move="strength"}, {4,14}, {4,13}, {3,13}, {3,15}, {4,15}, {4,16}, {3,16}, {s="push",dir="Left",x=0x02B5,y=0x02B4}, {3,11}, {5,11}, {5,8}, {14,8}, {14,14}, {21,14}, {21,16}, {28,16}, {28,11}, {23,11}, {23,7}},
|
||||
-- F3
|
||||
{198, {23,7}, {23,6}, {22,6}, {22,4}, {s="skill",move="strength"}, {22,2}, {23,2}, {23,1}, {7,1}, {7,0}, {6,0}, {6,1}, {7,1}, {7,2}, {3,2}, {3,1}, {2,1}, {2,4}, {1,4}, {1,5}, {2,5}, {2,4}, {4,4}, {4,2}, {7,2}, {7,1}, {20,1}, {20,6}, {17,6}, {17,4}, {9,4}, {9,10}, {5,10}, {5,8}, {1,8}, {1,15}, {11,15}, {11,16}, {20,16}, {20,15}, {23,15}},
|
||||
-- F2
|
||||
{194, {22,16}, {s="potionBeforeLorelei"}, {s="item",item="super_repel",chain=true}, {s="skill",move="strength"}, {s="bicycle"}, {22,17}, {24,17}, {24,16}, {11,16}, {s="push",dir="Left",x=0x02D5,y=0x02D4}, {21,16}, {21,14}, {25,14}},
|
||||
-- F3
|
||||
{198, {27,15}, {27,8}, {26,8}},
|
||||
-- F2 Exit
|
||||
{194, {27,7}, {30,7}},
|
||||
-- Victory end
|
||||
{34, {14,32}, {18,32}, {18,20}, {14,20}, {14,10}, {13,10}, {13,6}, {10,6}, {10,-1}},
|
||||
-- Elite Four entrance
|
||||
{9, {10,17}, {c="a",a="Elite Four"}, {10,5}},
|
||||
-- Last Center
|
||||
{174, {7,11}, {15,9}, {15,8}, {s="depositPokemon"}, {7,8}, {7,7}, {s="centerSkip"}, {4,7}, {3,7}, {3,2}, {8,2}, {8,0}},
|
||||
|
||||
-- 17: LORELEI
|
||||
|
||||
-- Lorelei
|
||||
{245, {4,5}, {c="a",a="Lorelei"}, {c="potion",b=false}, {4,2}, {s="interact",dir="Right"}, {s="lorelei"}, {s="split"}, {4,0}},
|
||||
-- Bruno
|
||||
{246, {4,5}, {c="a",a="Bruno"}, {s="item",item="elixer",poke="nidoking"}, {4,2}, {s="interact",dir="Right"}, {s="bruno"}, {s="split"}, {4,0}},
|
||||
-- Agatha
|
||||
{247, {4,5}, {c="a",a="Agatha"}, {s="potion",hp=113,full=true}, {4,2}, {s="interact",dir="Right"}, {s="agatha"}, {s="split"}, {4,1}, {s="prepareForLance"}, {s="ether",close=true}, {4,0}},
|
||||
-- Lance
|
||||
{113, {6,11}, {c="a",a="Lance"}, {6,2}, {s="lance"}, {s="split"}, {5,2}, {5,1}, {s="prepareForBlue"}, {5,-1}},
|
||||
-- Blue
|
||||
{120, {4,3}, {c="a",a="Blue"}, {s="blue"}, {3,0}},
|
||||
-- Champion
|
||||
{118, {4,2}, {s="champion"}}
|
||||
|
||||
}
|
||||
|
||||
return Paths
|
|
@ -0,0 +1,37 @@
|
|||
local Paths = {
|
||||
-- Red's room
|
||||
{38, {3,6}, {5,6}, {5,1}, {7,1}},
|
||||
-- Red's house
|
||||
{39, {7,1}, {7,6}, {3,6}, {3,8}},
|
||||
-- Into the Wild
|
||||
{0, {5,6}, {10,6}, {10,0}},
|
||||
-- Choose your character!
|
||||
{40, {5,3}, {c="a",a="Pallet Rival"}, {5,4}, {7,4}, {s="confirm",dir="Up",type="A"}, {5,3}, {s="confirm",dir="Up",type="B"}, {5,6}, {s="waitToFight"}, {5,12}},
|
||||
-- Let's try this escape again
|
||||
{0, {12,12}, {c="a",a="Pallet Town"}, {c="encounters",limit=4}, {9,12}, {9,2}, {10,2}, {10,-1}},
|
||||
-- First encounters
|
||||
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
|
||||
-- To the Mart
|
||||
{1, {21,35}, {21,30}, {19,30}, {19,20}, {29,20}, {29,19}},
|
||||
-- Viridian Mart
|
||||
{42, {2,5}, {3,5}, {3,8}},
|
||||
-- Backtracking
|
||||
{1, {29,20}, {c="encounters",limit=5}, {29,21}, {26,21}, {26,30}, {20,30}, {20,36}},
|
||||
-- Parkour
|
||||
{12, {10, 0}, {10,3}, {8,3}, {8,18}, {9,18}, {9,22}, {12,22}, {12,24}, {10,24}, {10,36}},
|
||||
-- To Oak's lab
|
||||
{0, {10,0}, {10,7}, {9,7}, {9,12}, {12,12}, {12,11}},
|
||||
-- Parcel delivery
|
||||
{40, {5,11}, {5,3}, {4,3}, {4,1}, {5,1}, {s="interact",dir="Down"}, {4,1}, {4,12}},
|
||||
-- Leaving home
|
||||
{0, {12,12}, {9,12}, {9,2}, {10,2}, {10,-1}},
|
||||
-- The grass again!?
|
||||
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
|
||||
-- Back to the Mart
|
||||
{1, {21,35}, {21,30}, {19,30}, {19,20}, {29,20}, {29,19}},
|
||||
-- Viridian Mart redux
|
||||
{42, {3,7}, {3,5}, {2,5}, {s="shopViridianPokeballs"}, {3,5}, {3,8}},
|
||||
|
||||
}
|
||||
|
||||
return Paths
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,138 @@
|
|||
local paths = {
|
||||
-- Red's room
|
||||
{38, {3,6}, {1,6}, {1,5}, {0,5}, {0,2}, {s="grabPCPotion"}, {7,2}, {7,1}},
|
||||
-- Red's house
|
||||
{39, {7,1}, {7,6}, {3,6}, {3,8}},
|
||||
-- Into the Wild
|
||||
{0, {5,6}, {s="checkStrats"}, {10,6}, {10,1}},
|
||||
-- Choose your character!
|
||||
{40, {5,3}, {c="a",a="Pallet Rival"}, {5,4}, {8,4}, {s="bulbasaurIChooseYou"}, {8,5}, {5,5}, {5,6}, {s="fightCharmander"}, {s="split"}, {5,12}},
|
||||
|
||||
-- 1: RIVAL 1
|
||||
|
||||
-- Let's try this escape again
|
||||
{0, {12,12}, {c="a",a="Pallet Town"}, {c="viridianExpGlitch"}, {c="encounters",limit=4}, {9,12}, {9,2}, {10,2}, {10,-1}},
|
||||
-- First encounters
|
||||
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
|
||||
-- To the Mart
|
||||
{1, {21,35}, {21,30}, {19,30}, {19,20}, {29,20}, {29,19}},
|
||||
-- Viridian Mart
|
||||
{42, {2,5}, {3,5}, {3,8}},
|
||||
-- Backtracking
|
||||
{1, {29,20}, {c="encounters",limit=5}, {29,21}, {26,21}, {26,30}, {20,30}, {20,36}},
|
||||
-- Parkour
|
||||
{12, {10, 0}, {10,3}, {8,3}, {8,18}, {9,18}, {9,22}, {12,22}, {12,24}, {10,24}, {10,36}},
|
||||
-- To Oak's lab
|
||||
{0, {10,0}, {10,7}, {9,7}, {9,12}, {12,12}, {12,11}},
|
||||
-- Parcel delivery
|
||||
{40, {5,11}, {5,3}, {4,3}, {4,1}, {5,1}, {s="interact",dir="Down"}, {4,1}, {4,12}},
|
||||
-- Leaving home
|
||||
{0, {12,12}, {c="viridianBackupExpGlitch"}, {9,12}, {9,2}, {10,2}, {10,-1}},
|
||||
-- The grass again!?
|
||||
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
|
||||
-- Back to the Mart
|
||||
{1, {21,35}, {c="a",a="Viridian City"}, {c="encounters",limit=8}, {21,30}, {19,30}, {19,20}, {29,20}, {29,19}},
|
||||
-- Viridian Mart redux
|
||||
{42, {3,7}, {3,5}, {2,5}, {s="shopViridian"}, {3,5}, {3,8}},
|
||||
-- To the forest
|
||||
{1, {29,20}, {18,20}, {18,6}, {s="dodgeViridianOldMan"}, {17,4}, {s="healTreePotion"}, {15,4}, {s="speak"}, {17,4}, {17, 0}, {17, -1}},
|
||||
-- Out of Viridian City
|
||||
{13, {7,71}, {7,57}, {4,57}, {4,52}, {8,52}, {c="a",a="Pidgey grass"}, {c="pidgeyBackupExp"}, {c="catchPidgey"}, {s="catchPidgey"}, {8,46}, {s="split"}, {c="disableCatch"}, {3,46}, {3,43}},
|
||||
|
||||
-- 2. PIDGEY
|
||||
|
||||
-- Forest entrance
|
||||
{50, {4,7}, {c="a",a="Viridian Forest"}, {c="encounters",limit=9}, {4,1}, {5,1}, {5,0}},
|
||||
-- Viridian Forest
|
||||
{51, {17,47}, {17,43}, {26,43}, {26,34}, {25,34}, {25,32}, {27,32}, {27,20}, {25,20}, {25,12}, {s="grabAntidote"}, {25,9}, {17,9}, {17,16}, {13,16}, {13,3}, {7,3}, {7,22}, {1,22}, {1,19}, {s="grabForestPotion"}, {1,18}, {s="fightWeedle"}, {c="encounters",limit=12}, {1,16}, {s="checkSpec"}, {1,15}, {s="equipForGlitch"}, {1,5}, {s="checkInventory"}, {1,-1}},
|
||||
-- Forest exit
|
||||
{47, {4,7}, {4,1}, {5,1}, {5,0}},
|
||||
-- Road to Pewter City
|
||||
{13, {3,11}, {c="a",a="Pewter City"}, {3,8}, {8,8}, {8,-1}},
|
||||
-- Pewter City
|
||||
{2, {18,35}, {18,26}, {s="checkForPidgey"}, {s="split"}, {18,22}, {19,22}, {19,18}, {36,18}, {s="prepareSave"}, {37,18}, {s="performSkip"}, {s="performReset"}, {s="speak"}, {40,18}},
|
||||
|
||||
-- 3: READY FOR SKIP
|
||||
|
||||
-- Route3 #1
|
||||
{14, {0,10}, {c="a",a="Route 3"}, {0,8}, {-1,8}},
|
||||
-- Back to Pewter City to talk
|
||||
{2, {39,16}, {36,16}, {s="openPokemonMenu"}, {s="closeMenu"}, {s="speakToGlithGuy"}, {s="split"}, {s="leaveGlitchGuy"}},
|
||||
|
||||
-- 4: SKIP DONE
|
||||
|
||||
-- Saffron City Poke Center
|
||||
{182, {3,7}, {c="a",a="Saffron City Brock Skip"}, {3,4}, {s="checkPidgeyHP"}, {s="walkBack"}, {s="split"}, {3,3}, {s="confirm",dir="Up"}, {3,8}},
|
||||
-- Saffron City
|
||||
{10, {9,30}, {2,30}, {2,18}, {-1,18}},
|
||||
-- Enter Guard
|
||||
{18, {19,10}, {17,10}},
|
||||
-- Guard House
|
||||
{76, {5,4}, {3,4}, {s="speak"}, {2,4}, {-1,4}},
|
||||
-- To Celadon City
|
||||
{18, {11,10}, {8,10}, {8,9}, {4,9}, {4,3}, {-1,3}},
|
||||
-- Celadon City
|
||||
{6, {49,11}, {36,11}, {36,23}, {25,23}, {25,28}, {31,28}, {31,27}},
|
||||
-- Getting Coin Case
|
||||
{138, {3,7}, {3,1}, {1,1}, {s="speak"}, {3,1}, {3,8}},
|
||||
-- Celadon City #2
|
||||
{6, {31,28}, {25,28}, {25,23}, {36,23}, {36,20}, {28,20}, {28,19}},
|
||||
-- Game Center
|
||||
{135, {15,17}, {15,11}, {s="interact",dir="Left"}, {15,9}, {s="speak"}, {15,18}},
|
||||
-- Celadon City #3
|
||||
{6, {28,20}, {33,20}, {33,19}},
|
||||
-- Buy Abra
|
||||
{137, {4,7}, {4,4}, {2,4}, {2,3}, {s="getAbra"}, {c="a",a="Celadon City Abra"}, {s="split"}, {4,3}, {4,8}},
|
||||
|
||||
-- 5. ABRA
|
||||
|
||||
-- Celadon City #4
|
||||
{6, {33,20}, {s="teleport",map=10}},
|
||||
-- Saffron City after teleport
|
||||
{10, {9,30}, {9,29}},
|
||||
-- Poke Center depose
|
||||
{182, {3,7}, {3,4}, {13,4}, {s="deposeAll",keep="abra"}, {4,4}, {4,8}},
|
||||
-- Saffron City after depose
|
||||
{10, {9,30}, {9,32}, {20,32}, {20,36}},
|
||||
-- Leave Saffron City
|
||||
{17, {10,0}, {10,2}},
|
||||
-- South Guard
|
||||
{73, {3,0}, {3,2}, {s="speak"}, {3,3}, {3,6}},
|
||||
-- Route6
|
||||
{17, {10,8}, {10,10}, {7,10}, {7,13}, {5,13}, {5,15}, {s="performTeleportGlitch"}, {s="swapItem",item="coin_case",pos1=5}, {s="teleport",map=10}},
|
||||
|
||||
-- 6. TELEPORT GLITCH #1
|
||||
|
||||
-- To the Dojo
|
||||
{10, {9,30}, {c="a",a="Saffron City Teleport #1"}, {s="split"}, {3,30}, {3,7}, {23,7}, {23,4}, {26,4}, {26,3}},
|
||||
-- Dojo Gym
|
||||
{177, {4,11}, {4,10}, {2,10}, {2,7}, {s="allowDeath",on=true}, {s="fightGymGuy"}},
|
||||
-- Saffron City after death
|
||||
{10, {9,30}, {s="allowDeath",on=false}, {s="openMenu"}, {s="closeMenu"}, {9,32}, {20,32}, {20,36}},
|
||||
-- MissingNo
|
||||
{17, {10,0}, {s="closingAutomation"}, {s="battleMissingNo"}, {10,2}},
|
||||
-- South Guard #2
|
||||
{73, {3,0}, {3,2}, {s="speak"}, {3,3}, {3,6}},
|
||||
-- Route6 #2
|
||||
{17, {10,8}, {10,10}, {7,10}, {7,13}, {5,13}, {5,15}, {s="performTeleportGlitch"}, {s="tossItem",pos=6,amount=2}, {s="teleport",map=10}},
|
||||
|
||||
-- 7. TELEPORT GLITCH #2
|
||||
|
||||
-- To the Dojo #2
|
||||
{10, {9,30}, {c="a",a="Saffron City Teleport #2"}, {s="split"}, {3,30}, {3,7}, {23,7}, {23,4}, {26,4}, {26,3}},
|
||||
-- Dojo Gym #2
|
||||
{177, {4,11}, {4,10}, {2,10}, {2,7}, {s="allowDeath",on=true}, {s="fightGymGuy"}},
|
||||
-- Saffron City after death #2
|
||||
{10, {9,30}, {s="allowDeath",on=false}, {s="openMenu"}, {s="closeMenu"}, {9,32}, {20,32}, {20,36}},
|
||||
-- MissingNo #2
|
||||
{17, {10,0}, {s="closingAutomation"}, {s="battleMissingNo"}, {10,2}},
|
||||
-- South Guard #3
|
||||
{73, {3,0}, {c="a",a="Hall Of Fame"}, {s="swapItem",pos1=3,pos2=6}, {s="tossItem",pos=6}, {s="tossItem",pos=1}, {s="tossItem",pos=1}, {s="tossItem",pos=1}, {s="tossItem",pos=1}, {s="tossItem",pos=1,amount=253}, {s="swapItem",pos1=1,pos2=2}, {s="swapItem",pos1=2,pos2=1}, {s="tossItem",pos=28,amount=1}, {s="swapItem",pos1=23,pos2=36}, {s="tossTM",pos=36,amount=9}, {s="closeMenu"}, {3,-1}},
|
||||
|
||||
-- 8. HALL OF FAME
|
||||
|
||||
-- Champion
|
||||
{118, {s="champion"}}
|
||||
}
|
||||
|
||||
return paths
|
|
@ -0,0 +1,138 @@
|
|||
local paths = {
|
||||
-- Red's room
|
||||
{38, {3,6}, {1,6}, {1,5}, {0,5}, {0,2}, {s="grabPCPotion"}, {7,2}, {7,1}},
|
||||
-- Red's house
|
||||
{39, {7,1}, {7,6}, {3,6}, {3,8}},
|
||||
-- Into the Wild
|
||||
{0, {5,6}, {s="checkStrats"}, {10,6}, {10,1}},
|
||||
-- Choose your character!
|
||||
{40, {5,3}, {c="a",a="Pallet Rival"}, {5,4}, {8,4}, {s="bulbasaurIChooseYou"}, {8,5}, {5,5}, {5,6}, {s="fightCharmander"}, {s="split"}, {5,12}},
|
||||
|
||||
-- 1: RIVAL 1
|
||||
|
||||
-- Let's try this escape again
|
||||
{0, {12,12}, {c="a",a="Pallet Town"}, {c="viridianExpGlitch"}, {c="encounters",limit=4}, {9,12}, {9,2}, {10,2}, {10,-1}},
|
||||
-- First encounters
|
||||
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
|
||||
-- To the Mart
|
||||
{1, {21,35}, {21,30}, {19,30}, {19,20}, {29,20}, {29,19}},
|
||||
-- Viridian Mart
|
||||
{42, {2,5}, {3,5}, {3,8}},
|
||||
-- Backtracking
|
||||
{1, {29,20}, {c="encounters",limit=5}, {29,21}, {26,21}, {26,30}, {20,30}, {20,36}},
|
||||
-- Parkour
|
||||
{12, {10, 0}, {10,3}, {8,3}, {8,18}, {9,18}, {9,22}, {12,22}, {12,24}, {10,24}, {10,36}},
|
||||
-- To Oak's lab
|
||||
{0, {10,0}, {10,7}, {9,7}, {9,12}, {12,12}, {12,11}},
|
||||
-- Parcel delivery
|
||||
{40, {5,11}, {5,3}, {4,3}, {4,1}, {5,1}, {s="interact",dir="Down"}, {4,1}, {4,12}},
|
||||
-- Leaving home
|
||||
{0, {12,12}, {c="viridianBackupExpGlitch"}, {9,12}, {9,2}, {10,2}, {10,-1}},
|
||||
-- The grass again!?
|
||||
{12, {10,35}, {10,30}, {8,30}, {8,24}, {12,24}, {12,20}, {9,20}, {9,14}, {14,14}, {s="dodgePalletBoy"}, {14,2}, {11,2}, {11,-1}},
|
||||
-- Back to the Mart
|
||||
{1, {21,35}, {c="a",a="Viridian City"}, {c="encounters",limit=8}, {21,30}, {19,30}, {19,20}, {29,20}, {29,19}},
|
||||
-- Viridian Mart redux
|
||||
{42, {3,7}, {3,5}, {2,5}, {s="shopViridian"}, {3,5}, {3,8}},
|
||||
-- To the forest
|
||||
{1, {29,20}, {18,20}, {18,6}, {s="dodgeViridianOldMan"}, {17,4}, {s="healTreePotion"}, {15,4}, {s="speak"}, {17,4}, {17, 0}, {17, -1}},
|
||||
-- Out of Viridian City
|
||||
{13, {7,71}, {7,57}, {4,57}, {4,52}, {8,52}, {c="a",a="Pidgey grass"}, {c="pidgeyBackupExp"}, {c="catchPidgey"}, {s="catchPidgey"}, {8,46}, {s="split"}, {c="disableCatch"}, {3,46}, {3,43}},
|
||||
|
||||
-- 2. PIDGEY
|
||||
|
||||
-- Forest entrance
|
||||
{50, {4,7}, {c="a",a="Viridian Forest"}, {c="encounters",limit=9}, {4,1}, {5,1}, {5,0}},
|
||||
-- Viridian Forest
|
||||
{51, {17,47}, {17,43}, {26,43}, {26,34}, {25,34}, {25,32}, {27,32}, {27,20}, {25,20}, {25,12}, {s="grabAntidote"}, {25,9}, {17,9}, {17,16}, {13,16}, {13,3}, {7,3}, {7,22}, {1,22}, {1,19}, {s="grabForestPotion"}, {1,18}, {s="fightWeedle"}, {c="encounters",limit=12}, {1,16}, {s="checkSpec"}, {1,15}, {s="equipForGlitch"}, {1,5}, {s="checkInventory"}, {1,-1}},
|
||||
-- Forest exit
|
||||
{47, {4,7}, {4,1}, {5,1}, {5,0}},
|
||||
-- Road to Pewter City
|
||||
{13, {3,11}, {c="a",a="Pewter City"}, {3,8}, {8,8}, {8,-1}},
|
||||
-- Pewter City
|
||||
{2, {18,35}, {18,26}, {s="checkForPidgey"}, {s="split"}, {18,22}, {19,22}, {19,18}, {36,18}, {s="prepareSave"}, {37,18}, {s="performSkip"}, {s="performReset"}, {s="speak"}, {40,18}},
|
||||
|
||||
-- 3: READY FOR SKIP
|
||||
|
||||
-- Route3 #1
|
||||
{14, {0,10}, {c="a",a="Route 3"}, {0,8}, {-1,8}},
|
||||
-- Back to Pewter City to talk
|
||||
{2, {39,16}, {36,16}, {s="openPokemonMenu"}, {s="closeMenu"}, {s="speakToGlithGuy"}, {s="split"}, {s="leaveGlitchGuy"}},
|
||||
|
||||
-- 4: SKIP DONE
|
||||
|
||||
-- Saffron City Poke Center
|
||||
{182, {3,7}, {c="a",a="Saffron City Brock Skip"}, {3,4}, {s="checkPidgeyHP"}, {s="walkBack"}, {s="split"}, {3,3}, {s="confirm",dir="Up"}, {3,8}},
|
||||
-- Saffron City
|
||||
{10, {9,30}, {2,30}, {2,18}, {-1,18}},
|
||||
-- Enter Guard
|
||||
{18, {19,10}, {17,10}},
|
||||
-- Guard House
|
||||
{76, {5,4}, {3,4}, {s="speak"}, {2,4}, {-1,4}},
|
||||
-- To Celadon City
|
||||
{18, {11,10}, {8,10}, {8,9}, {4,9}, {4,3}, {-1,3}},
|
||||
-- Celadon City
|
||||
{6, {49,11}, {36,11}, {36,23}, {25,23}, {25,28}, {31,28}, {31,27}},
|
||||
-- Getting Coin Case
|
||||
{138, {3,7}, {3,1}, {1,1}, {s="speak"}, {3,1}, {3,8}},
|
||||
-- Celadon City #2
|
||||
{6, {31,28}, {25,28}, {25,23}, {36,23}, {36,20}, {28,20}, {28,19}},
|
||||
-- Game Center
|
||||
{135, {15,17}, {16,17}, {16,15}, {s="speak"}, {16,13}, {s="interact",dir="Right"}, {16,11}, {15,11}, {s="interact",dir="Left"}, {15,9}, {s="speak"}, {15,8}, {9,8}, {9,11}, {s="speak"}, {10,11}, {10,15}, {s="speak"}, {10,17}, {15,17}, {15,18}},
|
||||
-- Celadon City #3
|
||||
{6, {28,20}, {33,20}, {33,19}},
|
||||
-- Buy Abra
|
||||
{137, {4,7}, {4,4}, {2,4}, {2,3}, {s="getAbra"}, {c="a",a="Celadon City Abra"}, {s="split"}, {4,3}, {4,8}},
|
||||
|
||||
-- 5. ABRA
|
||||
|
||||
-- Celadon City #4
|
||||
{6, {33,20}, {s="teleport",map=10}},
|
||||
-- Saffron City after teleport
|
||||
{10, {9,30}, {9,29}},
|
||||
-- Poke Center depose
|
||||
{182, {3,7}, {3,4}, {13,4}, {s="deposeAll",keep="abra"}, {4,4}, {4,8}},
|
||||
-- Saffron City after depose
|
||||
{10, {9,30}, {9,32}, {20,32}, {20,36}},
|
||||
-- Leave Saffron City
|
||||
{17, {10,0}, {10,2}},
|
||||
-- South Guard
|
||||
{73, {3,0}, {3,2}, {s="speak"}, {3,3}, {3,6}},
|
||||
-- Route6
|
||||
{17, {10,8}, {10,10}, {7,10}, {7,13}, {5,13}, {5,15}, {s="performTeleportGlitch"}, {s="swapItem",item="coin_case",pos1=5}, {s="teleport",map=10}},
|
||||
|
||||
-- 6. TELEPORT GLITCH #1
|
||||
|
||||
-- To the Dojo
|
||||
{10, {9,30}, {c="a",a="Saffron City Teleport #1"}, {s="split"}, {3,30}, {3,7}, {23,7}, {23,4}, {26,4}, {26,3}},
|
||||
-- Dojo Gym
|
||||
{177, {4,11}, {4,10}, {2,10}, {2,7}, {s="allowDeath",on=true}, {s="fightGymGuy"}},
|
||||
-- Saffron City after death
|
||||
{10, {9,30}, {s="allowDeath",on=false}, {s="openMenu"}, {s="closeMenu"}, {9,32}, {20,32}, {20,36}},
|
||||
-- MissingNo
|
||||
{17, {10,0}, {s="closingAutomation"}, {s="battleMissingNo"}, {10,2}},
|
||||
-- South Guard #2
|
||||
{73, {3,0}, {3,2}, {s="speak"}, {3,3}, {3,6}},
|
||||
-- Route6 #2
|
||||
{17, {10,8}, {10,10}, {7,10}, {7,13}, {5,13}, {5,15}, {s="performTeleportGlitch"}, {s="tossItem",pos=6,amount=2}, {s="teleport",map=10}},
|
||||
|
||||
-- 7. TELEPORT GLITCH #2
|
||||
|
||||
-- To the Dojo #2
|
||||
{10, {9,30}, {c="a",a="Saffron City Teleport #2"}, {s="split"}, {3,30}, {3,7}, {23,7}, {23,4}, {26,4}, {26,3}},
|
||||
-- Dojo Gym #2
|
||||
{177, {4,11}, {4,10}, {2,10}, {2,7}, {s="allowDeath",on=true}, {s="fightGymGuy"}},
|
||||
-- Saffron City after death #2
|
||||
{10, {9,30}, {s="allowDeath",on=false}, {s="openMenu"}, {s="closeMenu"}, {9,32}, {20,32}, {20,36}},
|
||||
-- MissingNo #2
|
||||
{17, {10,0}, {s="closingAutomation"}, {s="battleMissingNo"}, {10,2}},
|
||||
-- South Guard #3
|
||||
{73, {3,0}, {c="a",a="Hall Of Fame"}, {s="swapItem",pos1=3,pos2=6}, {s="tossItem",pos=6}, {s="tossItem",pos=1}, {s="tossItem",pos=1}, {s="tossItem",pos=1}, {s="tossItem",pos=1}, {s="tossItem",pos=1,amount=253}, {s="swapItem",pos1=1,pos2=2}, {s="swapItem",pos1=2,pos2=1}, {s="tossItem",pos=28,amount=1}, {s="swapItem",pos1=23,pos2=36}, {s="tossTM",pos=36,amount=9}, {s="closeMenu"}, {3,-1}},
|
||||
|
||||
-- 8. HALL OF FAME
|
||||
|
||||
-- Champion
|
||||
{118, {s="champion"}}
|
||||
}
|
||||
|
||||
return paths
|
|
@ -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,294 @@
|
|||
--##################################################
|
||||
--############# ############
|
||||
--############# 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 = "Blue" -- Set to Red, Blue or Yellow
|
||||
GAME_RUN = "No Save Corruption" -- Set to "Any%" or "No save corruption" for the run you want
|
||||
|
||||
--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 = "aaqrrzz" -- Player name
|
||||
|
||||
--No save corruption run Settings
|
||||
BULBASAUR_NAME = "B" -- Set Bulbasaur name
|
||||
ABRA_NAME = "A" -- Set Abra name
|
||||
PIDGEY_NAME = "P" -- Set Pidgey name
|
||||
STRATS = "" -- Set to "PP" or "Pidgey" if you want a forced Strats run, otherwise the bot will choice
|
||||
|
||||
--Any% Speedrun Settings
|
||||
SQUIRTLE_NAME = "S" -- Set Squirtle name for red/blue
|
||||
RIVAL_NAME = "> " -- Rival name (no save corruption run use internal set name)
|
||||
|
||||
--Advanced area Settings
|
||||
PATH_IDX = 0 -- Start the bot to the specified path idx
|
||||
STEP_IDX = 0 -- Start the bot to the specified step idx
|
||||
PRINT_PATH = false -- Print the current path in the console.
|
||||
PRINT_STEP = false -- Print the current step in the console.
|
||||
|
||||
--NAMES SETTINGS TIPS :
|
||||
-- - Can use up to 7 letter ingame
|
||||
-- - Upper and Lower case allowed
|
||||
-- - Specials Characters : <=Pk, >=Mn, {=♂, }=♀
|
||||
|
||||
|
||||
|
||||
--#####################################################################################
|
||||
--#####################################################################################
|
||||
--########### ###############
|
||||
--########### PLEASE DON'T EDIT ANYTHING BELLOW, IT'S AT YOUR RISK ###############
|
||||
--########### START CODE (hard hats on) ###############
|
||||
--########### ###############
|
||||
--#####################################################################################
|
||||
--#####################################################################################
|
||||
|
||||
-- SET VALUES
|
||||
|
||||
local VERSION = "2.6.5"
|
||||
|
||||
YELLOW = memory.getcurrentmemorydomainsize() > 30000
|
||||
|
||||
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
|
||||
local UsingCustomPath = false --used when we set a custom path
|
||||
|
||||
-- SET DIR
|
||||
|
||||
local lowerGameRun = string.lower(GAME_RUN)
|
||||
local lowerGameName = string.lower(GAME_NAME)
|
||||
local secondStratDir = ""
|
||||
local secondPaintDir = ""
|
||||
if lowerGameRun == "no save corruption" then
|
||||
if lowerGameName == "red" or lowerGameName == "blue" then
|
||||
secondStratDir = ".red-blue"
|
||||
secondPaintDir = secondStratDir
|
||||
end
|
||||
else
|
||||
secondStratDir = YELLOW and ".yellow" or ".red-blue"
|
||||
end
|
||||
|
||||
-- LOAD DIR
|
||||
|
||||
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."..lowerGameRun..secondStratDir..".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."..lowerGameRun..secondPaintDir..".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
|
||||
-- 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
|
||||
local OWNER_ANY = "Kylecoburn"
|
||||
local OWNER_OTHER = "Bouletmarc"
|
||||
if lowerGameRun == "any%" then
|
||||
OWNER = OWNER_ANY
|
||||
else
|
||||
OWNER = OWNER_ANY.." & "..OWNER_OTHER
|
||||
end
|
||||
p("Welcome to PokeBot Version "..VERSION, true)
|
||||
p("Actually running Pokemon "..GAME_NAME.." "..GAME_RUN.." 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
|
||||
|
||||
if PATH_IDX ~= 0 and STEP_IDX ~= 0 then
|
||||
UsingCustomPath = true
|
||||
end
|
||||
|
||||
-- MAIN LOOP
|
||||
|
||||
local previousMap
|
||||
|
||||
local RebootDone = false
|
||||
|
||||
while true do
|
||||
local currentMap = Memory.value("game", "map")
|
||||
if currentMap ~= previousMap then
|
||||
Input.clear()
|
||||
previousMap = currentMap
|
||||
end
|
||||
if Strategies.frames then
|
||||
if Memory.value("game", "battle") == 0 then
|
||||
Strategies.frames = Strategies.frames + 1
|
||||
end
|
||||
Utils.drawText(0, 80, Strategies.frames)
|
||||
end
|
||||
if Bridge.polling then
|
||||
Settings.pollForResponse()
|
||||
end
|
||||
|
||||
if not Input.update() then
|
||||
if not Utils.ingame() then
|
||||
if currentMap == 0 then
|
||||
if running then
|
||||
if not hasAlreadyStartedPlaying then
|
||||
client.reboot_core()
|
||||
hasAlreadyStartedPlaying = true
|
||||
else
|
||||
if not RUNNING4CONTINUE then
|
||||
resetAll() --reset if not running to continue
|
||||
RUNNING4NEWGAME = true --set back on in case we done a reboot
|
||||
else
|
||||
running = false --continue adventure
|
||||
end
|
||||
end
|
||||
else
|
||||
if UsingCustomPath then
|
||||
if not EXTERNALDONE then --continue adventure
|
||||
RUNNING4CONTINUE, RUNNING4NEWGAME = true, false
|
||||
elseif EXTERNALDONE and InternalDone then
|
||||
RUNNING4NEWGAME = true --set back to new game
|
||||
end
|
||||
end
|
||||
Settings.startNewAdventure(START_WAIT) --start/continue adventure
|
||||
end
|
||||
else
|
||||
if not running then
|
||||
Bridge.liveSplit()
|
||||
running = true
|
||||
end
|
||||
Settings.choosePlayerNames() --set names
|
||||
end
|
||||
else
|
||||
if RUNNING4NEWGAME then --remove last save game
|
||||
Settings.RemoveLastAdventure(START_WAIT)
|
||||
elseif RUNNING4CONTINUE then --continue the last adventure
|
||||
EXTERNALDONE = true
|
||||
InternalDone = true
|
||||
Settings.ContinueAdventure()
|
||||
else
|
||||
local battleState = Memory.value("game", "battle")
|
||||
Control.encounter(battleState)
|
||||
local curr_hp = Pokemon.index(0, "hp")
|
||||
-- if curr_hp ~= lastHP then
|
||||
-- Bridge.hp(curr_hp, Pokemon.index(0, "max_hp"))
|
||||
-- lastHP = curr_hp
|
||||
-- end
|
||||
if curr_hp == 0 and not Control.canDie() and Pokemon.index(0) > 0 then
|
||||
Strategies.death(currentMap)
|
||||
elseif Walk.strategy then
|
||||
if Strategies.execute(Walk.strategy) then
|
||||
Walk.traverse(currentMap)
|
||||
end
|
||||
elseif battleState > 0 then
|
||||
if not Control.shouldCatch(partySize) then
|
||||
Battle.automate()
|
||||
end
|
||||
elseif Textbox.handle() then
|
||||
Walk.traverse(currentMap)
|
||||
end
|
||||
end
|
||||
end
|
||||
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,203 @@
|
|||
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 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 = 0x131E
|
||||
|
||||
-- Data
|
||||
|
||||
function Inventory.indexOf(name)
|
||||
local searchID = items[name]
|
||||
for i=0,19 do
|
||||
local iidx = ITEM_BASE + i * 2
|
||||
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
|
||||
return Memory.raw(ITEM_BASE + index * 2 + 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.raw(0x131D) == 20
|
||||
end
|
||||
|
||||
function Inventory.use(item, poke, midfight)
|
||||
if midfight then
|
||||
local battleMenu = Memory.value("battle", "menu")
|
||||
if battleMenu == 94 then
|
||||
local rowSelected = Memory.value("menu", "row")
|
||||
if Menu.getCol() == 9 then
|
||||
if rowSelected == 0 then
|
||||
Input.press("Down")
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
else
|
||||
Input.press("Left")
|
||||
end
|
||||
elseif battleMenu == 233 then
|
||||
Menu.select(Inventory.indexOf(item), "accelerate", true)
|
||||
elseif Utils.onPokemonSelect(battleMenu) then
|
||||
if poke then
|
||||
if type(poke) == "string" then
|
||||
poke = Pokemon.indexOf(poke)
|
||||
end
|
||||
Menu.select(poke, true)
|
||||
else
|
||||
Input.press("A")
|
||||
end
|
||||
else
|
||||
Input.press("B")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local main = Memory.value("menu", "main")
|
||||
local column = Menu.getCol()
|
||||
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,307 @@
|
|||
local Pokemon = {}
|
||||
|
||||
local Bridge = require "util.bridge"
|
||||
local Input = require "util.input"
|
||||
local Memory = require "util.memory"
|
||||
local Menu = require "util.menu"
|
||||
|
||||
local pokeIDs = {
|
||||
rhydon = 1,
|
||||
kangaskhan = 2,
|
||||
nidoran = 3,
|
||||
spearow = 5,
|
||||
voltorb = 6,
|
||||
nidoking = 7,
|
||||
ivysaur = 9,
|
||||
gengar = 14,
|
||||
nidoranf = 15,
|
||||
nidoqueen = 16,
|
||||
cubone = 17,
|
||||
rhyhorn = 18,
|
||||
gyarados = 22,
|
||||
growlithe = 33,
|
||||
onix = 34,
|
||||
pidgey = 36,
|
||||
kadabra = 38,
|
||||
jinx = 72,
|
||||
meowth = 77,
|
||||
pikachu = 84,
|
||||
dragonair = 89,
|
||||
sandshrew = 96,
|
||||
zubat = 107,
|
||||
ekans = 108,
|
||||
paras = 109,
|
||||
weedle = 112,
|
||||
kakuna = 113,
|
||||
dewgong = 120,
|
||||
caterpie = 123,
|
||||
metapod = 124,
|
||||
hypno = 129,
|
||||
weezing = 143,
|
||||
abra = 148,
|
||||
alakazam = 149,
|
||||
pidgeotto = 150,
|
||||
pidgeot = 151,
|
||||
bulbasaur = 153,
|
||||
rattata = 165,
|
||||
raticate = 166,
|
||||
nidorino = 167,
|
||||
geodude = 169,
|
||||
squirtle = 177,
|
||||
oddish = 185,
|
||||
}
|
||||
|
||||
local moveList = {
|
||||
cut = 15,
|
||||
fly = 19,
|
||||
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,
|
||||
surf = 57,
|
||||
ice_beam = 58,
|
||||
bubblebeam = 61,
|
||||
strength = 70,
|
||||
leech_seed = 73,
|
||||
thunderbolt = 85,
|
||||
earthquake = 89,
|
||||
dig = 91,
|
||||
teleport = 100,
|
||||
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 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 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=1,4 do
|
||||
if mid == Memory.raw(0x101B + 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)
|
||||
return index(indexOf(name), offset)
|
||||
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("oddish", "paras", "spearow", "pidgey", "nidoran", "squirtle")
|
||||
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 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 pokeName = Pokemon.forMove(move)
|
||||
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,57 @@
|
|||
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, 14, currentMap..": "..px.." "..py)
|
||||
drawText(0, 0, elapsedTime())
|
||||
|
||||
if Memory.value("battle", "our_id") > 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(120, 7, hpStatus)
|
||||
end
|
||||
end
|
||||
|
||||
local nidx = Pokemon.indexOf("nidoran", "nidorino", "nidoking")
|
||||
if nidx ~= -1 then
|
||||
local att = Pokemon.index(nidx, "attack")
|
||||
local def = Pokemon.index(nidx, "defense")
|
||||
local spd = Pokemon.index(nidx, "speed")
|
||||
local scl = Pokemon.index(nidx, "special")
|
||||
drawText(100, 0, att.." "..def.." "..spd.." "..scl)
|
||||
end
|
||||
local enc = " encounter"
|
||||
if encounters ~= 1 then
|
||||
enc = enc.."s"
|
||||
end
|
||||
drawText(0, 116, Memory.value("battle", "critical"))
|
||||
drawText(0, 125, Memory.value("player", "repel"))
|
||||
drawText(0, 134, encounters..enc)
|
||||
return true
|
||||
end
|
||||
|
||||
function Paint.wildEncounters(count)
|
||||
encounters = count
|
||||
end
|
||||
|
||||
function Paint.reset()
|
||||
encounters = 0
|
||||
end
|
||||
|
||||
return Paint
|
|
@ -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,148 @@
|
|||
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 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 inputTable = {}
|
||||
if hold then
|
||||
inputTable = {[button]=true, B=true}
|
||||
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 hold then
|
||||
gui.text(0, 7, button.."+B")
|
||||
else
|
||||
if not newgame then
|
||||
gui.text(0, 7, button.." "..remainingFrames)
|
||||
else
|
||||
gui.text(0, 7, "Up+B+Select")
|
||||
end
|
||||
end
|
||||
end
|
||||
if ab then
|
||||
buttonbutton = "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)
|
||||
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, hold, newgame)
|
||||
end
|
||||
|
||||
function Input.cancel(accept)
|
||||
if accept and Memory.value("menu", "shop_current") == 20 then
|
||||
Input.press(accept)
|
||||
else
|
||||
local button
|
||||
if bCancel then
|
||||
button = "B"
|
||||
else
|
||||
button = "A"
|
||||
end
|
||||
remainingFrames = 0
|
||||
sendButton(button, true)
|
||||
bCancel = not bCancel
|
||||
end
|
||||
end
|
||||
|
||||
function Input.escape()
|
||||
local inputTable = {Right=true, Down=true}
|
||||
joypad.set(inputTable)
|
||||
bridgeButton("D,R")
|
||||
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
|
||||
|
||||
function Input.test(fn, completes)
|
||||
while true do
|
||||
if not Input.update() then
|
||||
if fn() and completes then
|
||||
break
|
||||
end
|
||||
end
|
||||
emu.frameadvance()
|
||||
end
|
||||
if completes then
|
||||
print(completes.." complete!")
|
||||
end
|
||||
end
|
||||
|
||||
return Input
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
local Memory = {}
|
||||
|
||||
local memoryNames = {
|
||||
setting = {
|
||||
text_speed = 0x0D3D,
|
||||
battle_animation = 0x0D3E,
|
||||
battle_style = 0x0D3F,
|
||||
yellow_bitmask = 0x1354,
|
||||
},
|
||||
menu = {
|
||||
settings_row = 0x0C24,
|
||||
column = 0x0C25,
|
||||
row = 0x0C26,
|
||||
current = 0x1FFC,
|
||||
main_current = 0x0C27,
|
||||
input_row = 0x0C2A,
|
||||
size = 0x0C28,
|
||||
pokemon = 0x0C51,
|
||||
shop_current = 0x0C52,
|
||||
transaction_current = 0x0F8B,
|
||||
selection = 0x0C30,
|
||||
selection_mode = 0x0C35,
|
||||
scroll_offset = 0x0C36,
|
||||
text_input = 0x04B6,
|
||||
text_length = 0x0EE9,
|
||||
main = 0x1FF5,
|
||||
},
|
||||
player = {
|
||||
name = 0x1158,
|
||||
name2 = 0x1159,
|
||||
moving = 0x1528,
|
||||
x = 0x1362,
|
||||
y = 0x1361,
|
||||
facing = 0x152A,
|
||||
repel = 0x10DB,
|
||||
party_size = 0x1163,
|
||||
},
|
||||
game = {
|
||||
map = 0x135E,
|
||||
battle = 0x1057,
|
||||
textbox = 0x0FC4,
|
||||
},
|
||||
time = {
|
||||
hours = 0x1A41,
|
||||
minutes = 0x1A43,
|
||||
seconds = 0x1A44,
|
||||
frames = 0x1A45,
|
||||
},
|
||||
shop = {
|
||||
transaction_amount = 0x0F96,
|
||||
},
|
||||
progress = {
|
||||
trashcans = 0x1773,
|
||||
},
|
||||
pokemon = {
|
||||
exp1 = 0x1179,
|
||||
exp2 = 0x117A,
|
||||
exp3 = 0x117B,
|
||||
},
|
||||
battle = {
|
||||
attack_turns = 0x1067,
|
||||
text = 0x1125,
|
||||
menu = 0x0C50,
|
||||
accuracy = 0x0D1E,
|
||||
x_accuracy = 0x1063,
|
||||
disabled = 0x0CEE,
|
||||
paralyzed = 0x1018,
|
||||
|
||||
opponent_next_move = 0x0CDD,
|
||||
opponent_last_move = 0x0FCC,
|
||||
|
||||
critical = 0x105E,
|
||||
miss = 0x105F,
|
||||
our_turn = 0x1FF1,
|
||||
battle_turns = 0x0CD5,
|
||||
|
||||
opponent_bide = 0x106F,
|
||||
opponent_id = 0x0FE5,
|
||||
opponent_level = 0x0FF3,
|
||||
opponent_type1 = 0x0FEA,
|
||||
opponent_type2 = 0x0FEB,
|
||||
|
||||
our_id = 0x1014,
|
||||
our_status = 0x1018,
|
||||
our_level = 0x1022,
|
||||
our_type1 = 0x1019,
|
||||
our_type2 = 0x101A,
|
||||
},
|
||||
}
|
||||
|
||||
local doubleNames = {
|
||||
pokemon = {
|
||||
attack = 0x117E,
|
||||
defense = 0x1181,
|
||||
speed = 0x1183,
|
||||
special = 0x1185,
|
||||
},
|
||||
battle = {
|
||||
opponent_hp = 0x0FE6,
|
||||
opponent_max_hp = 0x0FF4,
|
||||
opponent_attack = 0x0FF6,
|
||||
opponent_defense = 0x0FF8,
|
||||
opponent_speed = 0x0FFA,
|
||||
opponent_special = 0x0FFC,
|
||||
|
||||
our_hp = 0x1015,
|
||||
our_max_hp = 0x1023,
|
||||
our_attack = 0x1025,
|
||||
our_defense = 0x1027,
|
||||
our_speed = 0x1029,
|
||||
our_special = 0x102B,
|
||||
},
|
||||
}
|
||||
|
||||
local yellow = YELLOW
|
||||
|
||||
local function raw(address, forYellow)
|
||||
if yellow and not forYellow and address > 0x0F12 and address < 0x1F00 then
|
||||
address = address - 1
|
||||
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, forYellow)
|
||||
local memoryAddress = memoryNames[section]
|
||||
if key then
|
||||
memoryAddress = memoryAddress[key]
|
||||
end
|
||||
return raw(memoryAddress, forYellow)
|
||||
end
|
||||
|
||||
return Memory
|
|
@ -0,0 +1,199 @@
|
|||
local Menu = {}
|
||||
|
||||
local Input = require "util.input"
|
||||
local Memory = require "util.memory"
|
||||
|
||||
local yellow = GAME_NAME == "yellow"
|
||||
|
||||
local sliding = false
|
||||
|
||||
Menu.pokemon = yellow and 51 or 103
|
||||
|
||||
-- Private functions
|
||||
|
||||
local function getRow(menuType, scrolls)
|
||||
if menuType and menuType == "settings" then
|
||||
menuType = menuType.."_row"
|
||||
else
|
||||
menuType = "row"
|
||||
end
|
||||
local row = Memory.value("menu", menuType)
|
||||
if scrolls then
|
||||
row = row + Memory.value("menu", "scroll_offset")
|
||||
end
|
||||
return row
|
||||
end
|
||||
|
||||
local function setRow(desired, throttle, scrolls, menuType, loop)
|
||||
local currentRow = getRow(menuType, scrolls)
|
||||
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
|
||||
menuType = menuType.."_current"
|
||||
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, false, menuType)
|
||||
return false
|
||||
end
|
||||
|
||||
function Menu.select(option, throttle, scrolls, menuType, dontPress, loop)
|
||||
if setRow(option, throttle, scrolls, menuType, loop) then
|
||||
local delay = 1
|
||||
if throttle 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 = current > desired == inverted
|
||||
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)
|
||||
return Menu.sidle(Menu.getCol(), desired)
|
||||
end
|
||||
|
||||
-- Options
|
||||
|
||||
function Menu.setOption(name, desired)
|
||||
if yellow then
|
||||
local rowFor = {
|
||||
text_speed = 0,
|
||||
battle_animation = 1,
|
||||
battle_style = 2
|
||||
}
|
||||
local currentRow = Memory.raw(0x0D3D, true)
|
||||
if Menu.balance(currentRow, rowFor[name], true, false, true) then
|
||||
Input.press("Left")
|
||||
end
|
||||
else
|
||||
local rowFor = {
|
||||
text_speed = 3,
|
||||
battle_animation = 8,
|
||||
battle_style = 13
|
||||
}
|
||||
if Memory.value("setting", name) == desired then
|
||||
return true
|
||||
end
|
||||
if setRow(rowFor[name], true, false, "settings") then
|
||||
Menu.setCol(desired)
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Pause menu
|
||||
|
||||
function Menu.isOpen()
|
||||
return Memory.value("game", "textbox") == 1 or Memory.value("menu", "current") == 24
|
||||
end
|
||||
|
||||
function Menu.close()
|
||||
if Memory.value("game", "textbox") == 0 and Memory.value("menu", "main") < 8 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
|
||||
Input.cancel()
|
||||
else
|
||||
local main = Memory.value("menu", "main")
|
||||
if main > 2 and main ~= 64 then
|
||||
return true
|
||||
end
|
||||
Input.press("B")
|
||||
end
|
||||
else
|
||||
Input.press("Start", 2)
|
||||
end
|
||||
end
|
||||
|
||||
return Menu
|
|
@ -0,0 +1,60 @@
|
|||
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, 14, currentMap..": "..px.." "..py)
|
||||
drawText(0, 0, elapsedTime())
|
||||
|
||||
if Memory.value("battle", "our_id") > 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(120, 7, hpStatus)
|
||||
end
|
||||
end
|
||||
|
||||
local bidx = Pokemon.indexOf("bulbasaur")
|
||||
local pidx = Pokemon.indexOf("pidgey")
|
||||
if bidx ~= -1 then
|
||||
local scl = Pokemon.index(bidx, "special")
|
||||
local PP1 = Memory.raw(0xD02D)
|
||||
local PP2 = Memory.raw(0xD02E)
|
||||
local PP3 = Memory.raw(0xD02F)
|
||||
drawText(0, 134, scl.."scl "..PP1.."/"..PP2.."/"..PP3)
|
||||
end
|
||||
if pidx ~= -1 then
|
||||
local hp = Pokemon.index(pidx, "hp")
|
||||
drawText(100, 134, hp.."HP")
|
||||
end
|
||||
local enc = " encounter"
|
||||
if encounters ~= 1 or encounters ~= 0 then
|
||||
enc = enc.."s"
|
||||
end
|
||||
drawText(0, 125, encounters..enc)
|
||||
return true
|
||||
end
|
||||
|
||||
function Paint.wildEncounters(count)
|
||||
encounters = count
|
||||
end
|
||||
|
||||
function Paint.reset()
|
||||
encounters = 0
|
||||
end
|
||||
|
||||
return Paint
|
|
@ -0,0 +1,46 @@
|
|||
local Player = {}
|
||||
|
||||
local Textbox = require "action.textbox"
|
||||
|
||||
local Input = require "util.input"
|
||||
local Memory = require "util.memory"
|
||||
|
||||
local yellow = YELLOW
|
||||
local facingDirections = {Up=8, Right=1, Left=2, Down=4}
|
||||
|
||||
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)
|
||||
if Player.face(direction) then
|
||||
Input.press("A", yellow and 3 or 2)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function Player.disinteract(direction)
|
||||
if Player.face(direction) then
|
||||
Input.press("B", yellow and 3 or 2)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function Player.isMoving()
|
||||
return Memory.value("player", "moving") ~= 0
|
||||
end
|
||||
|
||||
function Player.position()
|
||||
return Memory.value("player", "x"), Memory.value("player", "y")
|
||||
end
|
||||
|
||||
return Player
|
|
@ -0,0 +1,145 @@
|
|||
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 START_WAIT = 99
|
||||
|
||||
local yellow = YELLOW
|
||||
local tempDir
|
||||
|
||||
local settings_menu
|
||||
if yellow then
|
||||
settings_menu = 93
|
||||
else
|
||||
settings_menu = 94
|
||||
end
|
||||
|
||||
local desired = {}
|
||||
if yellow then
|
||||
desired.text_speed = 1
|
||||
desired.battle_animation = 128
|
||||
desired.battle_style = 64
|
||||
else
|
||||
desired.text_speed = 1
|
||||
desired.battle_animation = 10
|
||||
desired.battle_style = 10
|
||||
end
|
||||
|
||||
local function isEnabled(name)
|
||||
if yellow then
|
||||
local matching = {
|
||||
text_speed = 0xF,
|
||||
battle_animation = 128,
|
||||
battle_style = 64
|
||||
}
|
||||
local settingMask = Memory.value("setting", "yellow_bitmask", true)
|
||||
return bit.band(settingMask, matching[name]) == desired[name]
|
||||
else
|
||||
return Memory.value("setting", name) == desired[name]
|
||||
end
|
||||
end
|
||||
|
||||
-- PUBLIC
|
||||
|
||||
function Settings.set(...)
|
||||
for i,name in ipairs(arg) do
|
||||
if not isEnabled(name) then
|
||||
if Menu.open(settings_menu, 1) then
|
||||
Menu.setOption(name, desired[name])
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
return Menu.cancel(settings_menu)
|
||||
end
|
||||
|
||||
function Settings.startNewAdventure(startWait)
|
||||
local startMenu, withBattleStyle
|
||||
withBattleStyle = "battle_style"
|
||||
if yellow then
|
||||
startMenu = Memory.raw(0x0F95) == 0
|
||||
else
|
||||
startMenu = Memory.value("player", "name") ~= 0
|
||||
end
|
||||
if startMenu and Menu.getCol() ~= 0 then
|
||||
if Settings.set("text_speed", "battle_animation", withBattleStyle) then
|
||||
Menu.select(0)
|
||||
end
|
||||
elseif math.random(0, startWait) == 0 then
|
||||
Input.press("Start")
|
||||
end
|
||||
end
|
||||
|
||||
function Settings.RemoveLastAdventure(startWait)
|
||||
if not tempDir then
|
||||
if Memory.value("menu", "size") ~= 2 and math.random(0, startWait) == 0 then
|
||||
Input.press("Start")
|
||||
elseif Memory.value("menu", "size") == 2 then
|
||||
Input.press("B")
|
||||
tempDir = true
|
||||
end
|
||||
else
|
||||
if Utils.ingame() then
|
||||
if Memory.value("menu", "pokemon") ~= 0 then
|
||||
Input.press("B")
|
||||
elseif Memory.value("menu", "pokemon") == 0 then
|
||||
if Memory.value("menu", "size") == 2 then
|
||||
Input.press("", 0, false, true)
|
||||
else
|
||||
if Memory.value("menu", "row") == 1 then
|
||||
Input.press("A")
|
||||
else
|
||||
Input.press("Down")
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
tempDir = false
|
||||
RUNNING4NEWGAME = false --stop the function after removed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Settings.ContinueAdventure()
|
||||
local current = Memory.value("menu", "current")
|
||||
local row = Memory.value("menu", "row")
|
||||
if row == 0 then
|
||||
if current == 32 then
|
||||
RUNNING4CONTINUE = false --stop ContinueAdventure
|
||||
elseif current ~= 55 then
|
||||
Input.press("A")
|
||||
end
|
||||
else
|
||||
Input.press("Up")
|
||||
end
|
||||
end
|
||||
|
||||
function Settings.choosePlayerNames()
|
||||
local name = PLAYER_NAME
|
||||
if dirText ~= "glitch" then
|
||||
if (Memory.value("player", "name") ~= 141) or (Memory.value("player", "name2") ~= 136) then
|
||||
name = RIVAL_NAME
|
||||
end
|
||||
else
|
||||
if (Memory.value("player", "name") ~= 141) or (Memory.value("player", "name2") ~= 136) then
|
||||
name = "> "
|
||||
end
|
||||
end
|
||||
Textbox.name(name, true)
|
||||
end
|
||||
|
||||
function Settings.pollForResponse()
|
||||
local response = Bridge.process()
|
||||
if response then
|
||||
Bridge.polling = false
|
||||
Textbox.setName(tonumber(response))
|
||||
end
|
||||
end
|
||||
|
||||
return Settings
|
|
@ -0,0 +1,125 @@
|
|||
local Utils = {}
|
||||
|
||||
local Memory = require "util.memory"
|
||||
|
||||
local EMP = 1
|
||||
|
||||
local yellow = YELLOW
|
||||
|
||||
-- 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.raw(0x020E) > 0
|
||||
end
|
||||
|
||||
function Utils.onPokemonSelect(battleMenu)
|
||||
if yellow then
|
||||
return battleMenu == 27 or battleMenu == 243
|
||||
end
|
||||
return battleMenu == 8 or battleMenu == 48 or battleMenu == 184 or battleMenu == 224
|
||||
end
|
||||
|
||||
function Utils.drawText(x, y, message)
|
||||
gui.text(x * EMP, y * EMP, message)
|
||||
end
|
||||
|
||||
-- TIME
|
||||
|
||||
function Utils.igt()
|
||||
local hours = Memory.value("time", "hours")
|
||||
local mins = Memory.value("time", "minutes")
|
||||
local secs = Memory.value("time", "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()
|
||||
local secs = Memory.value("time", "seconds")
|
||||
local mins = Memory.value("time", "minutes")
|
||||
local hours = Memory.value("time", "hours")
|
||||
return hours..":"..clockSegment(mins)..":"..clockSegment(secs)
|
||||
end
|
||||
|
||||
function Utils.frames()
|
||||
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