User File #45747701013813013

Upload All User Files

#45747701013813013 - Another Pokemon DPPt script

pearl_plat_rng_v2_3_1.lua
907 downloads
Uploaded 3/14/2018 5:50 AM by FractalFusion (see all 78)
Modified to include AABB autofire, battle analysis, and a "minimal mode"
-- Lua Script made by MKDasher
-- Based on gen 3 lua scripts by FractalFusion
-- Japanese D/P support added by Fortranm

--TODO:
-- Roaming pkm (birds)
-- Next pkrs frame
-- Object rate for pokemon

-------------------------

--Keys:

-- 1: Activate AABB autofire
--    Risk of dropping inputs if emulation speed is too high (0.5x  speed is usually safe)
--    (AABB isn't optimal on level-up stat dialogs for some reason, so don't use it there)
-- 3: Go to previous mode
-- 4: Go to next mode
-- 6: In RNG analysis (battle mode), subtract 2 from the RNG seed being analyzed
-- 7: In RNG analysis (battle mode), add 2 to the RNG seed being analyzed
-- 8: In RNG analysis (battle mode), subtract 1 from the highest byte of the RNG seed being analyzed
-- 9: In RNG analysis (battle mode), add 1 to the highest byte of the RNG seed being analyzed


-----
-- Analysis

-- First of all, the base RNG will now update whenever it is reseeded entering battle, so that the RNG distance resets to 0 on the first seed. Only exception is if it is too close to the overworld seed (but when does that happen anyway)
-- The following is used to do battle analysis.
-- rngdelay indicates the smallest RNG distance to check for crits/misses/etc.
-- mode=1 for critical hit, 2 for miss
-- probabilities works like this:
---- If mode is 1, probabilities should be a number from 0 to 15. 100 minus this number is the minimum allowable percentage of the max range for the crit. 0 means max crit (1/256 chance). 15 means any crit.
---- If mode is 2, probabilities is the accuracy of the move that you want to make miss (95, 90, etc.).
-- maxdelay is the maximum number of delay frames allowed in the result. ">max" will display if the total delay exceeds this.

-- Analysis will automatically be performed any time the base RNG is reseeded, or 6/7/8/9 is pressed.
-- The analyzed RNG will be displayed, followed by the delays for each rngdelay point, and then the total delay, and then the targeted RNG indices (distances).

-- Keys 6 and 7 add/subtract 2 to/from the analyzed RNG seed, so you don't have to keep loading savestates. Each addition of 2 corresponds to delaying 1 input frame (2 frames). However, if the seconds value changes, then you also need keys 8 and 9 to adjust the highest byte of the RNG. But you don't need to use 8 or 9 if you are only looking for crits/range, because the highest byte has no effect on crits/range, only on misses and any mechanic that is calculated mod 100.

-- You need to find and enter these values yourself.

local rngdelay = {565,862,935,1095}
local mode = {1, 2, 2, 1} -- 1 = critical hit, 2 = miss
local probabilities = {15, 95, 95, 10}
local maxdelay=50

-------------------------
local testingseed_forRNG =  0x160e0f55  --put overworld rng seed here
-------------------------

local land_mode = 1 -- menu mode (Auto = default)
local land_modehitbox = {0, 70, 106, 143}
local curland_mode = 0 -- real mode
local land = 0 -- selected mode
local landstr = {"Grass", "Water"}

local movement_mode = 1
local curmovement_mode = 1
local movement_rate
local movement_str = {"Walk", "Swim", "Bike"}
local movement_modehitbox = {0,64,94,124,155}

local encrate_mode = 1
local encrate_modehitbox = {0, 53, 71, 89, 107, 125, 143}

local hitboxstart = 73
local hitboxheight = -35
local menuvisible = 0

local bottommenu_mode = 1
local bottommenu_str = {"  Battle  ", "Next encs ", "  Slots   ","   Misc   "}

local encrate = 0
local curencrate = 0

local stepcounter = 0
local maxstepcounter = 0

local rshift, lshift=bit.rshift, bit.lshift
local lastRNG = 0
local i
local tabl={}
local prev={}

local hour = 0

local game = 1
local gamename = ""
local pointerAddr = {0x02106FAC, 0x02101D2C, 0x02108804}
local stepcounterAddrOffset = {0x2FA40, 0x2E834, 0x2FA40}
local stepcnt128AddrOffset = {0xE044, 0xDE34, 0xE044}
local RNGAddr = {0x021C4D48, 0x021BFB14, 0x021C65A8}
local curlandmodeAddrOffset = {0x31AE2, 0x3090A, 0x31AE2}
local curmovementmodeAddrOffset = {0x31950, 0x30778, 0x31950}
local grassEncAddrOffset = {0x315C0, 0x303C4, 0x315C0}
local waterEncAddrOffset = {0x3168C, 0x30490, 0x3168C}
local framecountAddr = {0x021C48E4, 0x021BF6A8, 0x021C6144}
local IGTAddrOffset = {0xD29A, 0xD07E, 0xD29A}
local clockAddr = {0x021C4828, 0x021BF5E8, 0x021C6088}
local TIDAddrOffset = {0xD288, 0xD06C, 0xD288}
local LIDAddrOffset = {0xE028, 0xDE18, 0xE028}

local encslots_pkm = {}
local encslots_lvl = {}
local waterslots_pkm = {}
local waterslots_minlvl = {}
local waterslots_maxlvl = {}

function drawsquare(a,b,c)
 gui.box(a,b,a+4,b+4,c)
end
function drawarrowdown(a,b,c)
 gui.line(a,b,a-2,b-2,c)
 gui.line(a,b,a+2,b-2,c)
 gui.line(a,b,a,b-6,c)
end
function drawarrowleft(a,b,c)
 gui.line(a,b+3,a+2,b+5,c)
 gui.line(a,b+3,a+2,b+1,c)
 gui.line(a,b+3,a+6,b+3,c)
end
function drawarrowright(a,b,c)
 gui.line(a,b+3,a-2,b+5,c)
 gui.line(a,b+3,a-2,b+1,c)
 gui.line(a,b+3,a-6,b+3,c)
end
function mult32(a,b)
 local c=rshift(a,16)
 local d=a%0x10000
 local e=rshift(b,16)
 local f=b%0x10000
 local g=(c*f+d*e)%0x10000
 local h=d*f
 local i=g*0x10000+h
 return i
end

function gettop(a)
	return(rshift(a,16))
end

function getbits(a,b,d)
	return rshift(a,b)%lshift(1,d)
end

local multspa={
 0x41C64E6D, 0xC2A29A69, 0xEE067F11, 0xCFDDDF21, 0x5F748241, 0x8B2E1481, 0x76006901, 0x1711D201,
 0xBE67A401, 0xDDDF4801, 0x3FFE9001, 0x90FD2001, 0x65FA4001, 0xDBF48001, 0xF7E90001, 0xEFD20001,
 0xDFA40001, 0xBF480001, 0x7E900001, 0xFD200001, 0xFA400001, 0xF4800001, 0xE9000001, 0xD2000001,
 0xA4000001, 0x48000001, 0x90000001, 0x20000001, 0x40000001, 0x80000001, 0x00000001, 0x00000001}

local multspb={
 0x00006073, 0xE97E7B6A, 0x31B0DDE4, 0x67DBB608, 0xCBA72510, 0x1D29AE20, 0xBA84EC40, 0x79F01880,
 0x08793100, 0x6B566200, 0x803CC400, 0xA6B98800, 0xE6731000, 0x30E62000, 0xF1CC4000, 0x23988000,
 0x47310000, 0x8E620000, 0x1CC40000, 0x39880000, 0x73100000, 0xE6200000, 0xCC400000, 0x98800000,
 0x31000000, 0x62000000, 0xC4000000, 0x88000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000}
 
function rngAdvance(a)
	return mult32(a,0x41C64E6D) + 0x6073
end

local baseRNGseed=testingseed_forRNG
function getSeedDistance(a)
	test=baseRNGseed
    distseed=0
    for j=0,31,1 do
		if getbits(a,j,1)~=getbits(test,j,1) then
			test=mult32(test,multspa[j+1])+multspb[j+1]
			distseed=distseed+bit.lshift(1,j)
			--if j==31 then
			--	distseed=distseed+0x100000000
			--end
		end
    end
	return distseed
end

function fillEncSlots()
	-- fill grass slots
	slotAddr = pointer + grassEncAddrOffset[game] + 4
	for i=1,12,1 do
		encslots_lvl[i] = memory.readdword(slotAddr)
		slotAddr = slotAddr + 4
		encslots_pkm[i] = memory.readdword(slotAddr)
		slotAddr = slotAddr + 4
	end
	-- overwrite slot 2 and 3 (3 and 4 in the array) with day / night encounters
	slotAddr = pointer + grassEncAddrOffset[game] + 0x6c
	if hour >= 10 and hour < 20 then --day
		encslots_pkm[3] = memory.readdword(slotAddr)
		encslots_pkm[4] = memory.readdword(slotAddr + 4)
	elseif hour >= 20 or hour < 4 then --night
		encslots_pkm[3] = memory.readdword(slotAddr + 8)
		encslots_pkm[4] = memory.readdword(slotAddr + 12)
	end
	-- fill water slots
	slotAddr = pointer + waterEncAddrOffset[game] + 4
	for i=1,5,1 do
		waterslots_maxlvl[i] = memory.readbyte(slotAddr)
		slotAddr = slotAddr + 1
		waterslots_minlvl[i] = memory.readbyte(slotAddr)
		slotAddr = slotAddr + 3
		waterslots_pkm[i] = memory.readdword(slotAddr)
		slotAddr = slotAddr + 4
	end
end

function ModeHandler()
	curland_mode = memory.readbyte(pointer + curlandmodeAddrOffset[game])
	if (curland_mode == 16 or curland_mode == 21) then --16 and 21 are water values
		curland_mode = 2
	else
		curland_mode = 1
	end
	
	if land_mode == 2 then -- Grass
		land = 1
	elseif land_mode == 3 then --(Water)
		land = 2
	else --(Auto)
		land = curland_mode 
	end
	
	if land == 1 then -- Grass
		curencrate = memory.readbyte(pointer + grassEncAddrOffset[game])
	else -- land == 2 --(Water)
		curencrate = memory.readbyte(pointer + waterEncAddrOffset[game])
	end
	maxstepcounter = 8 - lshift(curencrate,8) / 2560
	
	encrate = curencrate
	if encrate_mode > 1 then
		encrate = 5 * encrate_mode
	end
	
	-- 1 = walk, 6 = swim, 3 = bike
	curmovement_mode = memory.readdword(pointer + curmovementmodeAddrOffset[game])
	-- Since I store mode on array [walk, swim, bike], I convert mode 6 (swim) to 2
	if curmovement_mode == 6 then
		curmovement_mode = 2
	elseif curmovement_mode ~= 3 then
		curmovement_mode = 1 -- just to avoid lua crashing
	end
	
	movement_rate = 40
	if (movement_mode == 1 and curmovement_mode == 3) or movement_mode == 4 then --bike
		movement_rate = 70 -- bike enc rate
	end

	--print modes
	if menuvisible == 0 then
		gui.box(0,hitboxheight-5,12,0,"#00FF00B0")
		gui.text(3,hitboxheight-3, "S\nH\nO\nW\n", "#88FF88B0")
	else	
		gui.box(0,hitboxheight,256,0,"#000000B0")
		gui.box(0,hitboxheight-5,12,0,"#FF0000B0")
		gui.text(3,hitboxheight-3, "H\nI\nD\nE\n", "#FF8888B0")
		gui.box(land_modehitbox[1]+hitboxstart,hitboxheight,land_modehitbox[4]+hitboxstart,hitboxheight+10,"#FF0000B0", "#00000000")
		gui.box(movement_modehitbox[1]+hitboxstart,hitboxheight+10,movement_modehitbox[5]+hitboxstart,hitboxheight+20,"#FF0000B0", "#00000000")
		gui.box(encrate_modehitbox[1]+hitboxstart,hitboxheight+20,encrate_modehitbox[7]+hitboxstart,hitboxheight+30,"#FF0000B0", "#00000000")
		gui.box(land_modehitbox[land_mode]+hitboxstart,hitboxheight,land_modehitbox[land_mode+1]+hitboxstart,hitboxheight+10,"#0000FFFF", "#00000000")
		gui.box(movement_modehitbox[movement_mode]+hitboxstart,hitboxheight+10,movement_modehitbox[movement_mode+1]+hitboxstart,hitboxheight+20,"#0000FFFF", "#00000000")
		gui.box(encrate_modehitbox[encrate_mode]+hitboxstart,hitboxheight+20,encrate_modehitbox[encrate_mode+1]+hitboxstart,hitboxheight+30,"#0000FFFF", "#00000000")
		gui.text(15, hitboxheight+2, "LandType: Auto(" .. landstr[curland_mode] .. ") Grass Water","#FFFFFFB0")
		gui.text(15, hitboxheight+12, "Movement: Auto(" .. movement_str[curmovement_mode] .. ") Walk Swim Bike","#FFFFFFB0")
		if curencrate == 0 then
			gui.text(15, hitboxheight+22, "Enc.rate: Auto( 0) 10 15 20 25 30","#FFFFFFB0")
		else
			gui.text(15, hitboxheight+22, "Enc.rate: Auto(" .. curencrate .. ") 10 15 20 25 30","#FFFFFFB0")
		end
	end
end

local delaycount=0
local results = {}
local baseseedstring = "?"
local rngstring = "?"
local rngstring2 = "?"

function analyze(startRNG,RNGshift)

		baseseedstring = bit.tohex(startRNG) .. " (" .. RNGshift .. ")"
		rng=startRNG
		
		
		delaycount=0
		for i=1,#rngdelay,1 do
			local delays=rngdelay[1]
			if i>1 then
				delays=rngdelay[i]-rngdelay[i-1]
			end
			for j=1,delays,1 do
				rng=rngAdvance(rng)
			end
			--check for crit/miss
			if mode[i]==1 then --crit
				while delaycount<=maxdelay do
					if gettop(rng)%16==0 then
						rng2=rng
						rng2=rngAdvance(rng2)
						rng2=rngAdvance(rng2)
						if gettop(rng2)%16<=probabilities[i] then
						    results[i]=delaycount
							break
						end
					end
					rng=rngAdvance(rng)
					delaycount=delaycount+1
					--dbgcnt=dbgcnt+1
				end
			
			elseif mode[i]==2 then --miss
				while delaycount<=maxdelay do
					if gettop(rng)%100>=probabilities[i] then
						results[i]=delaycount
						break
					end
					rng=rngAdvance(rng)
					delaycount=delaycount+1
				end			
			end
			
			if delaycount>maxdelay then --exceeded limit
				break
			end
			
			
			
		end
		
		if delaycount>maxdelay then --exceeded limit
			rngstring=">max"
			rngstring2=""
		else --form rngstring of results
			rngstring=""
			rngstring2=""
			for i=1,#rngdelay,1 do
				if i==1 then
					rngstring=rngstring..results[1].." "
				else
					rngstring=rngstring..results[i]-results[i-1].." "
				end
				rngstring2=rngstring2..rngdelay[i]+results[i].." "
			end
			rngstring=rngstring.."tl:"..delaycount
		end
		
end
analyze(baseRNGseed,0)

local autofire=false
local shifted_baseRNG=baseRNGseed
local shifted_baseRNG_count=0
function UpdateTab()
	tabl = input.get()
	if tabl["1"] and not prev["1"] then
	   if autofire then
	     autofire=false
	   else
	     autofire=true
	   end
	end
	
	--local rngdelay = {100,200,300}
	--local mode = {1, 1, 1} -- 1 = critical hit, 2 = miss
	--local probabilities = {0, 0, 0}
	--local maxdelay=100
	--local delaycount
	--local results
	
	--if tabl["2"] and not prev["2"] then
		--testingseed_forRNG=memory.readdword(RNGAddr[game])
		--analysis mode
		--analyze(baseRNGseed)
		
	--end
	
	if tabl["6"] and not prev["6"] then
	  shifted_baseRNG=shifted_baseRNG-2
	  shifted_baseRNG_count=shifted_baseRNG_count-1
	  analyze(shifted_baseRNG,shifted_baseRNG_count)
	end
	if tabl["7"] and not prev["7"] then
	  shifted_baseRNG=shifted_baseRNG+2
	  shifted_baseRNG_count=shifted_baseRNG_count+1
	  analyze(shifted_baseRNG,shifted_baseRNG_count)
	end
	if tabl["8"] and not prev["8"] then
	  shifted_baseRNG=shifted_baseRNG-0x1000000
	  analyze(shifted_baseRNG,shifted_baseRNG_count)
	end
	if tabl["9"] and not prev["9"] then
	  shifted_baseRNG=shifted_baseRNG+0x1000000
	  analyze(shifted_baseRNG,shifted_baseRNG_count)
	end
	
	--if tabl["6"] and not prev["6"] then
	--	cur=memory.readdword(RNGAddr[game])
	--	cur=mult32(cur,0XEEB9EB65) + 0XA3561A1
	--	memory.writedword(RNGAddr[game], bit.band(cur))
	--end
	--if tabl["7"] and not prev["7"] then
	--	cur=memory.readdword(RNGAddr[game])
	--	cur=mult32(cur,0x41C64E6D) + 0x6073
	--	memory.writedword(RNGAddr[game], bit.band(cur))
	--end



	if tabl["3"] and not prev["3"] then
		if bottommenu_mode == 0 then
			bottommenu_mode = 4
		else
			bottommenu_mode = bottommenu_mode - 1
		end
	end
	if tabl["4"] and not prev["4"] then
		if bottommenu_mode == 4 then
			bottommenu_mode = 0
		else
			bottommenu_mode = bottommenu_mode + 1
		end
	end
--	if tabl["5"] and not prev["5"] then
--		memory.writedword(RNGAddr[game], bit.band(testingseed_forRNG))
--	end
	if tabl['leftclick'] and not prev['leftclick'] then
		x = tabl['xmouse']
		y = tabl['ymouse']
		if menuvisible == 1 then
			if y >= hitboxheight and y < hitboxheight+10 then
				for i = 1, 3, 1 do
					if x >= land_modehitbox[i]+hitboxstart and x < land_modehitbox[i+1]+hitboxstart then
						land_mode = i
						break
					end
				end
			end
			if y >= hitboxheight+10 and y < hitboxheight+20 then
				for i = 1, 4, 1 do
					if x >= movement_modehitbox[i]+hitboxstart and x < movement_modehitbox[i+1]+hitboxstart then
						movement_mode = i
						break
					end
				end
			end
			if y >= hitboxheight+20 and y < hitboxheight+30 then
				for i = 1, 6, 1 do
					if x >= encrate_modehitbox[i]+hitboxstart and x < encrate_modehitbox[i+1]+hitboxstart then
						encrate_mode = i
						break
					end
				end
			end
		end
		if x > 0 and x < 12 and y >= hitboxheight and y < hitboxheight+30 then
			if menuvisible == 1 then
				menuvisible = 0
			else
				menuvisible = 1
			end
		end
		if x > 1 and x < 15 and y > 177 and y < 189 then
			if bottommenu_mode == 0 then
				bottommenu_mode = 4
			else
				bottommenu_mode = bottommenu_mode - 1
			end
		end
		if x > 79 and x < 93 and y > 177 and y < 189 then
			if bottommenu_mode == 4 then
				bottommenu_mode = 0
			else
				bottommenu_mode = bottommenu_mode + 1
			end
		end
	end
	prev=tabl	
end

local pokemonname =  {"none", "Bulbasaur", "Ivysaur", "Venusaur", "Charmander", "Charmeleon", "Charizard",
			"Squirtle", "Wartortle", "Blastoise", "Caterpie", "Metapod", "Butterfree",
			"Weedle", "Kakuna", "Beedrill", "Pidgey", "Pidgeotto", "Pidgeot", "Rattata", "Raticate",
			"Spearow", "Fearow", "Ekans", "Arbok", "Pikachu", "Raichu", "Sandshrew", "Sandslash",
			"NidoranF", "Nidorina", "Nidoqueen", "NidoranM", "Nidorino", "Nidoking",
			"Clefairy", "Clefable", "Vulpix", "Ninetales", "Jigglypuff", "Wigglytuff",
			"Zubat", "Golbat", "Oddish", "Gloom", "Vileplume", "Paras", "Parasect", "Venonat", "Venomoth",
			"Diglett", "Dugtrio", "Meowth", "Persian", "Psyduck", "Golduck", "Mankey", "Primeape",
			"Growlithe", "Arcanine", "Poliwag", "Poliwhirl", "Poliwrath", "Abra", "Kadabra", "Alakazam",
			"Machop", "Machoke", "Machamp", "Bellsprout", "Weepinbell", "Victreebel", "Tentacool", "Tentacruel",
			"Geodude", "Graveler", "Golem", "Ponyta", "Rapidash", "Slowpoke", "Slowbro",
			"Magnemite", "Magneton", "Farfetch'd", "Doduo", "Dodrio", "Seel", "Dewgong", "Grimer", "Muk",
			"Shellder", "Cloyster", "Gastly", "Haunter", "Gengar", "Onix", "Drowzee", "Hypno",
			"Krabby", "Kingler", "Voltorb", "Electrode", "Exeggcute", "Exeggutor", "Cubone", "Marowak",
			"Hitmonlee", "Hitmonchan", "Lickitung", "Koffing", "Weezing", "Rhyhorn", "Rhydon", "Chansey",
			"Tangela", "Kangaskhan", "Horsea", "Seadra", "Goldeen", "Seaking", "Staryu", "Starmie",
			"Mr. Mime", "Scyther", "Jynx", "Electabuzz", "Magmar", "Pinsir", "Tauros", "Magikarp", "Gyarados",
			"Lapras", "Ditto", "Eevee", "Vaporeon", "Jolteon", "Flareon", "Porygon", "Omanyte", "Omastar",
			"Kabuto", "Kabutops", "Aerodactyl", "Snorlax", "Articuno", "Zapdos", "Moltres",
			"Dratini", "Dragonair", "Dragonite", "Mewtwo", "Mew",
			"Chikorita", "Bayleef", "Meganium", "Cyndaquil", "Quilava", "Typhlosion",
			"Totodile", "Croconaw", "Feraligatr", "Sentret", "Furret", "Hoothoot", "Noctowl",
			"Ledyba", "Ledian", "Spinarak", "Ariados", "Crobat", "Chinchou", "Lanturn", "Pichu", "Cleffa",
			"Igglybuff", "Togepi", "Togetic", "Natu", "Xatu", "Mareep", "Flaaffy", "Ampharos", "Bellossom",
			"Marill", "Azumarill", "Sudowoodo", "Politoed", "Hoppip", "Skiploom", "Jumpluff", "Aipom",
			"Sunkern", "Sunflora", "Yanma", "Wooper", "Quagsire", "Espeon", "Umbreon", "Murkrow", "Slowking",
			"Misdreavus", "Unown", "Wobbuffet", "Girafarig", "Pineco", "Forretress", "Dunsparce", "Gligar",
			"Steelix", "Snubbull", "Granbull", "Qwilfish", "Scizor", "Shuckle", "Heracross", "Sneasel",
			"Teddiursa", "Ursaring", "Slugma", "Magcargo", "Swinub", "Piloswine", "Corsola", "Remoraid", "Octillery",
			"Delibird", "Mantine", "Skarmory", "Houndour", "Houndoom", "Kingdra", "Phanpy", "Donphan",
			"Porygon2", "Stantler", "Smeargle", "Tyrogue", "Hitmontop", "Smoochum", "Elekid", "Magby", "Miltank",
			"Blissey", "Raikou", "Entei", "Suicune", "Larvitar", "Pupitar", "Tyranitar", "Lugia", "Ho-Oh", "Celebi",			
			"Treecko", "Grovyle", "Sceptile", "Torchic", "Combusken", "Blaziken", "Mudkip", "Marshtomp", 
			"Swampert", "Poochyena", "Mightyena", "Zigzagoon", "Linoone", "Wurmple", "Silcoon", "Beautifly",
			"Cascoon", "Dustox", "Lotad", "Lombre", "Ludicolo", "Seedot", "Nuzleaf", "Shiftry", 
			"Taillow", "Swellow", "Wingull", "Pelipper", "Ralts", "Kirlia", "Gardevoir", "Surskit", 
			"Masquerain", "Shroomish", "Breloom", "Slakoth", "Vigoroth", "Slaking", "Nincada", "Ninjask", 
			"Shedinja", "Whismur", "Loudred", "Exploud", "Makuhita", "Hariyama", "Azurill", "Nosepass", 
			"Skitty", "Delcatty", "Sableye", "Mawile", "Aron", "Lairon", "Aggron", "Meditite", "Medicham",
			"Electrike", "Manectric", "Plusle", "Minun", "Volbeat", "Illumise", "Roselia", "Gulpin", 
			"Swalot", "Carvanha", "Sharpedo", "Wailmer", "Wailord", "Numel", "Camerupt", "Torkoal", 
			"Spoink", "Grumpig", "Spinda", "Trapinch", "Vibrava", "Flygon", "Cacnea", "Cacturne", "Swablu",
			"Altaria", "Zangoose", "Seviper", "Lunatone", "Solrock", "Barboach", "Whiscash", "Corphish",
			"Crawdaunt", "Baltoy", "Claydol", "Lileep", "Cradily", "Anorith", "Armaldo", "Feebas", 
			"Milotic", "Castform", "Kecleon", "Shuppet", "Banette", "Duskull", "Dusclops", "Tropius", 
			"Chimecho", "Absol", "Wynaut", "Snorunt", "Glalie", "Spheal", "Sealeo", "Walrein", "Clamperl",
			"Huntail", "Gorebyss", "Relicanth", "Luvdisc", "Bagon", "Shelgon", "Salamence", "Beldum", 
			"Metang", "Metagross", "Regirock", "Regice", "Registeel", "Latias", "Latios", "Kyogre", 
			"Groudon", "Rayquaza", "Jirachi", "Deoxys",			
			"Turtwig", "Grotle", "Torterra", "Chimchar", "Monferno", "Infernape", "Piplup", "Prinplup", 
			"Empoleon", "Starly", "Staravia", "Staraptor", "Bidoof", "Bibarel", "Kricketot", "Kricketune", 
			"Shinx", "Luxio", "Luxray", "Budew", "Roserade", "Cranidos", "Rampardos", "Shieldon", "Bastiodon", 
			"Burmy", "Wormadam", "Mothim", "Combee", "Vespiquen", "Pachirisu", "Buizel", "Floatzel", "Cherubi", 
			"Cherrim", "Shellos", "Gastrodon", "Ambipom", "Drifloon", "Drifblim", "Buneary", "Lopunny", 
			"Mismagius", "Honchkrow", "Glameow", "Purugly", "Chingling", "Stunky", "Skuntank", "Bronzor", 
			"Bronzong", "Bonsly", "Mime Jr.", "Happiny", "Chatot", "Spiritomb", "Gible", "Gabite", "Garchomp", 
			"Munchlax", "Riolu", "Lucario", "Hippopotas", "Hippowdon", "Skorupi", "Drapion", "Croagunk", 
			"Toxicroak", "Carnivine", "Finneon", "Lumineon", "Mantyke", "Snover", "Abomasnow", "Weavile", 
			"Magnezone", "Lickilicky", "Rhyperior", "Tangrowth", "Electivire", "Magmortar", "Togekiss", 
			"Yanmega", "Leafeon", "Glaceon", "Gliscor", "Mamoswine", "Porygon-Z", "Gallade", "Probopass", 
			"Dusknoir", "Froslass", "Rotom", "Uxie", "Mesprit", "Azelf", "Dialga", "Palkia", "Heatran", 
			"Regigigas", "Giratina", "Cresselia", "Phione", "Manaphy", "Darkrai", "Shaymin", "Arceus",
}
nature = {"Hardy","Lonely(+ATK-DEF)","Brave(+ATK-SPE)","Adamant(+ATK-SAT)","Naughty(+ATK-SDF)",
			"Bold(+DEF-ATK)","Docile","Relaxed(+DEF-SPE)","Impish(+DEF-SAT)","Lax(+DEF-SDF)",
			"Timid(+SPE-ATK)","Hasty(+SPE-DEF)","Serious","Jolly(+SPE-SAT)","Naive(+SPE-SDF)",
			"Modest(+SAT-ATK)","Mild(+SAT-DEF)","Quiet(+SAT-SPE)","Bashful","Rash(+SAT-SDF)",
			"Calm(+SDF-ATK)","Gentle(+SDF-DEF)","Sassy(+SDF-SPE)","Careful(+SDF-SAT)","Quirky"}
			
function MethodJ(initialrng, a)
	frame = getSeedDistance(initialrng)
	rng2 = initialrng
	rng = rngAdvance(initialrng)
	slot = math.floor(gettop(rng2) / 656)
	pkmstr = ""
	lvlnum = 0
	if land == 1 then --(Grass)
		if (slot < 20) then slot = 0
		elseif (slot < 40) then slot = 1
		elseif (slot < 50) then slot = 2
		elseif (slot < 60) then slot = 3
		elseif (slot < 70) then slot = 4
		elseif (slot < 80) then slot = 5
		elseif (slot < 85) then slot = 6
		elseif (slot < 90) then slot = 7
		elseif (slot < 94) then slot = 8
		elseif (slot < 98) then slot = 9
		elseif (slot == 98) then slot = 10
		else slot = 11
		end
		pkmstr = pokemonname[encslots_pkm[slot+1]+1]
		lvlnum = encslots_lvl[slot+1]
	else -- land == 2 (Water)
		if (slot < 60) then slot = 0
		elseif (slot < 90) then slot = 1
		elseif (slot < 95) then slot = 2
		elseif (slot < 99) then slot = 3
		else slot = 4
		end
		pkmstr = pokemonname[waterslots_pkm[slot+1]+1]
		lvlnum = gettop(rng) % (waterslots_maxlvl[slot+1] - waterslots_minlvl[slot+1] + 1) + waterslots_minlvl[slot+1]
		rng = rngAdvance(rng)
		frame = frame + 1
	end
	mynat = math.floor(gettop(rng) / 0xA3E)
	loop = 0
	while (true) do
		rng2 = rngAdvance(rng)
		rng = rngAdvance(rng2)
		pid = gettop(rng)*65536 + gettop(rng2)  
		if (pid % 25 == mynat) then break end
	end
	rng = rngAdvance(rng)
	IV = gettop(rng)
	rng = rngAdvance(rng)
	IV2 = gettop(rng)
	gui.text(120,a, "F:".. frame ..
		", " .. pkmstr, "#FFFFFF80")
	gui.text(120,a+10, "IV: [".. IV%32 .. "," .. math.floor(IV/32)%32 .. ","
		.. math.floor(IV/1024)%32 .. "," .. math.floor(IV2/32)%32 .. ","
		.. math.floor(IV2/1024)%32 .. "," .. IV2%32 .. "]", "#FFFFFF80")
	gui.text(120,a+20, nature[mynat+1] .. " L." .. lvlnum, "#FFFFFF80")
end

function drawGrid()
	test = currentRNG
	lastRNG = currentRNG
	
	futureencs = {}
	futureencs_n = 0
	
	gui.box(3,3,103,79,"#AAAAAAA0", "white")	
	
	if bottommenu_mode == 1 then
		for i = 0, 11, 1 do
		for j = 0, 15, 1 do
			clr = "#000000FF" -- init square color to black
		    if j % 4 == 0 then
			 clr = "#404040FF"
			end
			
			randvalue = gettop(test)
			
			if randvalue % 16 == 0 then
			 if randvalue % 100 >= 95 then
			  clr = "magenta"
			 else
			  clr = "red"
			 end
			--elseif randvalue % 16 ==9 then
			  --clr = "green"
			else
			 if randvalue % 100 >= 95 then
			  clr = "blue"
			 end
			end
			
			drawsquare(6+6*j,6+6*i, clr)
			test=rngAdvance(test)
		end
		end
		drawarrowdown(8,6, "red")
		drawarrowdown(26,6, "red")
		drawarrowdown(44,6, "blue")
	else
		for i = 0, 11, 1 do
		for j = 0, 15, 1 do
			clr = "#000000FF" -- init square color to black
			randvalue = gettop(test)
			test2 = test
			if (stepcounter >= maxstepcounter) or (encrate_mode > 1) or (randvalue / 0x290 < 5) then
				if (stepcounter < maxstepcounter and encrate_mode == 1) then
					clr = "#666666FF"
					test2=rngAdvance(test2)
					randvalue=gettop(test2)
				end
				if (randvalue / 0x290 < movement_rate) then
					clr = "#666666FF"
					test2=rngAdvance(test2)
					randvalue=gettop(test2)
					if (randvalue / 0x290 < encrate) then
						clr = "#FF0000FF"
						if futureencs_n < 10 then
							futureencs[futureencs_n] = rngAdvance(test2)
							futureencs_n = futureencs_n + 1
						end
					end
				end
			end
			drawsquare(6+6*j,6+6*i, clr)
			test=rngAdvance(test)
		end
		end
	end
end

local buttons1={}
local buttons2={}
buttons1.A=true
buttons1.B=false
buttons2.B=true
buttons2.A=false

function fn()

    if autofire then
      if emu.framecount()%4==0 or emu.framecount()%4==1 then
	    joypad.set(buttons1)
      else
	    joypad.set(buttons2)
	  end	
    end	

	gameIDAddr = memory.readdword(0x23FFE0C)
	if gameIDAddr == 0x45415041 then
		game = 1
		gamename = "Pearl (U)"
	elseif gameIDAddr == 0x45414441 then
		game = 1
		gamename = "Diamond (U)"
	elseif gameIDAddr == 0x45555043 then
		game = 2
		gamename = "Platinum (U)"
	elseif gameIDAddr == 0x4A415041 then
		game = 3
		gamename = "Pearl (J)"
	elseif gameIDAddr == 0x4A414441 then
		game = 3
		gamename = "Diamond (J)"
	else
		game = -1
		gamename = "Invalid game"
	end

  if bottommenu_mode~=0 then
	
	gui.box(0,-192,256,-181,"#00000080")
	gui.box(0,0,256,192,"#000000A0")
	gui.text(0,-190,"Game: " .. gamename,"#FFFFFFB0")
	gui.text(140,-190,"Base seed: " .. bit.tohex(baseRNGseed),"#FFFFFFB0")
	if game == -1 then
		return
	end

	pointer = memory.readdword(pointerAddr[game])
	stepcounter = memory.readbyte(pointer + stepcounterAddrOffset[game])
	stepcnt128 = memory.readbyte(pointer + stepcnt128AddrOffset[game])
	
	UpdateTab()
	ModeHandler()
	
	currentRNG = memory.readdword(RNGAddr[game])
	nextRNG = rngAdvance(currentRNG)
	
	test = lastRNG
	for i = 0, 150, 1 do
		if bit.tohex(currentRNG)==bit.tohex(test) then
			gui.text(0,113,"Dist last: "..i, "#FFFF00A0")
			break
		elseif i >= 150 then
			gui.text(0,113,"Dist last: >150", "#FFFF00A0")
			break
		end
		test=rngAdvance(test)
	end
	
	gui.text(0,83,"Curr RNG: "..bit.tohex(currentRNG), "#FFFF00A0")
	gui.text(0,93,"Next RNG: "..bit.tohex(nextRNG), "#FFFF00A0")
	gui.text(0,103, "Step Cnt (128): ".. stepcnt128, "#FFFF00A0")
	distanceseed = getSeedDistance(currentRNG)
	if distanceseed>30000 or distanceseed<-1000 then
	  baseRNGseed=testingseed_forRNG
	  distanceseed = getSeedDistance(currentRNG)
	  if distanceseed>30000 or distanceseed<-1000 then
	     baseRNGseed=currentRNG
		 distanceseed=0
	  end
	  analyze(baseRNGseed, 0)
	  shifted_baseRNG=baseRNGseed
	  shifted_baseRNG_count=0
	end
	gui.text(0,123,"Dist seed: " .. distanceseed, "#FFFF00A0")
	gui.text(0,133, "Enc. Rate Cnt: ".. stepcounter .. "/".. maxstepcounter, "#FFFF00A0")
	hour = memory.readdword(clockAddr[game])
	gui.text(0,143, "Clock: "
		.. hour .. ":"
		.. memory.readdword(clockAddr[game]+4) .. ":"
		.. memory.readdword(clockAddr[game]+8)
	, "#FFFF00A0")
	gui.text(0,153, "IGT: "
		.. memory.readbyte(pointer + IGTAddrOffset[game]) .. ":"
		.. memory.readbyte(pointer + IGTAddrOffset[game]+2) .. ":"
		.. memory.readbyte(pointer + IGTAddrOffset[game]+3)
	, "#FFFF00A0")
	gui.text(0,163, "IG Framecount: " .. memory.readdword(framecountAddr[game]), "#FFFF00A0")
	
	-- Enc Slots
	fillEncSlots()

	-- Point Grid
	drawGrid()
	
	gui.box(2,177,93,189,"#00000080","#FFFFFFFF")
	drawarrowleft(5,180,"#FFFFFFFF")
	gui.text(20,180, bottommenu_str[bottommenu_mode], "#FFFFFFFF")
	drawarrowright(90,180,"#FFFFFFFF")
	
	
	if bottommenu_mode == 1 then
		gui.text(115,5,"RNG Analysis","#FFFFFFB0")
		gui.text(115,15,"" .. baseseedstring,"#FFFFFFB0")
		gui.text(115,25,"" .. rngstring,"#FFFFFFB0")
		gui.text(115,35,"" .. rngstring2,"#FFFFFFB0")
		
		
	
	
	elseif bottommenu_mode == 2 then
		--gui.text(50, -170, "Stationary:", "#FFFFFF80")
		--local tempRNG=rngAdvance(currentRNG)
		--MethodJ(tempRNG,-170)
		gui.text(86, -137, "Wild:", "#FFFFFF80")
		for i = 0, futureencs_n-1, 1 do
			MethodJ(futureencs[i],-170 + 33*(i+1))
		end
	elseif bottommenu_mode == 3 then
		gui.text(115,5, "Encounter slots (" .. landstr[land] .. ")", "#00FF00FF")
		if land == 1 then -- (Grass)
			for i = 1, 12, 1 do
				gui.text(115, (i+1)*10, i-1 .. " - " .. pokemonname[encslots_pkm[i]+1] .. " L." .. encslots_lvl[i])
			end
		else --land == 2 (Water)
			for i = 1, 5, 1 do
				gui.text(115, (i+1)*10, i-1 .. " - " .. pokemonname[waterslots_pkm[i]+1] .. " L." .. waterslots_minlvl[i] .. "-" .. waterslots_maxlvl[i])
			end
		end
	elseif bottommenu_mode == 4 then
		gui.text(115,5, "Misc. Data", "#00FF00FF")
		gui.text(115,20, "Trainer ID: " .. memory.readword(pointer + TIDAddrOffset[game]))
		gui.text(115,30, "Secret  ID: " .. memory.readword(pointer + TIDAddrOffset[game]+2))
		gui.text(115,40, "Lottery ID: " .. memory.readword(pointer + LIDAddrOffset[game]))
	end
	
	
	
	
  else --minimal mode
  
    gui.text(0,0,"Minimal mode")
	pointer = memory.readdword(pointerAddr[game])
	UpdateTab()
	currentRNG = memory.readdword(RNGAddr[game])
	distanceseed = getSeedDistance(currentRNG)
	if distanceseed>30000 or distanceseed<-1000 then
	  baseRNGseed=testingseed_forRNG
	  distanceseed = getSeedDistance(currentRNG)
	  if distanceseed>30000 or distanceseed<-1000 then
	     baseRNGseed=currentRNG
		 distanceseed=0
	  end
	  analyze(baseRNGseed, 0)
	  shifted_baseRNG=baseRNGseed
	  shifted_baseRNG_count=0
	end
	gui.text(0,10,"Dist seed: " .. distanceseed, "#FFFF00A0")
	gui.text(0,160,"Press 3 or 4 to leave mode")
  end
  
end

gui.register(fn)

--while false do
   --if autofire then
     -- if emu.framecount()%4==0 or emu.framecount()%4==1 then
	   -- joypad.set(buttons1)
     -- else
	   -- joypad.set(buttons2)
	 -- end	
    --end
  -- gui.text(120,0,"hello")
 --  emu.frameadvance()
--end