User File #76000472267214701

Upload All User Files

#76000472267214701 - Blue Rescue Team - dungeon bruteforce v1.2

PMD1_dungeon_bruteforce_v1.2.lua
139 downloads
Uploaded 12/5/2021 4:28 PM by ThunderAxe31 (see all 111)
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