Wow, nice find! So somebody already discovered that glitch a year ago and did some analysis on it. And now 4 different attacks have been reported to cause the glitch, so it probably works with anything that makes ProtoMan flinch. We just need to find the right moment in his attack pattern then. I'm not sure Shotoman really understood the differences in ProtoMan's attacks; whether he takes a wide swing or a long swing depends on where MegaMan is in relation to him, just as with the Swordy viruses. Charging up lets ProtoMan teleport directly in front of MegaMan instead of just to his own front column, and he'll do so up to three times if MegaMan dodges his sword. But sometimes he'll also attempt do his regular, front-column attack three times in a row, without even teleporting to the back again between tries, only stopping when MegaMan's been hit or ProtoMan's missed three times. So if you got hit by the first swipe of that attack, you couldn't tell it apart from the regular attack, I think.
As for BombMan, I was probably just going to shoot him a few times at the very beginning to get the 20 points or so in, as it takes a second for the bombs to get set up anyway. Then I may not even need the Charge attribute at all, depending on what I use on ElecMan. So I think the only annoying thing would be manipulating the 280 damage to happen.
And you're right that several of the bosses will only require TriSpear + GutsShoot, and in MagicMan's case maybe a HiCannon for a finisher. Other weaker bosses can be taken out faster with a row of Swords. I recall that even IceMan can be finished more quickly with 5 swords and then just shooting him 20 times to take off the remaining 100 HP than with waiting for GutsShoot to form, so it probably doesn't help to gamble for electric chips to use on him either.
The thing about ElecMan is that you're thrown into ProtoMan's battle immediately afterward with no time to re-arrange the folder, so unless you want to try to wait for the chips you need to randomly swap themselves into place, you'll have to set up the chips for ProtoMan's battle before ElecMan's main battle. And unless the game just happens to pick the same folder slots for the first 5 chips then, you won't be able to use the same chips in both battles. So my plan was to use GutsShoot on ProtoMan, since his battle would be very slow with all that shielding, and find something else to use on ElecMan. But if you can figure out that multiple hit glitch on ProtoMan, we may be able to use Quake3 to finish him off fairly quickly (likely starting with a MiniBomb so he doesn't have to flinch again), which would free up TriSpear + GutsShoot for ElecMan.
ElecMan's first fight is the one where you have to hit him for at least 50 HP 3 times, and I found that ShokWave + MiniBomb + MiniBomb was the fastest way to do that out of what I had, because it's slower to make ElecMan flinch, and it's slower to start off with an attack as slow as MiniBomb that lets him start to move to another square. So that would be one of the drawbacks to getting ShokWave P next to the area 3 vendor later instead of the ShokWave L early on. HiCannon, Dash, and TriSpear would work just as well I believe, but we'll want at least the Dash for GutsShoot later, and I think setting up the folder for 3 battles in a row would be the most efficient when there's hardly any time in between the two forms of ElecMan anyway.
Do you remember the viruses you fight after when using the Hig Memo to get into Area 5 (the Undernet)? That's another battle where the DynaWave + Quake3 + AquaTowr strategy
really helps. GutsShoot does bypass the shield, as it does with most objects belonging to the enemy, but that's a very inefficient way to beat something with 250 HP. So it's quite valuable to have Quake3 C and DynaWave C, but I hate the time sink required in jacking into Miyu's vase and then trying to get a perfect battle against a blue Mettool + one, and that's why I'm hoping they'll show up quickly enough in the chip trader.
Hmm, what else was I gonna say... KirkQ said I could just post Lua scripts with code tags, so here are a few that we made:
local AD1 = 0x020003f4 -- good
local AD3 = 0x02006448 -- good
local AD1Value
local AD3Value
AD1Value = 7
AD3Value = 7
while true do
memory.writebyte(AD1, AD1Value)
memory.writebyte(AD3, AD3Value)
vba.frameadvance();
end
Here's a simple one. It's just a cheat that prevents you from ever getting into any random encounter battles. Now you can roam the cyberworld without fear! Keep in mind that it doesn't affect non-random battles, so stay away from boss triggers until you're ready. And be careful not to leave a cheat like this on when you open another ROM, because there's no telling what might happen!
local tempstate = {}
local iterations
local value
local i
local j
local keys
local ChipID = 0x02019009
local ChipCode = 0x0201900a
local ChipIDValue
local ChipCodeValue
moviefile = "MemDump.vbm"
-- output file. contains ingame frame, scroll, position and hitbox information
dumpfile = moviefile..".dump"
io.output(dumpfile)
value = 0
tempstate[value] = savestate.create()
savestate.save(tempstate[value])
--iterations = 32768
iterations = 2000
for j = 1,iterations do
vba.frameadvance()
savestate.save(tempstate[value])
joypad.set(1,{["A"]=true})
for i=1,60 do
vba.frameadvance()
end
joypad.set(1,{["A"]=true})
vba.frameadvance()
vba.frameadvance()
vba.frameadvance()
joypad.set(1,{["A"]=true})
vba.frameadvance()
vba.frameadvance()
vba.frameadvance()
--Insert 7 more here for special
--joypad.set(1,{["A"]=true})
--for i=1,3 do
--vba.frameadvance()
--end
--------------------------
joypad.set(1,{["A"]=true})
for i=1,41 do
vba.frameadvance()
end
joypad.set(1,{["B"]=true})
for i=1,13 do
vba.frameadvance()
end
joypad.set(1,{["A"]=true})
for i=1,41 do
vba.frameadvance()
end
joypad.set(1,{["B"]=true})
for i=1,8 do
vba.frameadvance()
end
joypad.set(1,{["A"]=true})
for i=1,9 do
vba.frameadvance()
end
joypad.set(1,{["B"]=true})
for i=1,55 do
vba.frameadvance()
end
joypad.set(1,{["A"]=true})
for i=1,9 do
vba.frameadvance()
end
joypad.set(1,{["B"]=true})
for i=1,15 do
vba.frameadvance()
end
-- joypad.set(1,{["B"]=true})
-- for i=1,25 do
-- vba.frameadvance()
-- end
-- joypad.set(1,{["start"]=true})
-- for i=1,20 do
-- vba.frameadvance()
-- end
joypad.set(1,{["A"]=true})
-- for i=1,30 do
for i=1,44 do
vba.frameadvance()
gui.text(0,0,"ID: " .. memory.readbyte(ChipID))
gui.text(0,10,"Code: " .. memory.readbyte(ChipCode))
end
ChipIDValue = memory.readbyte(ChipID)
ChipCodeValue = memory.readbyte(ChipCode)
io.write(ChipIDValue, "\n")
io.write(ChipCodeValue, "\n")
savestate.load(tempstate[value])
end
An old classic from KirkQ, which I modified a bit to streamline the timing. I learned most of what I know about Lua by studying this. This is the script that retries the chip trading machine on each successive frame and records what you would have gotten. To run this, you need to be in the dialog box that asks whether you would like to trade, because the first thing this does it choose Yes.
In the output file, each odd-numbered line contains the chip's ID as seen in the library, and the line immediately following contains the chip's letter code, where 0 through 25 correspond to A through Z. Some of that commented-out code was in case you had fewer than 5 chips left, so it couldn't start to trade again to see what was at the top of the folder. You can also make a variation of this to use the 10-chip trader, as Kirk's comment shows. You may have noticed I let the script wait a couple more frames than necessary for each action, but that was because I don't want it to fail when a bit of random lag sets in. Accessing the Folder takes longer the more kinds of chips you have. Oh, and that it outputs to the screen at the end isn't really necessary, but it shows that it's working and doesn't harm anything.
local tempstate = {}
local iterations
local value
local i
local j
local addressvalue
local AD1 = 0x02004910
local AD2 = 0x02004911
local AD3 = 0x02004912
local AD4 = 0x02004913
local AD5 = 0x02004914
local AD6 = 0x02004915
local AD7 = 0x02004916
local AD8 = 0x02004917
local AD9 = 0x02004918
local AD10 = 0x02004919
local AD11 = 0x0200491A
local AD12 = 0x0200491B
local AD13 = 0x0200491C
local AD14 = 0x0200491D
local AD15 = 0x0200491E
local AD16 = 0x0200491F
local AD17 = 0x02004920
local AD18 = 0x02004921
local AD19 = 0x02004922
local AD20 = 0x02004923
local AD21 = 0x02004924
local AD22 = 0x02004925
local AD23 = 0x02004926
local AD24 = 0x02004927
local AD25 = 0x02004928
local AD26 = 0x02004929
local AD27 = 0x0200492A
local AD28 = 0x0200492B
local AD29 = 0x0200492C
local AD30 = 0x0200492D
moviefile = "BattleMemDump.vbm"
dumpfile = moviefile..".dump"
io.output(dumpfile)
value = 1
tempstate[value] = savestate.create()
savestate.save(tempstate[value])
iterations = 1000
for j = 1,iterations do
vba.frameadvance()
savestate.save(tempstate[value])
joypad.set(1,{["left"]=true})
vba.frameadvance()
joypad.set(1,{["left"]=true})
vba.frameadvance()
for i=1,75 do
vba.frameadvance()
end
joypad.set(1,{["start"]=true})
for i=1,120 do
vba.frameadvance()
end
io.write(memory.readbyte(AD1)," ")
io.write(memory.readbyte(AD2)," ")
io.write(memory.readbyte(AD3)," ")
io.write(memory.readbyte(AD4)," ")
io.write(memory.readbyte(AD5)," ")
io.write(memory.readbyte(AD6)," ")
io.write(memory.readbyte(AD7)," ")
io.write(memory.readbyte(AD8)," ")
io.write(memory.readbyte(AD9)," ")
io.write(memory.readbyte(AD10)," ")
io.write(memory.readbyte(AD11)," ")
io.write(memory.readbyte(AD12)," ")
io.write(memory.readbyte(AD13)," ")
io.write(memory.readbyte(AD14)," ")
io.write(memory.readbyte(AD15)," ")
io.write(memory.readbyte(AD16)," ")
io.write(memory.readbyte(AD17)," ")
io.write(memory.readbyte(AD18)," ")
io.write(memory.readbyte(AD19)," ")
io.write(memory.readbyte(AD20)," ")
io.write(memory.readbyte(AD21)," ")
io.write(memory.readbyte(AD22)," ")
io.write(memory.readbyte(AD23)," ")
io.write(memory.readbyte(AD24)," ")
io.write(memory.readbyte(AD25)," ")
io.write(memory.readbyte(AD26)," ")
io.write(memory.readbyte(AD27)," ")
io.write(memory.readbyte(AD28)," ")
io.write(memory.readbyte(AD29)," ")
io.write(memory.readbyte(AD30)," ")
io.write("\n")
savestate.load(tempstate[value])
end
Here's a script Kirk made to retry a boss battle (such as FireMan, which you would have to be one pixel to the right of) many times and record the sequence of folder slots chosen to form the chip order in battle. Now that's what you'll need to optimize the final TAS, but if I'm just testing from the start of a battle, I use this script I made:
local tempstate = {}
local iterations
local value
local i
local j
local addressvalue
local AD1 = 0x02004910
local AD2 = 0x02004911
local AD3 = 0x02004912
local AD4 = 0x02004913
local AD5 = 0x02004914
local AD6 = 0x02004915
local AD7 = 0x02004916
local AD8 = 0x02004917
local AD9 = 0x02004918
local AD10 = 0x02004919
local AD11 = 0x0200491A
local AD12 = 0x0200491B
local AD13 = 0x0200491C
local AD14 = 0x0200491D
local AD15 = 0x0200491E
local AD16 = 0x0200491F
local AD17 = 0x02004920
local AD18 = 0x02004921
local AD19 = 0x02004922
local AD20 = 0x02004923
local AD21 = 0x02004924
local AD22 = 0x02004925
local AD23 = 0x02004926
local AD24 = 0x02004927
local AD25 = 0x02004928
local AD26 = 0x02004929
local AD27 = 0x0200492A
local AD28 = 0x0200492B
local AD29 = 0x0200492C
local AD30 = 0x0200492D
while true do
gui.text(0,0, memory.readbyte(AD1) .. " " .. memory.readbyte(AD2) .. " " .. memory.readbyte(AD3) .. " " .. memory.readbyte(AD4) .. " " .. memory.readbyte(AD5))
gui.text(0,10, memory.readbyte(AD6) .. " " .. memory.readbyte(AD7) .. " " .. memory.readbyte(AD8) .. " " .. memory.readbyte(AD9) .. " " .. memory.readbyte(AD10))
gui.text(0,20, memory.readbyte(AD11) .. " " .. memory.readbyte(AD12) .. " " .. memory.readbyte(AD13) .. " " .. memory.readbyte(AD14) .. " " .. memory.readbyte(AD15))
gui.text(0,30, memory.readbyte(AD16) .. " " .. memory.readbyte(AD17) .. " " .. memory.readbyte(AD18) .. " " .. memory.readbyte(AD19) .. " " .. memory.readbyte(AD20))
gui.text(0,40, memory.readbyte(AD21) .. " " .. memory.readbyte(AD22) .. " " .. memory.readbyte(AD23) .. " " .. memory.readbyte(AD24) .. " " .. memory.readbyte(AD25))
gui.text(0,50, memory.readbyte(AD26) .. " " .. memory.readbyte(AD27) .. " " .. memory.readbyte(AD28) .. " " .. memory.readbyte(AD29) .. " " .. memory.readbyte(AD30))
vba.frameadvance()
end
Okay, I'm not sure if any of those variables are necessary, as this started out as a commented-out version of KirkQ's script. Anyway, this just displays the order of chips in the latest battle in a clump in the corner of the screen. We don't yet know how to find this sequence
before a battle begins, but what you can do is save-state while viewing the folder, close out and enter the battle in an optimized way, and record the sequence you get; you'll probably only need the top row. Then you can reload that state and move the chips you want into those slots where 0 is top and 29 is bottom and it's 7 per page. You can take your time doing this, because the sequence doesn't change while viewing the folder. Then close out of the menu and enter the battle with the same timing as before, and you should have exactly what you need.
local tempstate = {}
local i
local j
dumpfile="places.dump"
io.output(dumpfile)
value = 0
tempstate[value] = savestate.create()
for j = 0,80000 do
savestate.save(tempstate[value])
for i=1,100 do
joypad.set(1,{["right"]=true,["up"]=true,["B"]=true})
vba.frameadvance()
end
io.write(j, ": ")
if(memory.readdword(0x020034CC) == 0x00BEFF0E) then
io.write(0)
end
if(memory.readdword(0x020034CC) == 0x0194FEB6) then
io.write(1)
end
if(memory.readdword(0x020034B8) == 0x001400A4) then
io.write(2)
end
if(memory.readdword(0x020034B8) == 0x011A00DC) then
io.write(3)
end
if(memory.readdword(0x020034B8) == 0xFF540110) then
io.write(4)
end
if(memory.readdword(0x020034B8) == 0xFE9E011C) then
io.write(5)
end
if(memory.readdword(0x020034CC) == 0xFEECFFA4) then
io.write(6)
end
if(memory.readdword(0x020034CC) == 0x01A8FFFC) then
io.write(7)
end
io.write(", ")
for i=1,200 do
joypad.set(1,{["right"]=true,["B"]=true})
vba.frameadvance()
end
if(memory.readdword(0x020034CC) == 0xFE74FF64) then
io.write(0)
end
if(memory.readdword(0x020034E0) == 0x00C8FF24) then
io.write(1)
end
if(memory.readdword(0x020034F4) == 0x0022018E) then
io.write(2)
end
if(memory.readdword(0x020034E0) == 0x0164FF8A) then
io.write(3)
end
if(memory.readdword(0x020034B8) == 0x00F0FEB8) then
io.write(4)
end
if(memory.readdword(0x020034B8) == 0x0158FDC6) then
io.write(5)
end
if(memory.readdword(0x020034B8) == 0xFF78FE54) then
io.write(6)
end
if(memory.readdword(0x020034F4) == 0x00F600DA) then
io.write(7)
end
if(memory.readdword(0x020034E0) == 0xFFEC00CC) then
io.write(8)
end
if(memory.readdword(0x020034E0) == 0x004CFFD0) then
io.write(9)
end
if(memory.readdword(0x020034F4) == 0xFFD80164) then
io.write("A")
end
if(memory.readdword(0x020034F4) == 0x00C400FA) then
io.write("B")
end
if(memory.readdword(0x020034B8) == 0x01DCFEF2) then
io.write("C")
end
if(memory.readdword(0x020034CC) == 0x0032FFA8) then
io.write("D")
end
if(memory.readdword(0x020034CC) == 0xFE3E0040) then
io.write("E")
end
if(memory.readdword(0x020034CC) == 0xFF9AFFF6) then
io.write("F")
end
io.write("\n")
savestate.load(tempstate[value])
vba.frameadvance()
end
This one I made on my own to test the random item locations in areas 1 and 2 in a similar way to the chip trade tester. It requires that you start out a little below and to the left of the portal from Dex's computer to the Internet (as in where you end up when you enter Dex's PC from the Net) to function fully, as the memory addresses correspond to the actual positions of sprites on the map, so the script needs to visit both areas to see where they are. Since both areas' random item locations are decided when you enter the Internet anywhere, it should be possible to find another place in memory that has all 6 locations so the script wouldn't have to run around, but I'm not very good at address-hunting.
Uh, and those numbers it outputs? That was a system I came up with to label each location. I ought to make a map of those soon so everyone can see what the output means.