Script to AVI record battle animations when playing a movie file for Fire Emblem 12.
It may desync if any dialog is triggered during enemy phase (i.e. the enemy phase isn't skipped).
local INP = {}
local function NFR()
joypad.setfrommnemonicstr(INP[CFR])
CFR = CFR + 1
emu.frameadvance()
end
local function MR(addr)
return memory.read_u32_le(addr, "Main RAM")
end
local BATTLE = {
0x2F3120, 0x2B2B48, 0x278224, 0x278224, 0x278224, 0x2F52EC, 0x2B2B70, 0x278224, --P1 P8
0x2FDFDC, 0x2FB640, 0x2F9E54, 0x2B2B78, 0x2FBF58, 0x2F9A48, 0x2FBA4C, 0x2F50D8, --C1 C6x
0x2FCB5C, 0x2FE1DC, 0x2F53AC, 0x2FB510, 0x2B2B48, 0x2B2B48, 0x2F00C0, 0x2B2B48, 0x2B2B48, --C7 C13x
0x2F08D4, 0x2F688C, 0x2B2BD8, 0x2B2B48, 0x2FC418, 0x2B2B48, 0x304DC0, 0x2FD5AC, 0x278380, --C14 C20x
0x2B2B48, 0x2B2B48, 0x2B2B48, 0x2F7C5C --C21 C24
}
local EXP = {
0x2F352C, 0x2F3CEC, 0x2F48A0, 0x2F5848, 0x2F6E58, 0x2F56F8, 0x2F6408, 0x2FA73C, --P1 P8
0x2FE3E8, 0x2FBA4C, 0x2FA260, 0x2F6FEC, 0x2FC3DC, 0x2F9E54, 0x2FBE58, 0x2F54E4, --C1 C6x
0x2FCF68, 0x2FE82C, 0x2F57B8, 0x2FB91C, 0x2F69A4, 0x2EAC04, 0x2F04CC, 0x2EE28C, 0x2F59BC, --C7 C13x
0x2F0D08, 0x2F6CC0, 0x2FDF58, 0x2F5184, 0x2FC824, 0x2F9784, 0x3053E4, 0x2FD9B8, 0x2FA474, --C14 C20x
0x2F0780, 0x2EF26C, 0x2EE24C, 0x2F8068 --C21 C24
}
-- print(BATTLE[1])
-- print(memory.read_u8(BATTLE[1]))
local MOD4 = 0
local RNG4 = 0
local WAIT4 = 0
local RNG = 0
local RNG_EP = {}
local RNG_FR = {}
local IND = 0
local rngbase=0x1BC09C
local ANIM = 0
local CHID = 1
local INVENTORY = {}
local INVENTORY_FR = 1
while true do
if movie.isloaded()==false then break end
MLE = movie.length()
for i=1, MLE do
INP[i] = movie.getinputasmnemonic(i)
end
movie.stop()
CFR = emu.framecount() --Current movie frame
local PHASE = MR(0x1140BC)
while PHASE~=0xB0A5B0A5 and PHASE~=0xB0A9B0A9 and PHASE~=0xB4A7B4A8 and CFR<MLE do
NFR()
PHASE = MR(0x1140BC)
end
while true do
if PHASE==0xB4A7B4A8 then --End of chapter
while PHASE~=0xB0A5B0A5 and emu.framecount()<211705 do
NFR()
PHASE = MR(0x1140BC)
end
end
if PHASE==0xB0A5B0A5 then --Player phase
while PHASE~=0xB0A9B0A9 and PHASE~=0xB4A7B4A8 do
NFR()
ANIM = 0
CHID = memory.read_u8(0x2B6FDB, "Main RAM") + 1
if MR(BATTLE[CHID])>0 then
ANIM = 1
end
PHASE = MR(0x1140BC)
if ANIM==1 then
savestate.save("FE12_ANIM")
--Animation ON
memory.write_u8(0x2B6E0E, 1, "Main RAM")
while MR(BATTLE[CHID])>0 and PHASE~=0xB4A7B4A8 do
joypad.set({Down=true, A=true})
emu.frameadvance()
CHID = memory.read_u8(0x2B6FDB, "Main RAM") + 1
PHASE = MR(0x1140BC)
end
if PHASE~=0xB4A7B4A8 then
for i=1, 5 do
emu.frameadvance()
end
end
--End animation ON
--Animation OFF
client.pause_av()
savestate.load("FE12_ANIM")
EP = memory.read_u8(0x272BCC, "Main RAM")
while MR(BATTLE[CHID])>0 and PHASE~=0xB4A7B4A8 do
NFR()
CHID = memory.read_u8(0x2B6FDB, "Main RAM") + 1
PHASE = MR(0x1140BC)
end
if PHASE~=0xB4A7B4A8 then
for i=1, 5 do
NFR()
end
end
client.unpause_av()
--End animation OFF
end
end
end --End player phase
if PHASE==0xB0A9B0A9 then --Enemy phase
client.pause_av()
savestate.save("FE12_ANIM")
RNG_EP = {MR(rngbase)}
RNG_FR = {emu.framecount()}
INVENTORY = {}
INVENTORY_FR = 1
while PHASE~=0xB0A5B0A5 and PHASE~=0xB4A7B4A8 do
if MR(0x112FB0)>0 then --Inventory full during EP
INVENTORY[#INVENTORY + 1] = INP[CFR]
end
NFR()
RNG = MR(rngbase)
if RNG ~= RNG_EP[#RNG_EP] then
RNG_EP[#RNG_EP + 1] = RNG
RNG_FR[#RNG_FR + 1] = emu.framecount()
end
CHID = memory.read_u8(0x2B6FDB, "Main RAM") + 1
PHASE = MR(0x1140BC)
end
if PHASE==0xB0A5B0A5 then
for i=1, 55 do
NFR()
end
end
-- client.pause_av()
-- print(RNG_EP)
savestate.save("FE12_EP")
savestate.load("FE12_ANIM")
PHASE = MR(0x1140BC)
memory.write_u8(0x2B6E0E, 1, "Main RAM")
client.unpause_av()
while PHASE~=0xB0A5B0A5 and PHASE~=0xB4A7B4A8 do
joypad.set({Down=true, A=true})
if MR(0x112FB0)>0 then --Inventory full during EP
joypad.setfrommnemonicstr("| 0, 150, 0, 0,................|")
emu.frameadvance()
joypad.setfrommnemonicstr(INVENTORY[INVENTORY_FR])
INVENTORY_FR = INVENTORY_FR + 1
end
emu.frameadvance()
CHID = memory.read_u8(0x2B6FDB, "Main RAM") + 1
PHASE = MR(0x1140BC)
if MR(BATTLE[CHID])>0 then --Battle tab
RNG = memory.read_bytes_as_array(rngbase, 16, "Main RAM")
while MR(BATTLE[CHID])>0 do
joypad.set({Down=true, A=true})
emu.frameadvance()
end
memory.write_bytes_as_array(rngbase, RNG, "Main RAM")
end
if MR(EXP[CHID])>0 then --Exp tab
-- if memory.read_u8(EXP[CHID], "Main RAM")>0 then --Exp tab
for i=1, 3 do
emu.frameadvance()
end
savestate.save("FE12_MOD4")
joypad.set({Start=true})
emu.frameadvance()
RNG = MR(rngbase)
for i=1, 4 do
emu.frameadvance()
end
if MR(rngbase) ~= RNG then --Check if Level-up or not
client.pause_av()
for i = 1, #RNG_EP do
if RNG_EP[i]==RNG then
-- MOD4 = RNG_FR[i] % 4
RNG4 = RNG_EP[i+1]
break
end
end
-- savestate.load("FE12_MOD4")
-- MOD4 = (MOD4 + emu.framecount() - 1) % 4
-- if MOD4>0 then
-- for i = 1, MOD4 do
-- emu.frameadvance()
-- end
-- end
WAIT4 = 0
-- print(RNG4)
for i = 0, 5 do
savestate.load("FE12_MOD4")
if i>0 then
for j=1, i do
emu.frameadvance()
end
end
joypad.set({Start=true})
for j = 1, 5 do
emu.frameadvance()
end
-- print(MR(rngbase))
if MR(rngbase) == RNG4 then
WAIT4 = i
break
end
end
savestate.load("FE12_MOD4")
if WAIT4>0 then
for j=1, WAIT4 do
emu.frameadvance()
end
end
joypad.set({Start=true})
emu.frameadvance()
for i=1, 4 do
emu.frameadvance()
end
client.unpause_av()
-- for i = 1, 330 do --TODO: better approximation
for i = 1, 120 do
emu.frameadvance()
end
while MR(0x112F38)>0 do
joypad.set({A=true})
emu.frameadvance()
joypad.set({A=false})
emu.frameadvance()
end
joypad.set({Start=true})
emu.frameadvance()
end
end
end
if PHASE==0xB0A5B0A5 then
for i=1, 55 do
emu.frameadvance()
end
end
savestate.load("FE12_EP")
end --End enemy phase
if CFR>=MLE then break end
end
break
end
for i=1, 700 do
emu.frameadvance()
end
client.pause()