1 2
7 8 9
MarbleousDave
He/Him
Player (13)
Joined: 9/12/2009
Posts: 1559
Yes. Yes I did. I found a way through. In fact, I got the TAS finished. It took me an entire day. Oh, I uploaded the gif images on Photobucket. Those were my two paths that didn't work as small Mario. So I get the Superball Flowers from the bonus games. World 1 was so easy. 2-1 sees a spike in difficulty. 2-2 is as equally hard as 2-1. 3-1 wasn't as hard, but 3-2 was kinda tricky. 4-1 was a gauntlet. 4-2 was so easy thanks to a well aimed bounce, it reduced backtracking in the level to none, skipping the most dangerous parts. 2-3 and 4-3 removed the invincibility stars as it was a game breaker in the shoot-'em-up environment.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
urawaza.in wrote:
◇リフト2  4-2の真中らへんにもリフトがある ◇ Lift 2 There is also a lift in the middle of 4-2
Where???? I only know an invisible coin block.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
I did lowscore because some guy requested it. http://dehacked.2y.net/microstorage.php/info/1267827518/lowscore%20sml%20testrun%2010110%20points.bk2 (Bizhawk 2.2, Super Mario Land v1.0) 10110 points: 2-3 10 points from score tallying. Goal pedestral can't be touched at 0 seconds left. 3-3 100 points from unavoidable coin near the beginning. 4-3 5000 poins from killing the cloud boss. 5000 points from killing Tatanga.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
I investigated for hidden lifts / blocks / ground tiles today. Here are the results: https://i.imgur.com/jqRb4jr.png
  • The game uses map patterns and reserves certain tiles for hidden content.
  • Certain "reserved" tiles are unused, in 3-3. --> put this on TCRF
  • In the two autoscrollers there is a wall of hidden blocks at the boss, respectively. --> put this on TCRF
  • Whoever made the map for VGMaps didn't know about certain blocks... (This is also the case for some of the Mario & Luigi Superstar Saga maps at VGMaps.)
  • There are no more invisible ground tiles aside from those in the middle of 2-2. And there is no lift in 4-2, so
    urawaza.in wrote:
    ◇リフト2  4-2の真中らへんにもリフトがある
    this is wrong.
Find hidden blocks or ground:
Language: Lua

foundit=false hiddentile = 0x5F -- invisible block that reveals a lift/1up/powerup invistile = 0x62 -- invisible ground in 2-2 address="script started" while true do if emu.framecount()%90==0 then address="" foundit=false for i=0x9800,0x9AFF,0x01 do if memory.read_u8(i) == hiddentile then foundit=true address=address .. "\n$"..string.format("%x",i) end end if not foundit then address="tile not found" end end gui.text(50,50,address, 0xFFFFF070) emu.frameadvance() end
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
I reproduced scroll glitch by using lua, to freeze enemies on the screen to create lag. Due to the lag, the scroll glitch happens (at a rare chance). The game skips a vertical row. This is what it looks like normally: But due to the glitch it is like this (notice the tree is gone): As a side-effect, the game still scrolls as far as it normally would, thus wrapping around the level. The bug happens because $FFE9 doesn't update after a lagframe occured. So in the end, it's a very interesting glitch but probably not so useful for TAS purposes. However, I secretly hope lagframes could lead to other more severe tricks.
Language: Lua

memory.usememorydomain("System Bus") local tbl={} while true do --freeze mario at the sky memory.write_u8(0xE201,0) --freeze enemies on the screen if emu.framecount()%3==0 then for i=1,10,1 do val= memory.read_u8(0xD100+16*i-16) if val ~= 255 and val~=0x0A and val~=0x0B and val~=0x49 then if tbl[i]==nil then tbl[i]=true end end end elseif emu.framecount()%3==1 then count=0 for p=1,table.getn(tbl),1 do if tbl[p]==true then memory.write_u8(0xD100+16*p-16+3,40) -- x memory.write_u8(0xD100+16*p-16+2,20+p*12) -- y end count=count+1 if count>5 then break end end tbl={} end emu.frameadvance() end
I will try to record a movie file without lua/cheat.
Joined: 11/14/2016
Posts: 4
Nice!
Alyosha
He/Him
Editor, Emulator Coder, Expert player (3808)
Joined: 11/30/2014
Posts: 2828
Location: US
Nice work! one long unexplained bug figured out!
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
Alyosha wrote:
Nice work! one long unexplained bug figured out!
I wouldn't say that. It's still a very rare bug, I haven't been able to do it without lua yet. $FFE9 does normally update even during lagframes. Only in 0.1% of cases, it doesn't and we need to figure out why.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
Investigating the map bug further... $FFEA is 0 normally and becomes 1 every few pixels you move to the right. The contents of $FFEA are added to $FFE9. When $FFEA is 1, $FFE9 is updated. $FFE9 controls which column of the map is loaded next. I used Bizhawk tracelog to compare two scenarios. I'm not very good at assembly, but I highlighted everything that has to do with the two addresses.
normal frame ($FFE9 is updated)---bug frame ($FFE9 not updated)
0AFF:--20--F7--JR--NZ,0AF8h--A:ff--Cy:1861108572 0AF8:--7E--LD--A,(HL)--A:ff--Cy:1861108584 0AF9:--FE--FF--CP--#FFh--A:ff--Cy:1861108592 0AFB:--20--05--JR--NZ,0B02h--A:ff--Cy:1861108600 (...) 06B4:--7E--LD--A,(HL)--A:01--Cy:1861110032 06B5:--A7--AND--A--A:00--Cy:1861110040 06B6:--C8--RET--Z--A:00--Cy:1861110044 0296:--76--HALT--A:00--Cy:1861110064 0040:--C3--60--00--JP--#0060h--A:00--Cy:1861117772 0060:--F5--PUSH--AF--A:00--Cy:1861117788 0061:--C5--PUSH--BC--A:00--Cy:1861117804 0062:--D5--PUSH--DE--A:00--Cy:1861117820 0063:--E5--PUSH--HL--A:00--Cy:1861117836 0064:--CD--58--22--CALL--#2258h--A:00--Cy:1861117852 2258:--F0--EA--LDH--A,(#FFEAh)--A:00--Cy:1861117876 225A:--FE--01--CP--#01h--A:01--Cy:1861117888 225C:--C0--RET--NZ--A:01--Cy:1861117896 225D:--F0--E9--LDH--A,(#FFE9h)--A:01--Cy:1861117904 225F:--6F--LD--L,A--A:5a--Cy:1861117916 2260:--3C--INC--A--A:5a--Cy:1861117920 2261:--FE--60--CP--#60h--A:5b--Cy:1861117924 2263:--20--02--JR--NZ,2267h--A:5b--Cy:1861117932 2267:--E0--E9--LDH--(#FFE9h),A--A:5b--Cy:1861117944 2269:--26--98--LD--H,#98h--A:5b--Cy:1861117956 226B:--11--B0--C0--LD--DE,#C0B0h--A:5b--Cy:1861117964 226E:--06--10--LD--B,#10h--A:5b--Cy:1861117976 2270:--E5--PUSH--HL--A:5b--Cy:1861117984 (...) 22A0:--D1--POP--DE--A:2c--Cy:1861121476 22A1:--05--DEC--B--A:2c--Cy:1861121488 22A2:--20--CC--JR--NZ,2270h--A:2c--Cy:1861121492 22A4:--3E--02--LD--A,#02h--A:2c--Cy:1861121500 22A6:--E0--EA--LDH--(#FFEAh),A--A:02--Cy:1861121508 22A8:--C9--RET--A:02--Cy:1861121520 0067:--CD--86--1B--CALL--#1B86h--A:02--Cy:1861121536 1B86:--AF--XOR--A--A:02--Cy:1861121560 1B87:--EA--E2--C0--LD--(#C0E2h),A--A:00--Cy:1861121564 (...) 0030:--56--LD--D,(HL)--A:00--Cy:1861123776 0031:--D5--PUSH--DE--A:00--Cy:1861123784 0032:--E1--POP--HL--A:00--Cy:1861123800 0033:--E9--JP--(HL)--A:00--Cy:1861123812 0627:--CD--98--21--CALL--#2198h--A:00--Cy:1861123816 2198:--F0--EA--LDH--A,(#FFEAh)--A:00--Cy:1861123840 219A:--A7--AND--A--A:02--Cy:1861123852 219B:--20--EB--JR--NZ,2188h--A:02--Cy:1861123856 2188:--3E--03--LD--A,#03h--A:02--Cy:1861123868 218A:--E0--EA--LDH--(#FFEAh),A--A:03--Cy:1861123876 218C:--F0--A4--LDH--A,(#FFA4h)--A:03--Cy:1861123888 218E:--47--LD--B,A--A:f9--Cy:1861123900 218F:--FA--AA--C0--LD--A,(#C0AAh)--A:f9--Cy:1861123904 2192:--B8--CP--B--A:f8--Cy:1861123920 2193:--C8--RET--Z--A:f8--Cy:1861123924 2194:--AF--XOR--A--A:f8--Cy:1861123932 2195:--E0--EA--LDH--(#FFEAh),A--A:00--Cy:1861123936 2197:--C9--RET--A:00--Cy:1861123948 062A:--CD--4E--08--CALL--#084Eh--A:00--Cy:1861123964 084E:--F0--9C--LDH--A,(#FF9Ch)--A:00--Cy:1861123988 0850:--A7--AND--A--A:00--Cy:1861124000 (...) 06B4:--7E--LD--A,(HL)--A:02--Cy:1861174368 06B5:--A7--AND--A--A:00--Cy:1861174376 06B6:--C8--RET--Z--A:00--Cy:1861174380 0296:--76--HALT--A:00--Cy:1861174400 6C51:--FE--03--CP--#03h--A:01--Cy:1860406336 6C53:--20--10--JR--NZ,6C65h--A:01--Cy:1860406344 6C65:--E5--PUSH--HL--A:01--Cy:1860406356 6C66:--7D--LD--A,L--A:01--Cy:1860406372 (...) 0030:--56--LD--D,(HL)--A:00--Cy:1860409752 0031:--D5--PUSH--DE--A:00--Cy:1860409760 0032:--E1--POP--HL--A:00--Cy:1860409776 0033:--E9--JP--(HL)--A:00--Cy:1860409788 0627:--CD--98--21--CALL--#2198h--A:00--Cy:1860409792 2198:--F0--EA--LDH--A,(#FFEAh)--A:00--Cy:1860409816 219A:--A7--AND--A--A:01--Cy:1860409828 219B:--20--EB--JR--NZ,2188h--A:01--Cy:1860409832 2188:--3E--03--LD--A,#03h--A:01--Cy:1860409844 218A:--E0--EA--LDH--(#FFEAh),A--A:03--Cy:1860409852 218C:--F0--A4--LDH--A,(#FFA4h)--A:03--Cy:1860409864 218E:--47--LD--B,A--A:f9--Cy:1860409876 218F:--FA--AA--C0--LD--A,(#C0AAh)--A:f9--Cy:1860409880 2192:--B8--CP--B--A:f8--Cy:1860409896 2193:--C8--RET--Z--A:f8--Cy:1860409900 2194:--AF--XOR--A--A:f8--Cy:1860409908 2195:--E0--EA--LDH--(#FFEAh),A--A:00--Cy:1860409912 2197:--C9--RET--A:00--Cy:1860409924 062A:--CD--4E--08--CALL--#084Eh--A:00--Cy:1860409940 084E:--F0--9C--LDH--A,(#FF9Ch)--A:00--Cy:1860409964 0850:--A7--AND--A--A:00--Cy:1860409976 (...) 2D02:--1A--LD--A,(DE)--A:20--Cy:1860415488 2D03:--22--LD--(HL+),A--A:27--Cy:1860415496 2D04:--13--INC--DE--A:27--Cy:1860415504 0040:--C3--60--00--JP--#0060h--A:27--Cy:1860415532 0060:--F5--PUSH--AF--A:27--Cy:1860415548 0061:--C5--PUSH--BC--A:27--Cy:1860415564 0062:--D5--PUSH--DE--A:27--Cy:1860415580 0063:--E5--PUSH--HL--A:27--Cy:1860415596 0064:--CD--58--22--CALL--#2258h--A:27--Cy:1860415612 2258:--F0--EA--LDH--A,(#FFEAh)--A:27--Cy:1860415636 225A:--FE--01--CP--#01h--A:00--Cy:1860415648 225C:--C0--RET--NZ--A:00--Cy:1860415656 0067:--CD--86--1B--CALL--#1B86h--A:00--Cy:1860415676 1B86:--AF--XOR--A--A:00--Cy:1860415700 1B87:--EA--E2--C0--LD--(#C0E2h),A--A:00--Cy:1860415704 (...) 0030:--56--LD--D,(HL)--A:00--Cy:1860475292 0031:--D5--PUSH--DE--A:00--Cy:1860475300 0032:--E1--POP--HL--A:00--Cy:1860475316 0033:--E9--JP--(HL)--A:00--Cy:1860475328 0627:--CD--98--21--CALL--#2198h--A:00--Cy:1860475332 2198:--F0--EA--LDH--A,(#FFEAh)--A:00--Cy:1860475356 219A:--A7--AND--A--A:00--Cy:1860475368 219B:--20--EB--JR--NZ,2188h--A:00--Cy:1860475372 219D:--F0--A4--LDH--A,(#FFA4h)--A:00--Cy:1860475380 219F:--E6--08--AND--#08h--A:fa--Cy:1860475392 21A1:--21--A3--FF--LD--HL,#FFA3h--A:08--Cy:1860475400 21A4:--BE--CP--(HL)--A:08--Cy:1860475412 21A5:--C0--RET--NZ--A:08--Cy:1860475420 062A:--CD--4E--08--CALL--#084Eh--A:08--Cy:1860475440 084E:--F0--9C--LDH--A,(#FF9Ch)--A:08--Cy:1860475464 0850:--A7--AND--A--A:00--Cy:1860475476 (...) 089E:--E0--A2--LDH--(#FFA2h),A--A:4e--Cy:1860476528 08A0:--3E--02--LD--A,#02h--A:4e--Cy:1860476540 08A2:--80--ADD--A,B--A:02--Cy:1860476548 08A3:--E0--8F--LDH--(#FF8Fh),A--A:53--Cy:1860476552
Some things I can notice:
  • $2198 is executed twice in the bug scenario, only once in the normal scenario.
  • Execution of $2258~onwards is cut short in the bug scenario, skipping $225D and $2267.
Any explanations are welcome. -- <mugg> bug frame: https://paste.ofcode.org/WR5WcaaZEMEHAMMPPKjsXB <mugg> normal frame: https://paste.ofcode.org/adQuG4xEupGa4kAdVbyFMj In contrast to the two pastes above, these two start at the same ROM location: different bug scenario https://paste.ofcode.org/yNXGHYdfWMbTKjHrbP6WVL different normal scenario https://paste.ofcode.org/i6jJT9BA5fTiFbSKgVK2VM (They are the same for the first 370 lines.) Note: These pastes expire in one week from now.
Alyosha
He/Him
Editor, Emulator Coder, Expert player (3808)
Joined: 11/30/2014
Posts: 2828
Location: US
From the Bug Frame:
2D02:--1A--LD--A,(DE)--A:20--Cy:1860415488
2D03:--22--LD--(HL+),A--A:27--Cy:1860415496
2D04:--13--INC--DE--A:27--Cy:1860415504
0040:--C3--60--00--JP--#0060h--A:27--Cy:1860415532 
0040 is the VBlank interrupt address. It looks like it's occurring in the middle of some other operation. I wouldn't be surprised if this has something to do with the bug. EDIT: One other thing I noticed about this level is that in several places sprites pass through the status bar area.There is a LY=LYC interrupt that occurs at the edge of the status bar that checks for when drawing is finished, and sprites passing through this area can delay it by several cycles. This effect is not emulated by any emulator yet. If the glitch is due to some obscure cycle timing issue, it may not yet be possible to reproduce it on emulator during normal play.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
Alyosha wrote:
This effect is not emulated by any emulator yet.
Which effect? Is it visual? In Arkanias566's video, no sprites pass through the top status bar at the time the glitch is occuring. (The glitch happens when you can see the crack in the pattern right underneath the status bar.) (EDIT: Arkanias also encountered the bug when he played on BGB 1.5.1. And BGB and Gambatte are close in accuracy. In other words, if it works on BGB, why shouldn't it on Gambatte without the lua hack.) Question: What determines when $0040 should be executed? ___ By now, I think the bug might be dependent on the enemies you killed throughout the level. Some information pertaining the killed enemies is not cleared in the RAM and I noticed the bug happens more often in certain scenarios, and doesn't in others.
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
OK, so looking at a few traces of what's happened: $FFEA appears to be an address responsible for controlling some sort of loading routine. Part of this routine can only run during vblank. As such, the value normally moves through a few states: 0: normal 1: loading required 2: vblank portion of loading finished 3: loading finished The value goes from 3 back down to 0, resetting the loading sequence, whenever FFA4 and C0AA differ. (According to MUGG, these values are related to the character's position, one directly, one modulo 8, which makes a lot of sense.) Now, the loading process is meant to go 0→1→2→3 and back to 0, but the code doesn't actually enforce this. What actually happens is that the game sets the value from 0 to 1, some time later waits for an interrupt, then if the value is nonzero, sets it to 3. In other words, the code is assuming that the interrupt that it waited for is the vblank interrupt (which would set the 1 to 2 and do the vblank-critical part of the loading routine; this part of the routine is also what sets $FFE9). This "if the value is nonzero" test is not done immediately after the interrupt ends; it's done fairly late in the computation for that frame. However, the vblank interrupt isn't the only interrupt used by the code. There's also a timer interrupt (which is apparently used for, at least, playing the background music). When this interrupt happens, it satisfies the "wait for an interrupt" requirement in the code, even though the interrupt in question is not vblank. Normally, this doesn't matter; the code runs for quite a while before doing the 2→3 part of the loading sequence, so the odds of a vblank happening by chance before that part starts are very high (guaranteed under normal circumstances because the game's processing normally waits on vblanks, as is the case in most games, so the game's code normally runs at a consistent time relative to vblank). However, what if we had a lag frame recently? In that case, a vblank happened "before the code was ready", and it's possible (and actually observed in the "bug frames") for the vblank to happen right before $FFEA gets set from 0 to 1. Now, suppose a timer interrupt happens to happen right after; that will fulfil the requirement of waiting for an interrupt, so the code for the next frame starts running "early". (You could call this an "antilag" frame; instead of the code running late after vblank, it's running early before vblank.) If the timer interrupt happens quickly enough, the game manages to run all the way through to the 2→3 part of the loading sequence before the next vblank occurs, and runs it even though $FFEA isn't set to 2 (it's set to 1, which is nonzero, all the code was looking for). That means that only the second half of the loading sequence has actually run. Then because $FFEA isn't 1 any more (it unconditionally gets set to 3), the first half of the loading sequence won't run and so permanently ends up not having been run. So the conditions for this to happen are a) a lag frame that happens to run to more or less exactly the right length past vblank (so that the check for loading being required happens just after vblank, not before like it should have been); b) loading actually being required on that frame; c) a timer interrupt (or possibly LCD status interrupt, although I haven't seen that in MUGG's traces) that happens while the game thinks it's waiting for vblank, and fools it into thinking that vblank has already happened. This seems fairly unlikely to happen by chance, which is presumably why the playtesters didn't find it and why it's such a rare glitch.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
I can't thank ais523 enough for his research! Today I finally managed to create a movie file without using the luascript. http://dehacked.2y.net/microstorage.php/info/1074552241/sml1%20bug.bk2 It syncs on both v1.0 and v1.1. ---------- I would like to investigate "respawning at checkpoints" now. You know why. The game seems to rely on $FFE5 (which is some sort of x-pos address) to determine where Mario should respawn. So I made another trace log, right before the screen fades white to respawn Mario. This is the frame where $FFE5 is checked. It actually seems $FFE5 is supposed to be read as 2-byte(?). Values of $FFE5~$FFE6 Frame1: 12 06 (Mario died and screen is about to turn white) Frame2: 0F 01 Frame3: 0F 0D (Screen white) Frame4: 10 04 Frame5: 10 07 Frame6: 10 07 Frame7: 10 08 (Visible) https://paste.ee/p/jlRIC (this is when transitioning from frame 1 to 2) I looked at line 3952, where it does something with FFE5. What I can understand:
save address "FFE5" to HL
(...)
load value from HL (FFE5: 0x12) to A
if A > 0 then decrement A by 1 (So A turns 0x11)
(...)
Do some operations(Not sure what's happening) and save the result to B (= 0x0F)
load contents of B to address in HL (FFE5 is now 0x0F)
Write 0x00 to FFE6
(...)
Later on, it saves value of FFE5 to A (= 0x0F)
Adds A to A (= 0x1E) and saves the value to E
(...?)
I would be happy to understand better what the game is doing. What operations is it doing to come up with the value in B (0x0F)? What is it doing with the value in E at the end?
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
The operations from 06F8 to 0734 (the second (...) in your post) appear to be a table lookup. They're comparing A (i.e. the old value of (FFE5)) to a range of different values, and setting the value of BC accordingly. (This took me a while to understand because there's a triple negative, e.g. the first test is saying "if subtracting 7 from the value does not borrow, do not continue", but with "borrow" expressed as "not carry"; no wonder it's confusing.) If A is less than or equal to 7h (7 decimal), BC is set to 030Ch (780 decimal). If A is less than or equal to Bh (11 decimal), BC is set to 0734h (1844 decimal). If A is less than or equal to Fh (15 decimal), BC is set to 0B5Ch (2908 decimal). If A is less than or equal to 15h (19 decimal), BC is set to 0F84h (3972 decimal). This table probably continues, but the rest of the table doesn't show in the trace because that's the case that was taken in the trace in question. At that point, the B half of BC is saved back in FFE5, and the code moves on to FFE6, which is zeroed (like in your trace). The C half is saved into C0AB, and the code moves onto a subroutine at 21B1 (which appears to be very long and complex and start with several block copy / block clear routines; this would suggest to me that it's a major loading routine, which wouldn't be surprising if it's called during the player respawning). C0AB doesn't seem to be used immediately, although several values near it are used, so it wouldn't surprise me if it's part of some sort of "this is where the player is" state. I'd strongly recommend at least putting a memory watch on C0AA and C0AB because they seem to be relevant here. 21BC is the first point at which the code gets back to FFE4/FFE5/FFE6 rather than large block copies, and is still inside the long and complex subroutine mentioned earlier. FFE6 is compared to zero; if it actually is zero (as it is in this case), then something fairly small/simple gets skipped (which doesn't show up in the trace because it was skipped). As such, I'd expect FFE6 to be related to "the reason the player respawned". It starts by looking at the memory address (4000 + twice the value in FFE4); 16 bits gets loaded from that memory address into DE (in a painfully indirect way because the Z80 doesn't have any instructions for doing that efficiently, e.g. it has to use all of A/D/E/H/L as temporaries, because addresses like A are useful for doubling a value by adding it to itself). So I assume there's some sort of array starting at 4000. The code then does something very similar again, adding twice the value in FFE5 to the value that was previously in DE (again, in a very indirect way with a bunch of register-shuffling); several consecutive values get read from the resulting address. In C-like pseudocode, we'd write that code something like this:
    extern byte*** a4000; // * = 16-bit pointer to an address
    byte *base = a4000[ffe4][ffe5];
That is, we're taking a hardcoded array that points to another set of arrays, and indexing into it twice to get a base pointer. That pointer's then used to read several values from memory which determine how the game loads from there. Given that we already know that FFE5 is set to 3, 7, B, or F, (and probably other values but the pattern likely continues, it's going up by 4 each time), my guess is that there's an 8-byte structure that contains values describing how a level checkpoint behaves, and several of these structures exist for any given level; presumably, the first structure describes the level spawn point. I'd also guess that ffe4 somehow specifies which level the player is currently playing (that's just a guess but you can probably confirm it with memory watch). The code logged here seems to make sense: there seem to be checkpoints at FFE5 = 7, B, F, etc., and if the player has gone sufficiently past them (i.e. to 8, A, 10 respectively), they'll respawn at that checkpoint. There's no immediate bug there that I can spot. There is something that's bothering me, though: with the part of the code seen in the trace, respawning at say, checkpoint 2 would subsequently put you back at checkpoint 1 if you died without moving from then on, something which the developers are moderately likely to have tested and which is probably undesirable. I have a suspicion, therefore, that the setting of FFE5 in the part of the trace you posted is used only to determine which checkpoint to respawn at, and some other part of the code sets the new value of FFE5. I further have a hunch that the respawn bug you saw is a consequence of the value in FFE5 somehow getting out of sync with the player's/camera's actual x coordinate. You might want to try to work out the relationship between those to see if there's anything unexpected there.
Alyosha
He/Him
Editor, Emulator Coder, Expert player (3808)
Joined: 11/30/2014
Posts: 2828
Location: US
Nice work MUGG and ais523 for figuring this one out. Too bad it's not very useful, but good luck on the checkpoint one!
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
Thanks ais523! I started working on a visualisation of frames. Maybe something like this will be helpful.
Language: Lua

console.clear() memory.usememorydomain("System Bus") client.SetGameExtraPadding(0,0,134,0) local MouseX = 0 local MouseY = 0 local clickedFrames = 0 local clicked = false local prevframe = emu.framecount() function arrowDown(xpos,ypos,col) gui.drawLine(xpos,ypos,xpos+6,ypos,col) gui.drawLine(xpos+1,ypos+1,xpos+5,ypos+1,col) gui.drawLine(xpos+2,ypos+2,xpos+4,ypos+2,col) gui.drawPixel(xpos+3,ypos+3,col) end function arrowUp(xpos,ypos,col) gui.drawLine(xpos,ypos,xpos+6,ypos,col) gui.drawLine(xpos+1,ypos-1,xpos+5,ypos-1,col) gui.drawLine(xpos+2,ypos-2,xpos+4,ypos-2,col) gui.drawPixel(xpos+3,ypos-3,col) end local addressList={ --address color note [1]={0x0040,0xFFA0A0A0,"VBLANK START"}, [2]={0x2258,0xFFFFE000,"READ FFEA"}, [3]={0x225D,0xFFFFE000,"READ FFE9"}, [4]={0x2267,0xFFFF7000,"UPDATE FFE9(+1)"}, [5]={0x2198,0xFFFFE000,"READ FFEA"}, [6]={0x218A,0xFFFF7000,"UPDATE FFEA(03)"}, [7]={0x2195,0xFFFF7000,"UPDATE FFEA(00)"}, [8]={0x22A6,0xFFFF7000,"UPDATE FFEA(02)"}, [9]={0x0067,0xFFA0A0A0,"0067"}, [10]={0x06E7,0xFF00E0FF,"FFFE5->HL"}, [11]={0x0723,0xFF0070FF,"UPDATE FFFE5"}, [12]={0x21D8,0xFF00E0FF,"READ FFE5"} } local addressListFrame={} local address=0 local col=0 local index=1 local ListOffset=1 local Mouse={} function text(x, y, text, color, backcolor) gui.drawText(x, y, text,color,backcolor,10,"Arial") end local addAddress=function(n) addressListFrame[index]=n index=index+1 end for n=1,table.getn(addressList) do address=addressList[n][1] color=addressList[n][2] label=addressList[n][3] event.onmemoryexecute(function() addAddress(n) end,address) end event.onframestart(function() addressListFrame={} ListOffset=1 end) event.onloadstate(function() addressListFrame={} ListOffset=1 end) while true do thisframe=emu.framecount() MouseX = input.getmouse().X MouseY = input.getmouse().Y clicked = input.getmouse().Left if clicked then clickedFrames = clickedFrames + 1 else clickedFrames = 0 end text(164,2,"FRAME " .. emu.framecount(),0xFFA060A0) n=1 for s=ListOffset,table.getn(addressListFrame) do z=addressListFrame[s] text(164,4+n*10,string.upper(string.format("%04x",addressList[z][1])),0xFFFFFFFF) text(190,4+n*10,addressList[z][3],addressList[z][2]) n=n+1 end if MouseX>280 and MouseX<290>130 and MouseY<138 then if clicked and clickedFrames%2==1 then if ListOffset<table>280 and MouseX<290>120 and MouseY<127>1 then ListOffset=ListOffset-1 end end arrowUp(282,123,0xFFFFFFFF) else arrowUp(282,123,0xA0FFFFFF) end text(281,104,ListOffset-1,0xFFE0E0E0) index=1 if client.ispaused() then gui.DrawFinish() emu.yield() else emu.frameadvance() end prevframe=thisframe clicked=false end
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
Looking at the third and last bug. That is the Star man crash. I tried to redo this bug in multiple sessions, but randomly playing and causing a lot of lag while starman invincibility runs out didn't do anything. But today, I suspected the bug might happen due to audio handling, so I froze
  • $DFE0 (new sfx) to 0x02 (= bullet sound) and
  • $DFE8 (new bgm) to 0x11 (= credits theme).
What this does is that it starts playing audio anew every frame. When I played with the addresses frozen like this, I managed to freeze the game a few times. The freeze always happened when the invincibility ran out and the game attempted to play the main level theme (but failed). It doesn't seem to be related to lag frames, but the rarity of the bug and timing/precision seems more or less similar to the map bug. ...Although the technicalities might be way different, idk... I try to do it without freezing the addresses now.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
Ok, probably nothing will come of this. But I made a script that kills Mario and pauses when he gets further into the level (=checkpoint bug happened). I will try in different places.
Language: Lua

console.clear() memory.usememorydomain("System Bus") function text(x, y, text, color, backcolor) gui.drawText(x, y, text,color,backcolor,10,"Arial") end local address={ mode=0xFFB3, mapx=0xFFE5, lives=0xDA15, deathtime=0xFFA6, marioy=0xC201 } local progress=memory.read_u8(address.mapx) local didsomething=false function dosomething() progress=memory.read_u8(address.mapx) memory.write_u8(address.deathtime,1) didsomething=true end while true do if memory.read_u8(address.deathtime)>0 then if not didsomething then dosomething() end end if memory.read_u8(address.mode)==0 and didsomething then if memory.read_u8(address.mapx)>progress then client.pause() print("success?") end memory.write_u8(address.marioy,0xB0) didsomething=false end if emu.framecount()%4==0 then memory.write_u8(address.lives,0x09) end keys=joypad.get() keys.Right=true keys.B=true joypad.set(keys) text(70,20,"mode: " .. memory.read_u8(address.mode) .. "\ndeathtime: " .. memory.read_u8(address.deathtime) .. "\nmap x: " .. memory.read_u8(address.mapx),0xFF00B000,0xFFffffff) emu.frameadvance() end
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
OK I have a new idea. Lag seems to be key, so let's make the game lag. But instead of using a script, I'd like to put something like a "for i=0,1000"-loop right inside the game ROM. Does it sound feasible? If you can help me with the opcodes, I'd be happy.
Joined: 3/4/2018
Posts: 2
Hello everybody! I plan on recording a TAS of this game using newer strategies and on a more accurate emulator as my first TAS project. If you guys have any warnings or advice, let me know.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
Hey there. As I replied to your inquiring PM, this game is a hell when it comes to bonus game manipulation. There are probably better choices for a first game to TAS out there. But you might also want to just do a test TAS, not worry too much about the manipulation, and see how it goes? Good luck!
Joined: 3/4/2018
Posts: 2
Yeah I’m probably going to record a TAS with no bonus game luck manip first, then go through the process of idle frame trial and error. Right now I am just researching about strats used already by RTA and TAS.
MESHUGGAH
Other
Skilled player (1917)
Joined: 11/14/2009
Posts: 1353
Location: 𝔐𝔞𝔤𝑦𝔞𝔯
MUGG wrote:
OK I have a new idea. Lag seems to be key, so let's make the game lag.
I've started to examine (more like trying to make a stab on) SML2. I'm going to post my finds here rather than the submission, as I'm not sure if these would save time in the final product. Short list of lag influencing routes for the game end glitch TAS in order of time required to reach it: 1. picking up shroom and destroying blocks by spin jump + the first shroom is located after the 2nd enemy (1st goomba, 2nd koopa) + fastest way is bumping the shroom block from under, jumping on the shroom and spin jumping (while falling down on the shrom) to the next block after picking it up 2. bringing a koopa shell and throwing it between the first two flowers + this section generates 1 lag frame only when throwing it at the right spot (depends on camera X pos primarily, Y pos and mario pos secondarily) - it takes ~70frames to bump under the first koopa and pick up the shell
PhD in TASing 🎓 speedrun enthusiast ❤🚷🔥 white hat hacker ▓ black box tester ░ censorships and rules...
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
MESHUGGAH wrote:
MUGG wrote:
OK I have a new idea. Lag seems to be key, so let's make the game lag.
I've started to examine (more like trying to make a stab on) SML2. I'm going to post my finds here rather than the submission, as I'm not sure if these would save time in the final product. Short list of lag influencing routes for the game end glitch TAS in order of time required to reach it: 1. picking up shroom and destroying blocks by spin jump + the first shroom is located after the 2nd enemy (1st goomba, 2nd koopa) + fastest way is bumping the shroom block from under, jumping on the shroom and spin jumping (while falling down on the shrom) to the next block after picking it up 2. bringing a koopa shell and throwing it between the first two flowers + this section generates 1 lag frame only when throwing it at the right spot (depends on camera X pos primarily, Y pos and mario pos secondarily) - it takes ~70frames to bump under the first koopa and pick up the shell
You should post in the SML2 topic. The game end glitch route requires you to go to the row of ?-blocks because one memory address used to pull off the glitch is based on your X-position. I don't see the credits warp working in any other location in the first level.
Editor, Expert player (2328)
Joined: 5/15/2007
Posts: 3930
Location: Germany
1 2
7 8 9