Player (208)
Joined: 7/7/2006
Posts: 798
Location: US
EDIT: Apparently the problem was a bad rom version, it still seems strange to me that it could occur on any rom unless the bad rom was accessing something in the emulator it should not have been. No further issues, but still an interesting predicament. When brute forcing an outcome by inserting idle frames in various locations, the RNG result obtained while using a script does not sync with the emulated result of the same input. There is a possibility I just suck at coding, but it really seems to be a functionality or game related issue. I was recently contacted for some assistance in lua scripting the first portion of Pokemon Red, where idle frames need to be inserted in various locations in order to make the Trainer ID Low Byte $76 for a glitch. I wrote the script, and I have checked the input thoroughly to see that it seems doing exactly what I want it to. If I manually interrupt the lua script during an outcome and play the movie back, it does not sync. The bytes on the screen do not match what they do when I make the movie by inserting waits manually, and I get a desync. I have done scripting similar to this for Megaman Battle Network and never had anything like this occur. Could it be a problem with lua not accurately saving/loading factors relating to the sporadic RNG of this game? The following is the optimal input: -Wait1 356:A -Wait2 (waiting one or more frames here will make the game lag for 1 frame on the next input) 376:A -Wait3 560:A 677:down -Wait4 680:A 704:left 705:down 706:right 707:down 708:right 709:B -Wait5 766:A The script is currently setup to place the savestate on frame zero. If the savestate is moved to another location, other incorrect values are achieved. The first iteration of no wait seems accurate all (most of?) the time. Any other value based on the loaded state is wrong. I have made it output to a file and display on the screen for convenience. The first four results should be 92, 51, 27, 23. Beyond 27 does not sync with the savestate in this position. This thread is not about how mediocre my coding skills are. My code is probably inefficiently written and much overstated. I did my best to make it presentable. I had the script running without so much beginning/end time, but it's easier to troubleshoot when watching this way. If there are any errors in my code causing problems please let me know, but I did do my best to troubleshoot any problems that could be occurring. Pokemon Red (Super Gameboy) starting from frame 0:
local tempstate = {}
local Maxframewait  --Most frames to wait.
local value
local i
local Currentframewait -- Frames waited by current loop.
local Bestframewait -- Frames waited by best solution so far.
local TrainerIDLowByte

local wait1
local wait2
local wait3
local wait4
local wait5

moviefile = "FrameDump.vbm"  --Output frame counts to a small text file.
dumpfile = moviefile..".dump"
io.output(dumpfile)

value = 0
tempstate[value] = savestate.create()  --tempstate0 = base state

value = 1
tempstate[value] = savestate.create()  --tempstate1 = optimal state

value = 0
savestate.save(tempstate[value])

value = 1
savestate.save(tempstate[value])

-------------------
TrainerIDLowByte = 0xD35A
Maxframewait = 3 -- change this to run longer.  If you go much higher than 10 or so, the script may take quite a while.
Bestframewait = 1000  --arbitrary high number, just used as a comparison to start with.
-------------------

for wait1 = 0,Maxframewait do
for wait2 = 0,Maxframewait do
for wait3 = 0,Maxframewait do
for wait4 = 0,Maxframewait do
for wait5 = 0,Maxframewait do

Currentframewait = (wait1 + wait2 + wait3 + wait4 + wait5)
if wait2 > 0 then
Currentframewait = Currentframewait + 1 --There is a lag frame if wait2>0
end


if Currentframewait <= Maxframewait then
-- Lots of arbitrary loops that get skipped
	value = 0
	savestate.load(tempstate[value])
	
	for i=1,351 do
	vba.frameadvance()
	end
	
	vba.frameadvance()
	vba.frameadvance()
	vba.frameadvance()
	vba.frameadvance()

	----Commands go here-----------

	for i=0,wait1 do
	vba.frameadvance()
	end
	
	joypad.set(1,{["A"]=true})  --356
	
	for i=1,19 do
	vba.frameadvance()
	end
	
	for i=0,wait2 do
	vba.frameadvance()
	end
	
	joypad.set(1,{["A"]=true})  --376

	if wait2>0 then           --There is a lag frame if wait2>0
	vba.frameadvance()
	end
	
	for i=1,183 do
	vba.frameadvance()
	end
	
	for i=0,wait3 do
	vba.frameadvance()
	end	
	
	joypad.set(1,{["A"]=true})  --560
	
	for i=1,117 do
	vba.frameadvance()
	end
	
	joypad.set(1,{["down"]=true}) --677
	
	for i=1,2 do
	vba.frameadvance()
	end
	
	for i=0,wait4 do
	vba.frameadvance()
	end
	
	joypad.set(1,{["A"]=true})  --680
	
	for i=1,24 do
	vba.frameadvance()
	end
	
	joypad.set(1,{["left"]=true})
	vba.frameadvance()
	joypad.set(1,{["down"]=true})
	vba.frameadvance()
	joypad.set(1,{["right"]=true})
	vba.frameadvance()
	joypad.set(1,{["down"]=true})
	vba.frameadvance()
	joypad.set(1,{["right"]=true})
	vba.frameadvance()
	joypad.set(1,{["B"]=true})  --709
	vba.frameadvance()
	
	for i=1,55 do
	vba.frameadvance()
	gui.text(0,0,"Best=" .. Bestframewait)
	end
	
	for i=0,wait5 do
	vba.frameadvance()
	end
	
	joypad.set(1,{["A"]=true})
	
	for i=1,200 do
	vba.frameadvance()
	gui.text(0,0,"ID=" .. memory.readbyte(TrainerIDLowByte))
	end	
	
	------------------------------------------------
	io.write(wait1)
	io.write(" ")
	io.write(wait2)
	io.write(" ")
	io.write(wait3)
	io.write(" ")
	io.write(wait4)
	io.write(" ")
	io.write(wait5)
	io.write(" ")
	io.write(memory.readbyte(TrainerIDLowByte))
	io.write("\n")
	
	
	
	if memory.readbyte(TrainerIDLowByte) == 118 then  --$76 converted to decimal
		--io.write(wait1, " ", wait2, " ", wait3, " ", wait4, " ", wait5, "\n")
		if Currentframewait < Bestframewait then
			Bestframewait = Currentframewait
			value = 1
			savestate.save(tempstate[value])
		end
	end
	
	
	
end --End "if Currentframewait <= Maxframewait"
	
end
end
end
end
end

	value = 1
        savestate.load(tempstate[value])
	gui.text(0,0,"Best Wait " .. Bestframewait)
	vba.pause()
--- --- --- (This is now being used as Kirkq's code dump.)
--Start on frame 31872

local tempstate = {}
local value
local BossHP = 0x7E2287
local TotalHP = 465
local Break
local Success

local a
local b
local x
local y
local st
local se
local u
local d
local l
local r
local lb
local rb

local at1  --temp variables
local bt1
local xt1
local yt1
local stt1
local set1
local ut1
local dt1
local lt1
local rt1
local lbt1
local rbt1

local at2
local bt2
local xt2
local yt2
local stt2
local set2
local ut2
local dt2
local lt2
local rt2
local lbt2
local rbt2

---------------------
moviefile = "FrameDump.smv"  --I'm going to have it output frame counts to a small text file.
dumpfile = moviefile..".dump"
io.output(dumpfile)
-- Makes a text file to output data.

value = 0
tempstate[value] = savestate.create()  --tempstate0 = base state

value = 1
tempstate[value] = savestate.create()  --tempstate1 = optimal state

value = 0
savestate.save(tempstate[value])

value = 1
savestate.save(tempstate[value])

Success = 0

snes9x.speedmode("maximum")

snes9x.pause()

---------------------
	
for st=1,3 do  --0 and 2 seem to do the same thing
for se=1,3 do
for lb=1,3 do
for rb=1,3 do
for u=1,3 do
for d=1,3 do
for l=1,3 do
for r=1,3 do
for a=1,3 do
for b=1,3 do
for x=1,3 do
for y=1,3 do

	value = 0
	savestate.load(tempstate[value])

--00
--01
--10
--11
	
	if a == 0 then
	at1 = nil
	at2 = nil
	elseif a == 1 then
	at1 = nil
	at2 = true
	elseif a == 2 then
	at1 = true
	at2 = nil
	elseif a == 3 then
	at1 = true
	at2 = true
	end
	
	if b == 0 then
	bt1 = nil
	bt2 = nil
	elseif b == 1 then
	bt1 = nil
	bt2 = true
	elseif b == 2 then
	bt1 = true
	bt2 = nil
	elseif b == 3 then
	bt1 = true
	bt2 = true
	end
	
	if x == 0 then
	xt1 = nil
	xt2 = nil
	elseif x == 1 then
	xt1 = nil
	xt2 = true
	elseif x == 2 then
	xt1 = true
	xt2 = nil
	elseif x == 3 then
	xt1 = true
	xt2 = true
	end
	
	if y == 0 then
	yt1 = nil
	yt2 = nil
	elseif y == 1 then
	yt1 = nil
	yt2 = true
	elseif y == 2 then
	yt1 = true
	yt2 = nil
	elseif y == 3 then
	yt1 = true
	yt2 = true
	end

	if stt == 0 then
	stt1 = nil
	stt2 = nil
	elseif st == 1 then
	stt1 = nil
	stt2 = true
	elseif st == 2 then
	stt1 = true
	stt2 = nil
	elseif st == 3 then
	stt1 = true
	stt2 = true
	end

	if se == 0 then
	set1 = nil
	set2 = nil
	elseif y == 1 then
	set1 = nil
	set2 = true
	elseif se == 2 then
	set1 = true
	set2 = nil
	elseif se == 3 then
	set1 = true
	set2 = true
        end	

	if u == 0 then
	ut1 = nil
	ut2 = nil
	elseif u == 1 then
	ut1 = nil
	ut2 = true
	elseif u == 2 then
	ut1 = true
	ut2 = nil
	elseif u == 3 then
	ut1 = true
	ut2 = true
	end

	if d == 0 then
	dt1 = nil
	dt2 = nil
	elseif d == 1 then
	dt1 = nil
	dt2 = true
	elseif d == 2 then
	dt1 = true
	dt2 = nil
	elseif d == 3 then
	dt1 = true
	dt2 = true
	end

	if l == 0 then
	lt1 = nil
	lt2 = nil
	elseif l == 1 then
	lt1 = nil
	lt2 = true
	elseif l == 2 then
	lt1 = true
	lt2 = nil
	elseif l == 3 then
	lt1 = true
	lt2 = true
	end

	if r == 0 then
	rt1 = nil
	rt2 = nil
	elseif r == 1 then
	rt1 = nil
	rt2 = true
	elseif r == 2 then
	rt1 = true
	rt2 = nil
	elseif r == 3 then
	rt1 = true
	rt2 = true
	end
	
	if lb == 0 then
	lbt1 = nil
	lbt2 = nil
	elseif lb == 1 then
	lbt1 = nil
	lbt2 = true
	elseif lb == 2 then
	lbt1 = true
	lbt2 = nil
	elseif lb == 3 then
	lbt1 = true
	lbt2 = true
	end
	
	if rb == 0 then
	rbt1 = nil
	rbt2 = nil
	elseif rb == 1 then
	rbt1 = nil
	rbt2 = true
	elseif rb == 2 then
	rbt1 = true
	rbt2 = nil
	elseif rb == 3 then
	rbt1 = true
	rbt2 = true
	end
	
	
	joypad.set(1,{["A"]=at1,["B"]=bt1,["X"]=xt1,["Y"]=yt1,["start"]=stt1,["select"]=set1,["up"]=ut1,["down"]=dt1,["left"]=lt1,["right"]=rt1,["L"]=lbt1,["R"]=rbt1})
	snes9x.frameadvance();
	joypad.set(1,{["A"]=at2,["B"]=bt2,["X"]=xt2,["Y"]=yt2,["start"]=stt2,["select"]=set2,["up"]=ut2,["down"]=dt2,["left"]=lt2,["right"]=rt2,["L"]=lbt2,["R"]=rbt2})
	snes9x.frameadvance();
        snes9x.frameadvance();

------2 Button presses are complete.
-----Start Turn 1
Break = 0

    for i=1,131 do
	snes9x.frameadvance()
    end
    
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    snes9x.frameadvance()
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    
     for i=1,43 do
	snes9x.frameadvance()
     end  

    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    snes9x.frameadvance()
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    
    for i=1,160 do
    snes9x.frameadvance()
    end
    
if memory.readword(BossHP) > TotalHP - 130 then
	Break = 1
end

--Turn 2

if Break == 0 then
    
    for i=1,209 do
	snes9x.frameadvance()
    end
    
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    snes9x.frameadvance()
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    
     for i=1,45 do
	snes9x.frameadvance()
     end  
     
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    snes9x.frameadvance()
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    
    for i=1,230 do
    snes9x.frameadvance()
    end
    
    if memory.readword(BossHP) > TotalHP - 260 then
    Break = 2
    end
     
end

if Break == 0 then
    
    for i=1,27 do
    snes9x.frameadvance()
    end
    
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    snes9x.frameadvance()
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    
     for i=1,137 do
     snes9x.frameadvance()
     end  
     
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    snes9x.frameadvance()
    joypad.set(1,{["A"]=true})
    snes9x.frameadvance()
    
    for i=1,250 do
    snes9x.frameadvance()
    gui.text(0,0,"HP: " .. memory.readbyte(BossHP))
    gui.text(0,20,"Success: " .. Success)
    end

end    
 
    io.write(Break," ",memory.readword(BossHP)," ",a,b,x,y,st,se,u,d,l,r,lb,rb, "\n")
    
    if memory.readword(BossHP) == 0 then
    value = 1
    savestate.save(tempstate[value])
    Success = 1
    end
    

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

end   --loop ends
end
end
end
end
end
end
end
end
end
end
end

value= 1
savestate.load(tempstate[value])
	
	snes9x.pause()
local tempstate = {}
local Maxframewait  --Most frames to wait.
local value
local i
local Currentframewait -- Frames waited by current loop.
local Bestframewait -- Frames waited by best solution so far.
local TrainerIDLowByte

local wait1 
local wait2
local wait3
local HoldTrigger
local HoldTime

moviefile = "FrameDump.vbm"  --I'm going to have it output frame counts to a small text file.
dumpfile = moviefile..".dump"
io.output(dumpfile)
-- Makes a text file.

value = 0
tempstate[value] = savestate.create()  --tempstate0 = base state

value = 1
tempstate[value] = savestate.create()  --tempstate1 = optimal state

value = 0
savestate.save(tempstate[value])

value = 1
savestate.save(tempstate[value])

-------------------
EnemyHPAddress = 0xCFE7  --Updated
HoldTime = 15  --Time to hold A button for each alternate attempt.
Maxframewait = 16 -- If you go much higher than 20 or so, the script may take quite a while.
Bestframewait = 1000  --arbitrary high number, just used as a comparison to start with.
GoalHP = 0
-------------------

vba.pause()

--Start this on the exact frame 1 before you can hit A for "but it failed"

for wait1 = 0,Maxframewait do
for wait2 = 0,Maxframewait do
for wait3 = 0,Maxframewait do
for HoldTrigger = 0,3 do  -- 0 = Just waits 1 = Hold  2 = Lag Mash  3 = Lag Mash and Hold

--You can change that to for HoldTrigger = 1,3 1,2 0,2 or whatever to not repeat searches you've already done.

Currentframewait = (wait1 + wait2 + wait3)

if Currentframewait < Bestframewait then
if Currentframewait <= Maxframewait then
-- Lots of arbitrary loops that get skipped
   value = 0
   savestate.load(tempstate[value])

   ----Commands go here-----------

   for i=0,wait1 do
   vba.frameadvance()
   end
   
   joypad.set(1,{["A"]=true})  --but it failed
   
   for i=1,8 do
   vba.frameadvance()
   end
   
   for i=0,wait2 do
   vba.frameadvance()
   end
   
   joypad.set(1,{["A"]=true})  --click fight

   for i=1,7 do
   vba.frameadvance()
   end
   
   for i=0,wait3 do
   vba.frameadvance()
   end
   
   joypad.set(1,{["A"]=true})  --select attack

   if HoldTrigger == 1 then
      for i=1,HoldTime do
      joypad.set(1,{["A"]=true})
      vba.frameadvance()
      end
   elseif HoldTrigger >= 2 then
      if Currentframewait < (Bestframewait - 2) then
      if Currentframewait <= (Maxframewait-2) then
      
         for i=1,7 do
         vba.frameadvance()
         end
      
         joypad.set(1,{["A"]=true})
         
         if HoldTrigger == 3 then
            for i=1,HoldTime do
            joypad.set(1,{["A"]=true})
            vba.frameadvance()
            end
         end
         
         Currentframewait = Currentframewait + 2
      end
      end
   end
   
   for i=1,150 do
   vba.frameadvance()
   gui.text(0,0,"HP=" .. memory.readbyte(EnemyHPAddress))
   gui.text(0,20,"Best=" .. Bestframewait)
   
   gui.text(0,10,wait1)
   gui.text(10,10,wait2)
   gui.text(20,10,wait3)
   gui.text(30,10,HoldTrigger)
   
   
   end   
   
   ------------------------------------------------
   io.write(wait1)
   io.write(" ")
   io.write(wait2)
   io.write(" ")
   io.write(wait3)
   io.write(" ")
   io.write(HoldTrigger)
   io.write(" ")
   io.write(memory.readbyte(EnemyHPAddress))
   io.write("\n")
   
   
   
   if memory.readword(EnemyHPAddress) == GoalHP then
      --io.write(wait1, " ", wait2, " ", wait3, " ", wait4, " ", wait5, "\n")
      if Currentframewait < Bestframewait then
         Bestframewait = Currentframewait
         value = 1
         savestate.save(tempstate[value])
      end
   end
   
   
   
end --End "if Currentframewait <= Maxframewait"
end   
   
end
end
end
end

   value = 1
        savestate.load(tempstate[value])
   gui.text(0,20,"Best Wait " .. Bestframewait)
   gui.text(0,0,"Enemy HP=" .. memory.readbyte(EnemyHPAddress))
   vba.pause() 
Joined: 10/3/2005
Posts: 1332
Blah. Nevermind.
Player (42)
Joined: 12/27/2008
Posts: 873
Location: Germany
Well, it didn't desync for me. The script found some 6-frame loss inputs with the right byte. 0 0 0 5 1 118 0 0 4 0 2 118 0 0 4 2 0 118 0 0 3 2 1 118 0 0 6 0 0 118 I manually tested all of them and they worked.
Banned User
Joined: 5/31/2010
Posts: 30
Location: RIO DE JANEIRO (BR)
I like this
I am a determined person and not give up so easy. And better and getting used to because I will send many videos angry. I am Brazilian and not ever quit. (Though I actually rooting for Japan ^ ^)