fixed the bug that prevented for working on the second dungeon.
now also logs the floor generation speed, yay!
--NDS Pokemon Mystery Dungeon: Blue Rescue Team - dungeon bruteforce v1.3 by ThunderAxe31
--launch this on at least 1 frame before that the dungeon seed (0x02115414) gets updated.
local floors = 3 --amount of floors we want to bruteforce... probably later will automatically make it set the right value
local starting_floor = 1 --starting floor
local starting_adv = 0 --starting amount of RNG advancements before loading the dungeon. lowest value allowed is 0
local iter = 100000 --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 off_stairs = 1
local off_item = 16
local off_tile = 20
local dun_w = 56
local dun_h = 32
local waiting = 0
local current_floor = 0
local current_floor_rng = 0
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
local function change_floor()
memory.write_u8(addr_floor, current_floor)
end
local function change_floor_rng()
memory.write_u32_le(addr_floor_rng, rng_adv(memory.read_u32_le(addr_floor_rng), current_floor-1))
end
if not memory.usememorydomain("Main RAM") then
log_update("ERROR: Can't set Main RAM as default memory domain.")
while true do
emu.frameadvance()
end
end
if (memory.read_u8(addr_floor) ~= 0) and (memory.read_u8(addr_floor) ~= 255) then
log_update("ERROR: Dungeon generation already started. Please start the script before entering the dungeon.")
while true do
emu.frameadvance()
end
end
client.unpause()
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_u32_le(addr_dungeon_rng) == 0 do --this tells it's the frame it starts generating
waiting = waiting +1
emu.frameadvance()
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() --start of dungeon generation
event.on_bus_read(change_floor, 0x02000000 +addr_floor)
event.on_bus_read(change_floor_rng, 0x02000000 +addr_floor_rng)
for rng_advancements = starting_adv, iter +starting_adv -1 do
memorysavestate.loadcorestate(iter_state)
local source_rng = rng_adv(memory.read_u32_le(addr_global_rng), rng_advancements) --we also save it for diagnostic purposes
memory.write_u32_le(addr_global_rng, source_rng)
log_update("RNG Advancements: " .. rng_advancements .. " Global RNG: " .. string.format("%08X", source_rng))
local floor_state = memorysavestate.savecorestate() --start of floor generation
local steps = 0
local dungeon_frames = 0
for f=starting_floor, floors do
memorysavestate.loadcorestate(floor_state)
current_floor = f
local floor_frames = 0
while memory.read_u8(addr_fade_in) == 0 do
floor_frames = floor_frames +1 --count how many frames it takes to generate this floor
emu.frameadvance()
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 " .. string.format("%02u", f) .. " seed " .. string.format("%08X", memory.read_u32_le(addr_floor_rng)) .. " distance " .. string.format("%2u", distance) .. " steps loading time " .. string.format("%3u", floor_frames) )
steps = steps +distance
if distance == 0 then
distance = 4 --having the stairs directly under your feets is actually slower due to menuing
end
dungeon_frames = dungeon_frames +floor_frames +distance
if f == floors then
log_update("= Total steps: " .. steps .. " steps; Total time: " .. dungeon_frames)
end
end
memorysavestate.removestate(floor_state)
end
memorysavestate.loadcorestate(iter_state)
client.pause()