Expert player (3578)
Joined: 11/9/2007
Posts: 375
Location: Varberg, Sweden
First of all you MUST run faster than 13 pixels/frame at a 45 degree angle (the value 32 in the lua HUD), which means at least a speed of 3329. 4663 * sin(45) = 3297 so no it will not work from here, Sanic gotta go faster.
feos wrote:
Only Aglar can improve this now.
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
Guys... I want to explain why I call this glitch "monitor madness". Just a few days ago I was sure I was a very experienced Sonic TASer who knew the game very well. Then I saw Kiske's TAS. That TAS exploded my brain to a level, similar to what I felt after watching the famous bortreb's TAS of Pokemon Yellow the first time. Why? Because... I could maybe expect just some kind of a new strategy. New zip, for example. But what I saw was like a bomb. It destroyed all of my knowledge about the game's physics. A flat ground. A monitor. And Sonic running into it. Before that day I was 100% sure that there were no way to break that monitor without slowing down because of the RSC. What I saw looked crazy. I have no words other than "madness" or "insanity" to name that kind of thing. Because that thing had proved that Sonic game is just so complex that even very basic tricks are still discovered from time to time.
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
marzojr
He/Him
Experienced player (749)
Joined: 9/29/2008
Posts: 964
Location: 🇫🇷 France
Aglar wrote:
First of all you MUST run faster than 13 pixels/frame at a 45 degree angle (the value 32 in the lua HUD), which means at least a speed of 3329. 4663 * sin(45) = 3297 so no it will not work from here, Sanic gotta go faster.
Yeah, then it seems like it can't be done in this case; it doesn't seem possible to run up the slope, align to the side of the monitor for the "monitor madness" and keep enough speed to run up the next slope. Out of curiosity, what are the other requirements in terms of alignment?
Marzo Junior
Expert player (3578)
Joined: 11/9/2007
Posts: 375
Location: Varberg, Sweden
It's about skipping all pixels where the slope value is > 32. Just inch your way forward to find where it starts.
feos wrote:
Only Aglar can improve this now.
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
So basically we need to have such a combination of speed and alignment that allows us to skip 3 intervals in a row (when the space for alignment is very tiny)? 2 for the slopes and 1 for the ring box? Can’t we calculate explicitly the possibility of doing it and minimum required speed? I think it could be possible if you perform a perfect alignment and speed management way before that place, so you will minimize loss of speed. There should be a combination of speed and alignment allowing to “hit” the required position sequence, though it may require way too high speed =( (upd) I think it also makes sense to draw vertical boundaries of the areas that need to be skipped, to have a better visual control of your movement. (upd 2) I also considered the possibility of taking Amy’s route for Sonic. It would give Sonic extra boost from the slope before the loops, and we could accelerate to ~5600 sp/f, and finalize the stage like in the currently published TAS. I assigned that task for feeuzz, but I have no idea if he succeeded at it or not…
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
Expert player (3578)
Joined: 11/9/2007
Posts: 375
Location: Varberg, Sweden
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
Man, everytime you post a gmv or make a submission or just a comment, I have only 3 words to explain my feelings:
like a boss
Do you even realize yourself what you do? You’ve just accelerated to 5600+ without taking boost from the slope before the loops! I begin feeling that you can do anything to this game *_* Like:
<WST> hmm, is it possible to skip that wall?
<Aglar> take it
<WST> would be so nice to accelerate to 5600+
<Aglar> here it is
How if I ask you to accelerate to 6000 after those loops? Still possible? If not, where is the limit? In other words, if someone has to update Sonic 2 run, it should be you. Tee-N-Tee had years to do it, but still didn’t. I don’t want to claim that he’s worse, I just love seeing you doing things so much like a boss :) (upd) honestly, I am not that stupid and I see myself that your speed after the loops is dependant on the points which give you boost — like up-loop jump and down-loop jump in the first loop, then a series of rolling + small-jumps on every signle point allowing doing it. So I actually realize how you manage it, but it still impressive. Perfect alignment, friend, and now I do not have questions like before.
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
Active player (356)
Joined: 12/17/2013
Posts: 73
Location: Argentina
It does not support file <preditc> (For Sonic 1), with Sonic 2 ?. For predicting movement of the animal in the capsule. Because I have improved some zones but I get negative results despite improved weather in-game time, because frames is delayed because the animals are slower than in the previous and this complicates me much .. Too much to ask that compatibility for Sonic 2 is made?
Current Projects: Snic & Knuckles 3 - Knuckles 100% - AIZ2 Future Proyects: Genesis games GBx - GBA games
marzojr
He/Him
Experienced player (749)
Joined: 9/29/2008
Posts: 964
Location: 🇫🇷 France
I could sworn I had released one, but I can't seem to find it. The script is below; I have no recollection on how good or bad it is (it is that old). The major issue with animal manipulation in S2 is that you have very few opportunities to do so compared to S1: you can only manipulate them by adding or deleting boss explosions (which is annoying because you need to use something like TASMovieEditor or have to redo everything from the explosion to the capsule hit) or by deleting or adding additional animals. Both animals and boss explosions can be deleted by pausing a game so that the frame when the byte at FFFFFE0F has the low 3 bits clear (in RAM watch, make it a hex value, the rightmost digit must be 0 or 8). So pause right before, unpause right after. To add animals or explosions, you want to pause in such a way that these frames happen more often when the game is unpaused; for example, pausing right after them, and unpausing right before them. Anyway, the script:
Language: lua

local object_size = 0x40 local Object_RAM = 0xFFFFB000 local Dynamic_Object_RAM = Object_RAM + 16 * object_size -- Object SST constants. local render_flags = 0x1 local x_pos = 0x8 local y_pos = 0xC local x_vel = 0x10 local y_vel = 0x12 local mapping_frame = 0x1A local y_radius = 0x16 local x_radius = 0x17 local anim_frame_duration = 0x1E local routine = 0x24 local routine_secondary = 0x25 local animal_ground_routine_base = 0x30 local animal_ground_x_vel = 0x32 local animal_ground_y_vel = 0x34 -- A few important RAM locations. local RNG_seed = 0xFFFFF636 local Current_Zone = 0xFFFFFE10 local Vint_runcount = 0xFFFFFE0C local Collision_addr = 0xFFFFF796 local Level_Layout = 0xFFFF8000 local ColCurveMap = 0x00042D50 local ColArray = 0x00042E50 local Camera_X_pos = 0xFFFFEE00 local Camera_Y_pos = 0xFFFFEE04 -- Function to find the main capsule object local function find_capsule() for addr=Dynamic_Object_RAM,Object_RAM + 0x2000,object_size do if memory.readbyte(addr) == 0x3e and memory.readbyte(addr+routine) == 2 then return addr end end return nil end -- Function to enumerate all animals that matter for the capsule local function enum_animals() local animals = {} for addr=Dynamic_Object_RAM,Object_RAM + 0x2000,object_size do if memory.readbyte(addr)==0x28 and memory.readbyte(addr+routine) > 0 then table.insert(animals, addr) end end return animals end local function speed2color(speed, min, max) local green = math.floor(((speed - min) * 255) / (max - min)) local red = math.floor(((max - speed) * 255) / (max - min)) local blue, alpha = 0, 255 return {red, green, blue, alpha} end local minspd, maxspd = 0x140, 0x300 -- Names for animals. local animals = { [0]={"Rabbit" , speed2color(0x200, minspd, maxspd), -0x200, -0x400}, [1]={"Chicken" , speed2color(0x200, minspd, maxspd), -0x200, -0x300}, [2]={"Penguin" , speed2color(0x180, minspd, maxspd), -0x180, -0x300}, [3]={"Seal" , speed2color(0x140, minspd, maxspd), -0x140, -0x180}, [4]={"Pig" , speed2color(0x1C0, minspd, maxspd), -0x1C0, -0x300}, [5]={"Flicky" , speed2color(0x300, minspd, maxspd), -0x300, -0x400}, [6]={"Squirrel", speed2color(0x280, minspd, maxspd), -0x280, -0x380}, [7]={"Eagle" , speed2color(0x280, minspd, maxspd), -0x280, -0x300}, [8]={"Mouse" , speed2color(0x200, minspd, maxspd), -0x200, -0x380}, [9]={"Beaver" , speed2color(0x2C0, minspd, maxspd), -0x2C0, -0x300}, [10]={"Turtle" , speed2color(0x140, minspd, maxspd), -0x140, -0x200}, [11]={"Bear" , speed2color(0x200, minspd, maxspd), -0x200, -0x300}} -- Map between zone ID and animal names. local typelist = { [0]={[0]= 6, [1]= 5}, -- EHZ [1]={[0]= 6, [1]= 5}, -- Zone 1 [2]={[0]= 6, [1]= 5}, -- WZ [3]={[0]= 6, [1]= 5}, -- Zone 3 [4]={[0]= 9, [1]= 7}, -- MTZ [5]={[0]= 9, [1]= 7}, -- MTZ [6]={[0]= 9, [1]= 7}, -- WFZ [7]={[0]= 9, [1]= 7}, -- HTZ [8]={[0]= 8, [1]= 3}, -- HPZ [9]={[0]= 8, [1]= 3}, -- Zone 9 [10]={[0]= 2, [1]= 3}, -- OOZ [11]={[0]= 8, [1]= 1}, -- MCZ [12]={[0]=11, [1]= 5}, -- CNZ [13]={[0]= 0, [1]= 7}, -- CPZ [14]={[0]= 4, [1]= 1}, -- DEZ [15]={[0]= 2, [1]= 5}, -- ARZ [16]={[0]=10, [1]= 1}} -- SCZ -- Adddress of capsule switch in RAM. local main_capsule,capsule_body,capsule_switch = nil -- Internal variables. local seed = 0 local last_seed = -1 local last_vbla = -1 -- Lua version of the Sonic 2 random number generator. local function RandomNumber() local d1 = seed or 0x2A6D365A local d0 = d1 -- move.l d1,d0 d1 = SHIFT(d1, -2) -- asl.l #2,d1 d1 = d1 + d0 -- add.l d0,d1 d1 = SHIFT(d1, -3) -- asl.l #3,d1 d1 = d1 + d0 -- add.l d0,d1 d0 = OR(AND(d1, 0x0000FFFF), AND(d0, 0xFFFF0000)) -- move.w d1,d0 d1 = OR(SHIFT(AND(d1, 0x0000FFFF), -16), SHIFT(AND(d1, 0xFFFF0000), 16)) -- swap d1 d0 = OR(AND(d1 + d0, 0x0000FFFF), AND(d0, 0xFFFF0000)) -- add.w d1,d0 d1 = OR(SHIFT(AND(d0, 0x0000FFFF), -16), SHIFT(AND(d1, 0xFFFF0000), 16)) -- move.w d0,d1 \n swap d1 seed = d1 -- move.l d1,(RNG_seed).w return d0 end -- Lua version of the Sonic 2 function to find the nearest tile. local function Floor_ChkTile(objRender, objX, objY) -- move.w d2,d0 ; y_pos -- add.w d0,d0 -- andi.w #$F00,d0 ; rounded 2*y_pos -- move.w d3,d1 ; x_pos -- lsr.w #3,d1 -- move.w d1,d4 -- lsr.w #4,d1 ; x_pos/128 = x_of_chunk -- andi.w #$7F,d1 -- add.w d1,d0 ; d0 is relevant chunk ID now local d4 = SHIFT(objX, 3) local index = AND(AND(SHIFT(objY, -1), 0xF00) + AND(SHIFT(d4, 4), 0x7F),0xFFFF) -- moveq #-1,d1 -- clr.w d1 -- lea (Level_Layout).w,a1 -- move.b (a1,d0.w),d1 ; move 128*128 chunk ID to d1 local chunknum = memory.readbyte(Level_Layout + index) -- add.w d1,d1 -- move.w word_1E5D0(pc,d1.w),d1 -- move.w d2,d0 ; y_pos -- andi.w #$70,d0 -- add.w d0,d1 -- andi.w #$E,d4 ; x_pos/8 -- add.w d4,d1 local chunkaddr = 0xFFFF0000 + AND(memory.readword(0x1E5D0 + 2*chunknum) + AND(objY,0x70) + AND(d4, 0xE), 0xFFFF) -- movea.l d1,a1 ; address of block ID -- rts return chunkaddr end -- Lua version of the Sonic 2 secondary function to find the floor. local function FindFloor2(objRender, objX, objY, solidbit, delta, initangle, flipmask) local angle = initangle local tileaddr = Floor_ChkTile(objRender, objX, objY) -- bsr.s Floor_ChkTile local floordist = 0 local tile = memory.readword(tileaddr) -- move.w (a1),d0 \n move.w d0,d4 -- andi.w #$3FF,d0 \n beq.s loc_1E88A \n btst d5,d4 \n bne.s loc_1E898 local tileid = AND(tile, 0x3FF) if tileid ~= 0 and AND(tile, solidbit) ~= 0 then -- loc_1E898: local colptr = memory.readlong(Collision_addr) -- movea.l (Collision_addr).w,a2 local block = memory.readbyte(colptr + tileid) -- move.b (a2,d0.w),d0 if block == 0 then -- beq.s loc_1E88A -- loc_1E88A return 0xF - AND(objY, 0xF), tileaddr, angle end angle = memory.readbytesigned(ColCurveMap + block) -- lea (ColCurveMap).l,a2 \n move.b (a2,d0.w),(a4) block = SHIFT(block, -4) -- lsl.w #4,d0 local xcopy = objX -- move.w d3,d1 if AND(tile, BIT(0xA)) ~= 0 then -- btst #$A,d4 \n beq.s + xcopy = -objX-1 -- not.w d1 angle = -angle -- neg.b (a4) end -- + if AND(tile, BIT(0xB)) ~= 0 then --- btst #$B,d4 \n beq.s + angle = -0x80 - angle -- addi.b #$40,(a4) \n neg.b (a4) \n subi.b #$40,(a4) end -- + xcopy = AND(objX, 0xF) + block -- andi.w #$F,d1 \n add.w d0,d1 local colhgt = memory.readbytesigned(ColArray + xcopy) -- lea (ColArray).l,a2 \n move.b (a2,d1.w),d0 \n ext.w d0 tile = XOR(tile, flipmask) -- eor.w d6,d4 if AND(tile, BIT(0xB)) ~= 0 then -- btst #$B,d4 \n beq.s + colhgt = -colhgt -- neg.w d0 end -- + if colhgt == 0 then -- tst.w d0 \n beq.s loc_1E88A -- loc_1E88A return 0xF - AND(objY, 0xF), tileaddr, angle elseif colhgt < 0 then -- bmi.s loc_1E900 -- loc_1E900: local dist = AND(objY, 0xF) -- move.w d2,d1 \n andi.w #$F,d1 if dist + colhgt < 0 then -- add.w d1,d0 \n bpl.w loc_1E88A return -dist-1, tileaddr, angle -- not.w d1 \n rts end else local dist = AND(objY, 0xF) -- move.w d2,d1 \n andi.w #$F,d1 return 0xF - (dist + colhgt), tileaddr, angle -- add.w d1,d0 \n move.w #$F,d1 \n sub.w d0,d1 \n rts end end -- loc_1E88A: -- move.w #$F,d1 -- move.w d2,d0 -- andi.w #$F,d0 -- sub.w d0,d1 -- rts return 0xF - AND(objY, 0xF), tileaddr, angle end -- Lua version of the Sonic 2 function to find the floor. local function FindFloor(objRender, objX, objY, solidbit, delta, initangle, flipmask) local angle = initangle local tileaddr = Floor_ChkTile(objRender, objX, objY) -- bsr.s Floor_ChkTile local floordist = 0 local tile = memory.readword(tileaddr) -- move.w (a1),d0 \n move.w d0,d4 -- andi.w #$3FF,d0 \n beq.s loc_1E7E2 \n btst d5,d4 \n bne.s loc_1E7F0 local tileid = AND(tile, 0x3FF) if tileid ~= 0 and AND(tile, solidbit) ~= 0 then -- loc_1E7F0: local colptr = memory.readlong(Collision_addr) -- movea.l (Collision_addr).w,a2 local block = memory.readbyte(colptr + tileid) -- move.b (a2,d0.w),d0 \n andi.w #$FF,d0 if block == 0 then -- beq.s loc_1E7E2 -- loc_1E7E2 floordist, tileaddr, angle = FindFloor2(objRender, objX, objY + delta, solidbit, delta, initangle, flipmask) return floordist + 0x10, tileaddr, angle end angle = memory.readbytesigned(ColCurveMap + block) -- lea (ColCurveMap).l,a2 \n move.b (a2,d0.w),(a4) block = SHIFT(block, -4) -- lsl.w #4,d0 local xcopy = objX -- move.w d3,d1 if AND(tile, BIT(0xA)) ~= 0 then -- btst #$A,d4 \n beq.s + xcopy = -objX-1 -- not.w d1 angle = -angle -- neg.b (a4) end -- + if AND(tile, BIT(0xB)) ~= 0 then --- btst #$B,d4 \n beq.s + angle = -0x80 - angle -- addi.b #$40,(a4) \n neg.b (a4) \n subi.b #$40,(a4) end -- + xcopy = AND(objX, 0xF) + block -- andi.w #$F,d1 \n add.w d0,d1 local colhgt = memory.readbytesigned(ColArray + xcopy) -- lea (ColArray).l,a2 \n move.b (a2,d1.w),d0 \n ext.w d0 tile = XOR(tile, flipmask) -- eor.w d6,d4 if AND(tile, BIT(0xB)) ~= 0 then -- btst #$B,d4 \n beq.s + colhgt = -colhgt -- neg.w d0 end -- + if colhgt == 0 then -- tst.w d0 \n beq.s loc_1E7E2 -- loc_1E7E2 floordist, tileaddr, angle = FindFloor2(objRender, objX, objY + delta, solidbit, delta, initangle, flipmask) return floordist + 0x10, tileaddr, angle elseif colhgt < 0 then -- bmi.s loc_1E85E -- loc_1E85E: local dist = AND(objY, 0xF) -- move.w d2,d1 \n andi.w #$F,d1 if dist + colhgt < 0 then -- add.w d1,d0 \n bpl.w loc_1E7E2 -- loc_1E86A: floordist, tileaddr, angle = FindFloor2(objRender, objX, objY - delta, solidbit, delta, initangle, flipmask) return floordist - 0x10, tileaddr, angle end elseif colhgt == 0x10 then -- cmpi.b #$10,d0 \n beq.s loc_1E86A -- loc_1E86A: -- sub.w a3,d2 -- bsr.w FindFloor2 -- add.w a3,d2 -- subi.w #$10,d1 -- rts floordist, tileaddr, angle = FindFloor2(objRender, objX, objY - delta, solidbit, delta, initangle, flipmask) return floordist - 0x10, tileaddr, angle else -- move.w d2,d1 -- andi.w #$F,d1 -- add.w d1,d0 -- move.w #$F,d1 -- sub.w d0,d1 -- rts return 0xF - (AND(objY, 0xF) + colhgt), tileaddr, angle end end -- loc_1E7E2: -- add.w a3,d2 -- bsr.w FindFloor2 ; try tile below the nearest -- sub.w a3,d2 -- addi.w #$10,d1 ; return distance to floor -- rts floordist, tileaddr, angle = FindFloor2(objRender, objX, objY + delta, solidbit, delta, initangle, flipmask) return floordist + 0x10, tileaddr, angle end -- Lua version of the Sonic 2 function to find distance to the floor. local function ObjCheckFloorDist(objX, objY, objH, objR) --local objX = memory.readword(obj+x_pos) -- move.w x_pos(a0),d3 --local objY = memory.readword(obj+y_pos) -- move.w y_pos(a0),d2 --local objH = memory.readbytesigned(obj+y_radius) -- moveq #0,d0 \n move.b y_radius(a0),d0 \n ext.w d0 --local objR = memory.readbyte(obj+render_flags) --objY = objY + objH -- add.w d0,d2 -- lea (v_anglebuffer).w,a4 -- move.b #0,(a4) -- movea.w #$10,a3 -- move.w #0,d6 -- moveq #$D,d5 local floordist, tileaddr, angle = FindFloor(objR, objX, objY + objH, BIT(0xC), 0x10, 0, 0) -- bsr.w FindFloor if AND(angle, 1) ~= 0 then angle = 0 -- move.b (v_anglebuffer).w,d3 \n btst #0,d3 \n beq.s locret_14E4E \n move.b #0,d3 end return floordist, tileaddr, angle -- locret_14E4E: rts end -- Lua version of the Sonic 2 function to make an object "fall". local function ObjectMoveAndFall(objX, objY, objVX, objVY) --local memory.readlong(obj+x_pos) -- move.l x_pos(a0),d2 --local memory.readlong(obj+y_pos) -- move.l y_pos(a0),d3 --local memory.readwordsigned(obj+x_vel) -- move.w x_vel(a0),d0 \n ext.l d0 objX = AND(objX + SHIFT(objVX, -8), 0xFFFFFFFF) -- asl.l #8,d0 \n add.l d0,d2 --local memory.readwordsigned(obj+y_vel) -- move.w y_vel(a0),d0 \n ext.l d0 objY = AND(objY + SHIFT(objVY, -8), 0xFFFFFFFF) -- asl.l #8,d0 \n add.l d0,d3 objVY = objVY + 0x38 -- addi.w #$38,y_vel(a0) return objX, objY, objVX, objVY -- move.l d2,x_pos(a0) \n move.l d3,y_pos(a0) \n rts end -- Lua version of the Sonic 2 function loc_11ADE. local function animal_fall(objX, objY, objVX, objVY, objH, objR, objNVX, objNVY, vbla) -- tst.b render_flags(a0) -- bpl.w DeleteObject objX, objY, objVX, objVY = ObjectMoveAndFall(objX, objY, objVX, objVY) -- bsr.w ObjectMoveAndFall if objVY >= 0 then -- tst.w y_vel(a0) \n bmi.s + local floordist = ObjCheckFloorDist(SHIFT(objX, 16), SHIFT(objY, 16), objH, objR) -- jsr (ObjCheckFloorDist).l if floordist < 0 then -- tst.w d1 \n bpl.s + objY = objY + floordist -- add.w d1,y_pos(a0) objVX = objNVX -- move.w animal_ground_x_vel(a0),x_vel(a0) objVY = objNVY -- move.w animal_ground_y_vel(a0),y_vel(a0) -- move.b #1,mapping_frame(a0) -- move.b animal_ground_routine_base(a0),d0 -- add.b d0,d0 -- addq.b #4,d0 -- move.b d0,routine(a0) -- tst.b objoff_38(a0) -- beq.s + if AND(vbla, BIT(4)) ~= 0 then -- btst #4,(Vint_runcount+3).w \n beq.s + objVX = -objVX -- neg.w x_vel(a0) objR = XOR(objR, BIT(0)) -- bchg #0,render_flags(a0) end end end -- + -- bra.w DisplaySprite return objX, objY, objVX, objVY, objH, objR, objNVX, objNVY, vbla end local function simulate_animal_delay_fall_escape(obj, objX, objY, objVX, objVY, objNVX, objNVY, objWait, vbla, capX) local objH = 0xC local objR = 0x85 local objW = 8 local initvbla = vbla -- If we have a real object: if obj ~= nil then objX = memory.readlong(obj+x_pos) objY = memory.readlong(obj+y_pos) objVX = memory.readwordsigned(obj+x_vel) objVY = memory.readwordsigned(obj+y_vel) objNVX = memory.readwordsigned(obj+animal_ground_x_vel) objNVY = memory.readwordsigned(obj+animal_ground_y_vel) objWait = memory.readword(obj+0x36) - 1 end -- Compute time to get offscreen local le = SHIFT(Camera_X_pos - objW, -8) local re = SHIFT(Camera_X_pos + 320 + objW, -8) if objX <= le or objX >= re then return 0, vbla end -- Simulate wait if needed if objWait > 0 then vbla = vbla + objWait + 1 end -- Simulate falling while objVX == 0 do vbla = vbla + 1 objX, objY, objVX, objVY, objH, objR, objNVX, objNVY, vbla = animal_fall(objX, objY, objVX, objVY, objH, objR, objNVX, objNVY, vbla) end -- Lets use relative position here. objX = SHIFT(objX, 8) local lastvbla = vbla if objVX > 0 then vbla = vbla + math.abs(math.floor((re - objX + objVX - 1) / objVX)) + 1 else vbla = vbla + math.abs(math.floor((objX - le - objVX - 1) / -objVX)) + 1 end return objVX, vbla end function print_animal_objects(vbla) local animal_list = enum_animals() if #animal_list > 0 then row = 4 gui.drawtext(4, row, "Spawned animals:") row = row + 8 gui.drawtext(12, row, "Animal Wait D Exit at") row = row + 8 local capX = memory.readword(capsule_body+x_pos) local list1 = {} local list2 = {} for i,m in pairs(animal_list) do local ty = memory.readbyte(m+0x30) local delay = memory.readword(m+0x36) local vx, endvbla = simulate_animal_delay_fall_escape(m, nil, nil, nil, nil, nil, nil, nil, vbla, capX) local dir = (vx > 0 and ">") or "<" local endpt = movie.framecount() + endvbla - vbla + 1 if m < capsule_switch then endpt = endpt - 1 end table.insert((delay == 0 and list2) or list1, {endpt, function(rw) gui.drawtext(12, rw, string.format("%-8s %4d %s %7d", animals[ty][1], delay, dir, endpt), animals[ty][2]) end}) end table.sort(list1, function(item1, item2) return item1[1] < item2[1] end) table.sort(list2, function(item1, item2) return item1[1] < item2[1] end) for i,m in pairs(list1) do m[2](row) row = row + 8 end gui.drawtext(12, row, "========= Free =========") row = row + 8 for i,m in pairs(list2) do m[2](row) row = row + 8 end end end function predict_animals() -- Try to find a capsule main_capsule = find_capsule() if main_capsule == nil then -- If it was not found, so update variables and leave last_seed = memory.readlong(RNG_seed) last_vbla = memory.readbyte(Vint_runcount+3) return end capsule_body = 0xFFFF0000 + memory.readword(main_capsule+0x3C) capsule_switch = 0xFFFF0000 + memory.readword(main_capsule+0x38) -- Update random seed to RAM value seed = memory.readlong(RNG_seed) -- Capsule switch's routine counter local rout = memory.readbyte(main_capsule+routine_secondary) -- V-Int counter, used for pseudo-random numbers local vbla = memory.readbyte(Vint_runcount+3) -- Sometimes, the V-Int counter does not update; doing this "manual" -- update corrects the issue, which causes misprediction. if last_vbla == vbla then vbla = vbla + 1 end local savevbla = vbla -- Special case: if rout == 0 and memory.readword(capsule_switch+0x32) ~= 1 then -- Switch not pressed gui.drawtext(4, 4, "Capsule not broken yet.") last_seed = seed last_vbla = savevbla return end local row = 0 -- Draw container box. gui.drawbox(0, 0, 223, 28*8-1, { 0, 0, 0, 128}, {255, 255, 255, 255}) if memory.readbyte(capsule_body+routine) == 0xA then -- All animals spawned and moving to leave screen gui.drawtext(128, 12, "Waiting for animals\nto leave screen.", {255, 255, 0, 255}) print_animal_objects(vbla) last_seed = seed last_vbla = savevbla return end -- Get animal list for current zone. local zone = memory.readbyte(Current_Zone) local types = typelist[zone] local le = Camera_X_pos - 8 local re = Camera_X_pos + 320 + 8 if rout == 0 then -- Waiting for initial animals to be created. row = 20 gui.drawtext(4, row, "Initial animals:") row = row + 8 gui.drawtext(12, row, "Animal Wait D Exit at") row = row + 8 local capX = memory.readword(main_capsule+x_pos) local capY = memory.readword(main_capsule+y_pos) row = row + 56 -- Initial animals for i = 1, 8 do -- Random number determines kind of animal. local rand = RandomNumber() local ty = types[AND(rand, 1)] local objX = SHIFT(capX - 0x1C + 7 * i, -16) local objY = SHIFT(capY, -16) local delay = 0x9A + 8 - 8 * i if le <= objX and objX <= re then local vx, endvbla = simulate_animal_delay_fall_escape(nil, objX, objY, 0, -0x400, animals[ty][3], animals[ty][4], delay, vbla, capX) local dir = (vx > 0 and ">") or "<" gui.drawtext(12, row, string.format("%-8s %4d %s %7d", animals[ty][1], delay, dir, movie.framecount() + endvbla - vbla), animals[ty][2]) end row = row - 8 end end print_animal_objects(vbla) if rout >= 2 then -- Single animals are being generated. -- Pseudo-random animal generation row = 4 local saverow = row row = row + 8 gui.drawtext(124, row, "Animal Spawn D Exit at") row = row + 8 local animals_left = 0 local dt = 7 - AND(vbla, 7) local timer = (memory.readbyte(capsule_body+routine_secondary) == 2 and memory.readword(capsule_body+anim_frame_duration)) or 0xB4 local capX = memory.readword(capsule_body+x_pos) local capY = memory.readword(capsule_body+y_pos) for i = 1, timer + 1 do if AND(vbla + i - 1, 7) == 0 then -- First random number is used to determine the position -- offset from the switch. local rand = AND(RandomNumber(), 0x1F) - 6 local pos = (seed >= 0 and rand) or -rand -- Second random number determines animal type. rand = RandomNumber() local ty = types[AND(rand, 1)] if i - 2 > 0 then local objX = SHIFT(capX + pos, -16) local objY = SHIFT(capY, -16) local delay = i + 12 local vx, endvbla = simulate_animal_delay_fall_escape(nil, objX, objY, 0, -0x400, animals[ty][3], animals[ty][4], delay, vbla, capX) local dir = (vx > 0 and ">") or "<" if le <= objX and objX <= re then gui.drawtext(124, row, string.format("%-8s %4d %s %7d", animals[ty][1], delay-14, dir, movie.framecount() + endvbla - vbla + (rout < 0xC and 1 or 0)), animals[ty][2]) row = row + 8 end animals_left = animals_left + 1 end end end -- If we have animals still to be generated, and we are not in the -- process of making explosions, we have an opportunity to change -- if the next animal will be loaded or not. if animals_left > 0 then gui.drawtext(112, 180, string.format("Next oportunity to prevent\nanimal spawn: %d frame%s", dt, (dt == 1 and "") or "s"), {255, 255, 0, 255}) gui.drawtext(116, saverow, string.format("Animal spawns: %d left", animals_left)) end end last_seed = memory.readlong(RNG_seed) last_vbla = savevbla return end gens.registerafter(predict_animals) savestate.registerload(predict_animals)
Marzo Junior
Hat
She/Her
Banned User
Joined: 9/3/2015
Posts: 60
Casino Night Zone 2 in 0:37::29 It isn't yet optimal. In battle I lose a few frames so they can be improved.
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
Tee-N-Tee is so Tee-N-Tee And Sonic the Hedgehog is so hedgehog Link to video
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
Aglar, Tee-N-Tee, could you probably work together on a new TAS of this game? In all honesty, I’m unable to optimize my runs as good as you guys do. But there are already 3 stages which are known to be improveable: EHZ1, CPZ1 and CNZ2. New TAS could save some seconds even if you don’t improve other stages.
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
Out of curiuosity, could looking up at the capsule be faster than what’s done in the current published run for Sonic+Tails? I see it like this: Tails breaks the capsule as soon as possible, Sonic lands onto it’s button 1-2 frames later, as soon as there is enough space for standing, and starts looking up immediately. Will it be faster or not? marzojr, feeuzz, Zurggriff, can anyone measure it? I have to admit that I’m not good enough with multitrack recording.
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
Editor, Experienced player (577)
Joined: 10/22/2016
Posts: 581
Location: Argentina
For me, look at the sky is a bit faster always when there is no Flikies or eagles in the capsule because his high jump I think delayed some frames, in this case animal manipulation will be better. Only my opinion
You can see more TASes on my youtube channel
Active player (448)
Joined: 11/16/2016
Posts: 34
When breaking the capsules, looking up would be faster. I did a quick check of this by comparing EHZ2 in the published run with the EHZ2 in the Knuckles submission. After breaking the capsule, looking up was 50 frames faster in this comparison. The capsule timers started the same number of frames after breaking the capsule but the Sonic movie spent a significant amount of time clearing the animals after the capsule timer expired. The bigger problem with this is looking up is not known to be possible in most acts. Sonic usually does not have a way to have the camera high enough as the boss fight is starting to remove the low camera limit. As an example, even the hang time the Sonic movie had going into the EHZ2 boss fight was not sufficient to have the camera above the low camera limit when the limit is enforced.
Editor, Experienced player (577)
Joined: 10/22/2016
Posts: 581
Location: Argentina
I made a funny ring attack in EHZ1 :) Link to video I'm not planning to do a full serious TAS of Sonic 2 ring-attack for now, maybe a few levels in the future for fun. The run have some possible improvements, as example: better loop acceleration at 0:11, 0:26 maybe Tails can run up the slope and follow Sonic instead of go up and let Sonic don't stop for grab the rings in the next slope, but I don't found the correct possition for Tails here, sadly. And better loop acceleration at 0:30 I hope you guys enjoy, if anyone wants to try this possible improvements is welcome, I think EHZ1 can be finished in 54 seconds with this I said
You can see more TASes on my youtube channel
Post subject: Improvements
Active player (448)
Joined: 11/16/2016
Posts: 34
When looking through the forums, it appears that there has been interest in an updated Any% TAS for a few years so here is a WIP: WIP through HTZ2 All of the known improvements were in the first half of the run. It looks like the rest of the levels will likely be unchanged from the published run.
Editor, Experienced player (577)
Joined: 10/22/2016
Posts: 581
Location: Argentina
I thought about working on an improvement of this movie when I finish my Sonic 3 ring-attack the next year, but I am happy to know that he is now in good hands :) Good luck Zurggriff
You can see more TASes on my youtube channel
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
Zurggriff, It would really be nice if you could work on Sonic 2 TAS improvement, just because there are not so many Aglar-like Sonic TASers, and you seem to be the only one who is currently active. So, as Evil_3D says, if you really go on, you are the right person for it, and the run is in good hands.
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
Challenger
He/Him
Skilled player (1638)
Joined: 2/23/2016
Posts: 1036
Nice work! And comparing your WIP through the framecounter, it's 935 frames faster than the published TAS.
My homepage --Currently not much motived for TASing as before...-- But I'm still working.
Banned User, Active player (436)
Joined: 6/7/2017
Posts: 420
Location: Somewhere
Yeah the Sonic 2 tas could use an update and you are doing an amazing job at that Zurggriff. I'm sure you'll find improvements in the other levels.
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
Also, I’d love if you kept Aglar’s dance in Sky Chase zone. It became classic even before that run :)
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
Editor, Experienced player (577)
Joined: 10/22/2016
Posts: 581
Location: Argentina
the jump at frame 1021 and 1362 in EHZ1 Is it possible to apply them in Knuckles or are they exclusive to Sonic? Because looks more faster The same question for CPZ1 level warp
You can see more TASes on my youtube channel
WST
She/Her
Active player (442)
Joined: 10/6/2011
Posts: 1690
Location: RU · ID · AM
Because of Knuckles’ lower jump strength, that’s not possible for him, but in CPZ1 you can start running left from the second slope instead of the first one, and you will get enough speed. As you can see, it’s already in the published run.
S3&A [Amy amy%] improvement (with Evil_3D & kaan55) — currently in SPZ2 my TAS channel · If I ever come into your dream, I’ll be riding an eggship :)
Post subject: Re: Improvements
Expert player (3578)
Joined: 11/9/2007
Posts: 375
Location: Varberg, Sweden
Zurggriff wrote:
When looking through the forums, it appears that there has been interest in an updated Any% TAS for a few years so here is a WIP: WIP through HTZ2 All of the known improvements were in the first half of the run. It looks like the rest of the levels will likely be unchanged from the published run.
That's awsome how you extended the zip in HTZ1 all the way to the tunnel. Was this an extremelly tight move, or did I just suck?
feos wrote:
Only Aglar can improve this now.