重要のはダッシュの原点のX座標です。だが、問題があります。座標はpixelより細かくて、画面で区別出来ません。例えばX=100に立ってるMaximとX=100.5に立ってるMaximの表示が画面に全く同じです。
ダッシュする前は左に歩く必要ありますからダッシュの原点より歩く前の座標が便利と思います。
2フレーム間左押して、3フレーム目に右にダッシュすると成功出来る原点は:
| 91.75 | ~ | 92.5 |
| 96.25 | ~ | 97 |
| 100.75 | ~ | 101.5 |
| 105.25 | ~ | 106 |
| 109.75 | ~ | 110.5 |
| 114.25 | ~ | 115 |
(正確にいうと上記のは半開区間で右開です。)
歩く速度は2フレームで5 pixelだからX=97から始めると4フレーム間左押して5フレーム目にダッシュとかでも大丈夫です。
剣を振るうタイミングはホァイが出来るか出来ないかしか影響ありません。
RTAする時に座標は整数の部分しか分かりませんので2か4か6行目がいいと思います。(整数じゃない部分がなんとか出来るか英語のDiscordに聞きましたが返事がありません。)
崖からダッシュの原点の距離で空中なる座標が決まります。速度と加速はその時点まで固定されてるのでその座標は軌道決まります。
ダッシュの速度は1フレームで4.5 pixelだから上の座標は4.5 pixel離れています。(例えば96.25 - 91.75 = 4.5)
Robert Ordisさんのお陰でゲームの内部は簡単に弄り事できた。Twitterに参考になったスクリプトのリンクある。
BizHawk(mGBAコア)というエミュレータ使った。書いたLuaスクリプトは下にある。
function inputs(t)
local i = {}
i['A'] = false
i['B'] = false
i['Down'] = false
i['L'] = false
i['Left'] = false
i['Power'] = false
i['R'] = false
i['Right'] = false
i['Select'] = false
i['Start'] = false
i['Light Sensor'] = 0
i['Tilt X'] = 0
i['Tilt Y'] = 0
i['Tilt Z'] = 0
i['Up'] = false
for _,v in ipairs(t) do i[v] = true end
return i
end
function fromEighths(n)
return n << 13
end
function fromFloat(n)
return math.floor(n / 0.125 + 0.5)
end
function toFloat(n)
return (n >> 13) * 0.125
end
function toEighths(n)
return n >> 13
end
MemVar = {}
function MemVar:setup()
local mt = {
__index = function(t, k)
local vars = rawget(t, "vars")
if vars[k] then
return vars[k].read(vars[k].addr, vars[k].domain)
else
return self[k]
end
end,
__newindex = function(t, k, v)
local vars = rawget(t, "vars")
if vars[k] then
vars[k].write(vars[k].addr, v, vars[k].domain)
else
rawset(t, k, v)
end
end
}
local ret = setmetatable({}, mt)
rawset(ret, "vars", {})
return ret
end
function MemVar:vz()
return rawget(self, "vars")
end
function MemVar:reg(t)
local v = {}
v.addr = t.addr
v.domain = t.domain or "System Bus"
v.bits = t.bits or 16
v.signed = t.signed == nil and true or t.signed
func = (v.signed and "s" or "u") .. v.bits .. ((v.bits > 8) and "_le" or "")
v.read = memory["read_" .. func]
v.write = memory["write_" .. func]
local vars = rawget(self, "vars")
vars[t.name] = v
end
function dumppos()
print("x = " .. v.xPos + toFloat(v.xPosFrac) + v.xCam .. " y = " .. v.yPos + toFloat(v.yPosFrac) + v.yCam)
end
v = MemVar:setup()
--v:reg({name="hp", addr=0x0201854e})
v:reg({name="xPos", addr=0x2000462})
v:reg({name="xPosFrac", addr=0x02000460, signed=false})
v:reg({name="yPos", addr=0x02000466})
v:reg({name="yPosFrac", addr=0x02000464, signed=false})
v:reg({name="xAcc", addr=0x02000470})
v:reg({name="yAcc", addr=0x02000474})
v:reg({name="pushRight", addr=0x03001A24})
v:reg({name="xCam", addr=0x0200A446})
v:reg({name="yCam", addr=0x0200A44A})
v:reg({name="xVel", addr=0x0200046A})
v:reg({name="xVelFrac", addr=0x02000468, signed=false})
v:reg({name="yVel", addr=0x0200046E})
v:reg({name="yVelFrac", addr=0x0200046C, signed=false})
require("byakuyahelpers")
for x=88, 116 do
for frac=0, 7 do
savestate.loadslot(1)
v.xPos = x
v.xPosFrac = fromEighths(frac)
emu.frameadvance()
joypad.set(inputs({"Left"}))
emu.frameadvance()
joypad.set(inputs({"Left"}))
emu.frameadvance()
joypad.set(inputs({"R"}))
emu.frameadvance()
while v.yAcc == 0 do emu.frameadvance() end
joypad.set(inputs({"B"}))
while v.yPos + v.yCam > 214 and v.yPos + v.yCam < 240 do emu.frameadvance() end
if v.yPos + v.yCam < 214 then
print("PASS " .. x + frac * 0.125)
end
end
end
require("byakuyahelpers")
function fa(n, i)
for _=1, n do
if i then joypad.set(i) end
emu.frameadvance()
end
end
for x=88,116 do
savestate.loadslot(1)
v.xPos = x
v.xPosFrac = 0
emu.frameadvance()
joypad.set(inputs({"Left"}))
fa(10)
client.screenshot(string.format("%d left.png", x))
fa(10, inputs({"Down"}))
client.screenshot(string.format("%d left crouch.png", x))
joypad.set(inputs({"Right"}))
fa(10)
client.screenshot(string.format("%d right.png", x))
joypad.set(inputs({"Down"}))
fa(10, inputs({"Down"}))
client.screenshot(string.format("%d right crouch.png", x))
end