launch this on at least 1 frame before that the dungeon seed (0x02115414) gets updated
--NDS Pokemon Mystery Dungeon: Blue Rescue Team - dungeon bruteforce v1.2 by ThunderAxe31
--launch this on at least 1 frame before that the dungeon seed (0x02115414) gets updated.
local floors = 5 --amount of floors we want to bruteforce... probably later will automatically make it set the right value
local start = 1 --starting amount of RNG advancements before loading the dungeon. lowest value allowed is 0
local iter =1000 --amount of seeds we want to test, starting from the value above
local addr_global_rng = 0x0E9FC0
local addr_dungeon_rng = 0x115414
local addr_floor_rng = 0x1C2790
local addr_floor = 0x1153E5
local addr_fade_in = 0x1C284C
local addr_player_x = 0x126360
local addr_player_y = 0x126362
local addr_tiles_start = 0x118260
local addr_warp = 0x114DAA
local off_stairs = 1
local off_item = 16
local off_tile = 20
local dun_w = 56
local dun_h = 32
local waiting = 0
local bad_timing = false
local file_log = io.open("log.txt", "a")
function log_update(text)
file_log:write(text .. "\n")
file_log:flush()
console.log(text)
end
local function rng_adv(val, iter)
for i=1, iter do
local high = (val * 0x5D58) % 0x10000
local low = (val * 0x8B65) % 0x100000000
val = (low + high * 0x10000) % 0x100000000 +1
local high = (val * 0x5D58) % 0x10000
local low = (val * 0x8B65) % 0x100000000
val = (low + high * 0x10000) % 0x100000000 +1
end
return val
end
if memory.usememorydomain("Main RAM") then
client.unpause()
if memory.read_u8(addr_floor) ~= 0 then
log_update("ERROR: Dungeon generation already started. Please start the script before entering the dungeon.")
while true do
emu.frameadvance()
end
end
while memory.read_u32_le(addr_dungeon_rng) ~= 0 do --let's wait until we're close enough
emu.frameadvance()
end
local iter_state = memorysavestate.savecorestate() --we save before checking how long it takes to start generating
while memory.read_u8(addr_floor) ~= 1 do --this tells it's the frame it starts generating
waiting = waiting +1
emu.frameadvance()
end
if memory.read_u32_le(addr_dungeon_rng) ~= memory.read_u8(addr_floor_rng) then
bad_timing = true
end
memorysavestate.loadcorestate(iter_state)
for i=1, waiting-1 do --let's wait the same, but 1 frame less.
emu.frameadvance()
end
iter_state = memorysavestate.savecorestate() --now this is the exact frame from where we want to start!
for rng_advancements = start, iter +start do
memorysavestate.loadcorestate(iter_state)
local source_rng = memory.read_u32_le(addr_global_rng)
memory.write_u32_le(addr_global_rng, rng_adv(source_rng, rng_advancements))
source_rng = memory.read_u32_le(addr_global_rng) --we save it for diagnostic purposes
emu.frameadvance() --the dungeon seed will get generated in the next frame, based on the global RNG.
local dungeon_seed = memory.read_u32_le(addr_dungeon_rng) --we save it for diagnostic purposes
log_update("RNG Advancements: " .. rng_advancements .. " Global RNG: " .. string.format("%08X", source_rng) .. " Dungeon seed: " .. string.format("%08X", dungeon_seed))
local floor_state = 0
if bad_timing == false then
floor_state = memorysavestate.savecorestate() --now this is the exact frame from where we want to start!
end
local score = 0
for f=1, floors do
if bad_timing == false then
memorysavestate.loadcorestate(floor_state)
memory.write_u8(addr_floor, f)
memory.write_u32_le(addr_floor_rng, rng_adv(dungeon_seed, f-1))
end
while memory.read_u8(addr_fade_in) == 0 do
emu.frameadvance()
end
if bad_timing then
memory.write_u8(addr_warp, 1)
end
local player_x = memory.read_u16_le(addr_player_x)
local player_y = memory.read_u16_le(addr_player_y)
local stairs_x = -1
local stairs_y = -1
for y=2, dun_h-2 do
for x=2, dun_w-2 do
local stairs = memory.read_u8(addr_tiles_start +y*dun_w*off_tile +x*off_tile +off_stairs)
if stairs == 2 then
stairs_x = x
stairs_y = y
break
end
end
if stairs_x ~= -1 then
break
end
end
local distance = math.max(math.abs(player_x -stairs_x), math.abs(player_y -stairs_y))
log_update("Floor " .. f .. " distance is " .. distance .. " steps")
score = score +distance
if f == floors then
log_update("= Total distance: " .. score .. " steps")
break
end
while memory.read_u8(addr_fade_in) ~= 0 do
emu.frameadvance()
end
end
if bad_timing == false then
memorysavestate.removestate(floor_state)
end
end
memorysavestate.loadcorestate(iter_state)
client.pause()
end