Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs

I would love to see the unobfuscated code for these projects

A topic by nextlevelbanana created Nov 14, 2018 Views: 174 Replies: 10
Viewing posts 1 to 9
Submitted

I want to understand your wizardry! Anyone willing to share?

HostSubmitted(+1)

I'd be willing, but I wrote the code as obfuscated in the first place, since I knew I'd have to shorten it later! Perhaps I'll unobfuscate one of my games tonight for this thread!

Submitted (3 edits)

Sure. Here's the original code for Patrick's Picochallenge:

poke(24364,3)x="웃"v="▥"h="▤"b={}for i=1,36 do b[i]=i%9<2 and""or"█"end for i in all{"⬆️","➡️",h,"⬅️","⬇️",v,x}do repeat f=1+flr(rnd(36))until b[f]!=""b[f]=i
if(i==x)p=f
end::_::t=btnp cls()for i=0,35 do
k=b[i+1]
?k,i%9*8,6*flr(i/9)+20,k==x and 11 or 7
end b[p]=""q=p
if(t(0))q-=1
if(t(1))q+=1
if(t(2))q-=9
if(t(3))q+=9
if(b[q]and#b[q]>0)p=q t=b[p]
if(t=="⬆️"or t==v)b[p-10]=""b[p-9]=""b[p-8]=""
if(t=="⬇️"or t==v)b[p+10]=""b[p+9]=""b[p+8]=""
if(t=="⬅️"or t==h)b[p-10]=""b[p-1]=""b[p+8]=""
if(t=="➡️"or t==h)b[p+10]=""b[p+1]=""b[p-8]=""
b[p]=x flip()goto _

My attempt at unobfuscating and commenting it (I wrote it minified from the start):

--patrick's picochallenge
--by tobiasvl
--use 64x64 resolution
poke(0x5f2c,3)
--generate a blank board of
--empty █ tiles
board={}
--the board is 7x4, but we
--represent it as a one-
--dimensional table. we also
--represent it as 36 tiles, ie
--a 9x4 grid, with two columns
--of "" on each end, so ⬅️➡️▤▥
--tiles don't wrap around when
--they destroy adjacent tiles.
for i=1,36 do
  if i%9<2 then
    --first and last column
    board[i]=""
  else
    board[i]="█"
  end
end
--populate the board with tiles
--and the player's starting tile
tiles={"⬆️","➡️","▤","⬅️","⬇️","▥","웃"}
for i in all(tiles) do
  --find a random tile which is
  --not in the "invisible" outer
  --columns
  repeat
    position=1+flr(rnd(36))
  until board[position]!=""
  board[position]=i
  --remember the player
  if (i=="웃") player=position
end
--game loop
::_::
cls()
--print the board
--here's the only obfuscation i
--left in: here i loop from
--0 to 35, instead of 1 to 36,
--because then i only need to
--do i+1 once instead of i-1
--twice.
for i=0,35 do
  local tile=board[i+1]
  --the player is green
  if tile=="웃" then
    color(11)
  else
    color(7)
  end
  --properly centering the board
  --takes up too many characters
  --so just an approximation
  print(tile,i%9*8,6*flr(i/9)+20)
end
--erase the player character
--and destroy the tile
board[player]=""
--remember the player's position
new_player=player
--move the player's position if
--an arrow key is pressed
if (btnp(⬅️)) new_player-=1
if (btnp(➡️)) new_player+=1
if (btnp(⬆️)) new_player-=9
if (btnp(⬇️)) new_player+=9
--if we're still inside the
--board proper, ie the tile isn't
--nil (outside the board) or ""
--(the border columns), make
--that the new position.
if board[new_player] and board[new_player]!="" then
  player=new_player
  tile=board[player]
end
--if the player lands on one of
--the special tiles, destroy
--adjacent tiles
if tile=="⬆️" or tile=="▥" then
  --destroy three tiles above
  board[player-10]=""
  board[player-9]=""
  board[player-8]=""
end
if tile=="⬇️" or tile=="▥" then
  --destroy three tiles below
  board[player+10]=""
  board[player+9]=""
  board[player+8]=""
end
if tile=="⬅️" or tile=="▤" then
  --destroy three tiles left
  board[player-10]=""
  board[player-1]=""
  board[player+8]=""
end
if tile=="➡️" or tile=="▤" then
  --destroy three tiles right
  board[player+10]=""
  board[player+1]=""
  board[player-8]=""
end
--put the player in the new
--(or old!) position
board[player]="웃"
--loop
flip()
goto _

Fun exercise. I actually found a bug while looking through it, so thanks for that!

The game itself is a demake of a game I made earlier this year, so it was really interesting to try to find smarter solutions than I did originally.

Edit: itch stripped out blank lines from the code for some reason, here's a gist.

Submitted (3 edits)

Here's Froggy Road, de-obfuscated!  I tried to make the variable names more clear and removed all the line-break-saving measures, but I didn't change any of the logic, so there are still some spots where it does a weird thing to avoid an if statement or whatever (for example, every road-lane draws a frog, but they're all hidden offscreen except for the lane which actually-currently-contains the player).

(edit - like with tobiasvl, my linebreaks get stripped here - here's a version on pastebin which keeps them intact)

frogX=0
frogY=0
died=0
camX=frogX
camY=frogY
::_::
flip()
cls(1)
// weird arrow key input
z=btnp()
// add +/- 5 to x for right/left arrows
frogX+=(flr(z/2)%2-z%2)*5
// add +/- 1 to y for up/down arrows
frogY-=flr(z/8)%2-flr(z/4)%2
// camera eases toward frog position
camX+=(frogX-camX)/3
camY+=(frogY-camY)/3
// draw road lanes
for laneY=frogY+25,frogY-2,-1 do
    // each lane has its own randomized properties
    srand(laneY)
    // car animation properties
    cycleOffset=rnd()
    carSpeed=8+rnd(16)
    // perspective distortion strength
    // (persp=0 means "infinitely far away")
    persp=(laneY-camY+2.3)/12
    
    // draw the road
    // (but draw it offscreen if persp<0)
    rectfill(-1,64+9/persp,sgn(persp)*127,127,6-laneY%2)
    // draw a frog in every lane...
    // but offset it off the screen if the
    // frog isn't actually in this lane
    print("🐱",61+(frogX-camX)/persp+(laneY-frogY)*99,62+7.5/persp,3)
    // each lane has a different # of cars
    // (early/negative lanes have no cars)
    for i=1,sgn(laneY-2)*rnd(8) do
        // a car has two halves, parallel to the lane
        // (near-half and far-half)
        for k=0,1 do
            // each car has five sub-circles for the body
            for j=-2,2 do
                // x-position of this sub-circle
                worldX=(i*carSpeed*4+j+t()*carSpeed+cycleOffset-camX)%198-99
                
                // collision detection for the frog
                if laneY==frogY and abs(worldX-frogX+camX)<2 then
                    died=1
                end
                // far-half of car uses a different persp value
                persp2=persp-k/60
                // get screen position of this sub-circle
                screenX=worldX/persp2+64
                screenY=5/persp2+64
                // draw this sub-circle
                circfill(screenX,screenY,2/persp2,laneY%5)
                // draw a wheel, but only if j equals +/- 2
                circfill(screenX,screenY+2/persp2,(abs(j)-1)/persp2,0)
            end
        end
    end
end
// self-explanatory death check
if (died>0) then
    goto dead
end
// if you're not dead, continue the game loop
goto _
::dead::
// you done goofed
// random red/orange noise
pset(rnd(128),rnd(128),8+rnd(2))
// death UI
print("❎ reset",46,62,7)
// your score is your distance, literally
print("score: "..frogY,3,3)
// restart command
if btn(5) then
    run()
end
// haven't reset yet. resume death
goto dead

And then just for the sake of easy comparison, here's the original code:

x=0y=0l=0q=x
r=y
f=rnd
g=flr
h=circfill::_::flip()cls(1)z=btnp()x+=(g(z/2)%2-z%2)*5y-=g(z/8)%2-g(z/4)%2
q+=(x-q)/3r+=(y-r)/3
for z=y+25,y-2,-1 do
srand(z)o=f()m=8+f(16)p=(z-r+2.3)/12rectfill(-1,64+9/p,sgn(p)*127,127,6-z%2)
?"🐱",61+(x-q)/p+(z-y)*99,62+7.5/p,3
for i=1,sgn(z-2)*f(8)do
for k=0,1 do
for j=-2,2 do
u=(i*m*4+j+t()*m+o-q)%198-99
if(z==y and abs(u-x+q)<2)l=1
v=p-k/60n=u/v+64w=5/v+64h(n,w,2/v,z%5)h(n,w+2/v,(abs(j)-1)/v,0)end
end
end
end
if(l>0)goto d
goto _::d::pset(f(128),f(128),8+f(2))
?"❎ reset",46,62,7
?"score: "..y,3,3
if(btn(5))run()
goto d
Submitted

I just put my earlier tweetgame on Itch.io and included fully commented source code. You can see it here: https://kometbomb.itch.io/breakout-280

Submitted

How did you format the source code there?

Submitted

I used hilite.me but the wysiwyg HTML editor is really annoying with custom HTML (especially if you edit it later).

HostSubmitted

I de-obfuscated my code for Putt, in case anybody is interested. Planning to make this into a proper lil PicoPutt game, but gonna need to spend a LOT of time polishing it.

function _init()
    spawn_level()
end

function _update()
    move_player()
end

function _draw()
cls()
    draw_bg()
    collision()
    draw_player()
end

-- levelgen

function spawn_level()
    grass={}
    sand={}
 for i=1,5 do
     j=14+i*16
     k=50+rnd(35)
     q=17+rnd(10)
-- make grass and sand
     add(grass,{x=j,y=k,r=q})
     if i>1 and
                 i<5 then
         add(sand,{x=j+rnd(q)-q/2,y=k+rnd(q)-q/2,r=8})
     end
-- make player and hole
     if i==1 then
            p={x=j-q/2,y=k,a=0,xd=0,yd=4,p=1,v=0}
     elseif i==5 then
            h={x=j+q/2,y=k}
     end
 end
end

-- draw functions

function draw_bg()
    for v in all(grass) do
     circfill(v.x,v.y,v.r,11)
 end
 for v in all(sand) do
     circfill(v.x,v.y,v.r,4)
 end
-- hole
 circfill(h.x,h.y,2,0)
--    power bar
 circfill(64,8,5,7)
 print(p.p,63,6,0) end

-- player

function draw_player()
 circfill(p.x,p.y,2,7)
 circfill(p.x+p.xd,p.y+p.yd,0)
end

function move_player()
-- set angle of shot
 if btnp(5) then
     if p.a<6.28 then
         p.a+=.1 else p.a=0
     end
     p.xd=sin(p.a)*4
     p.yd=cos(p.a)*4
 end
-- set shot power
    if btnp(2) then
        if p.p<5 then
            p.p+=1 else
            p.p=1
        end
    end
-- shoot
    if btnp(4) then
        p.v=p.p
    end
-- move ball, apply deceleration
 p.x+=p.v*p.xd
 p.y+=p.v*p.yd
 p.v*=.7
end

function collision()
-- hole/border pixel collision
 if pget(p.x,p.y)==0 then
  _init()
 end
-- sand trap collision
    if pget(p.x,p.y)==4 then
        p.v/=3
    end
end

HostSubmitted

And here's the obfuscated code:


::z::e={}f={}
d,xd,yd,p,s,b,t,o=0,0,4,1,0,circfill,btnp,rnd
for i=1,5 do
j,k,q=14+i*16,50+o(35),17+o(10)add(e,{x=j,y=k,r=q})
if(i>1 and i<5)add(f,{x=j+o(q)-q/2,y=k+o(q)-q/2,r=8})
if(i==1)x,y=j-q/2,k
if(i==5)w,u=j+q/2,k
end::_::cls()if t(5) then
if(d<6.28)d+=.1else d=0
xd=sin(d)*4
yd=cos(d)*4
end
if t(2) then
if(p<5)p+=1else p=1
end
if(t(4))s=p
x+=s*xd y+=s*yd s*=.7
for v in all(e) do
b(v.x,v.y,v.r,11)end
for v in all(f) do
b(v.x,v.y,v.r,4)end
b(w,u,2,0)
if(pget(x,y)==0)goto z
if(pget(x,y)==4)s/=3
b(x,y,2,7)b(64,8)b(x+xd,y+yd,0)
?p,63,6,0
flip()goto _

Submitted (2 edits)

Here's my other game too, Lights Out. I'm more pleased with this game as it has two modes, a title screen and a win state.

Minified:

z="lights out"poke(24364,3)::x::flip()cls()k=btnp()w={[0]="","▒","█"}f=flr
?z,12,18,stat(95)%4
?"z: classic\nx: 2000",12,32,7
if(k<9)goto x
if(k>16)w[3]="█"
b={}p=2m=0
for i=1,35 do
b[i]=i%7<2 and 0or 2
end::_::flip()cls()
?m,30,54
for i=1,35 do
j=b[i]
?w[j],i%7*8-2,6*f(i/7)+18,j*3+2
end
x=p%7*8-2y=6*f(p/7)+17rect(x-1,y,x+7,y+6,9)q=0k=btnp()h={-1,1,-7,0,7}if k>9then m+=1for i in all(h)do
o=b[p+i]
if(o and o>0)b[p+i]=o%#w+1
end
elseif k>0then q=h[f(k/2)+1]end
g=b[p+q]
if(g and g>0)p=p+q
for i=1,35 do
if(b[i]>1)goto _ end
z="you win!"goto x

Unobfuscated and commented (gist, since itch strips linebreaks):

-- title screen logo
title="lights out"
-- 64x64 resolution
poke(0x5f2c,3)
-- title screen loop
::title_screen::
-- clear screen
-- (we do it here because we
-- jump back upon winning)
flip()
cls()
-- read button input
key=btnp()
-- light values and visuals:
-- 0: no light
-- 1: light off
-- 2: red light
-- 3: green light
-- (green light only in mode
-- "lights out 2000")
lights={[0]="","▒","█"}
-- print title with color
-- alternating based on time
-- (stat(95) is current second)
print(title,12,18,stat(95)%4)
-- print menu
print("z: classic\nx: 2000",12,32,7)
-- if the button value is below
-- 16 (all values are powers of
-- two so by checking below 9
-- here we save a character),
-- including 0 (no input), we
-- just loop. 16 is the z key,
-- so if that's the case we
-- will fall through to classic
-- mode.
if (key<9) goto title_screen
-- button value 32 is x, so in
-- that case we add the green
-- light value for "2000 mode".
if (key>16) lights[3]="█"
-- initialize the board
board={}
-- start in the left corner
player=2
-- move counter
moves=0
-- initialize the 5x5 board
-- with the value 2 (red light)
-- but add a column of 0 (no
-- light) on either side to
-- avoid wrapping when toggling
for i=1,35 do
  -- if column is 1 or 7:
  if i%7<2 then
    board[i]=0
  else
    board[i]=2
  end
end
-- gameplay loop
::play::
flip()
cls()
-- move counter
print(moves,30,54)
-- print the board
for i=1,35 do
  light=board[i]
  -- a trick: each light's
  -- color can be computed from
  -- its value
  -- none: 0*3+2 = 0 (black)
  -- off: 1*3+2 = 5 (dark gray)
  -- red: 2*3+2 = 8
  -- green: 3*3+2 = 11
  light_color=light*3+2
  -- print lights in grid
  print(lights[light],i%7*8-2,6*flr(i/7)+18,light_color)
end
-- print the player's marker
x=player%7*8-2
y=6*flr(player/7)+17
rect(x-1,y,x+7,y+6,9)
-- marker movement: we find the
-- new position and see if it's
-- valid. if so, we move it.
new_player=0
key=btnp()
-- all adjacent grid indices.
-- used for movement and for
-- toggling lights. notice that
-- 0 (ie. no movement, the
-- currently marked light) is
-- in position 4 in the table.
-- this is a trick, used when
-- mapping input keys to
-- positions.
directions={-1,1,-7,0,7}
-- if the key is x or z (value
-- is 16 or 32) we toggle:
if key>9 then
  moves+=1
  -- look at all adjacent
  -- lights in all directions
  for i in all(directions) do
    light=board[player+i]
    -- if it's inside the board
    if light and light>0 then
      -- cycle light value up
      -- (use #lights here so
      -- we cover both classic
      -- and 2000 mode)
      board[player+i]=light%#lights+1
    end
  end
-- if the key is an arrow key
-- (value is 1, 2, 4 or 8):
elseif key>0 then
  -- divide the button value by
  -- two and add 1 and we get
  -- 1, 2, 3 or 5. look that up
  -- in the directions table
  -- (recall that position 4
  -- was the current light)
  new_player=directions[flr(key/2)+1]
  -- if it's inside the board
  light=board[player+new_player]
  if light and light>0 then
    -- move there
    player=player+new_player
  end
end
-- if any of the lights are
-- still on, stay in the
-- gameplay loop
for i=1,35 do
  if (board[i]>1) goto play
end
-- otherwise, set the title to
-- a congratulatory message
title="you win!"
-- and go back to the title
-- screen
goto title_screen
Submitted (1 edit)

Sorry for the late reply, just saw this now! Here's some commented code for Ninja Punch Zone. It's been long enough that I had to go through it and figure out what every line did again, and while doing that I found a couple of things I think I can optimize further. So thanks for that! :D

EDIT: Itch's comment system mangles the formatting so I've put an easier-to-read version up here.

--INITIALIZING VARIABLES--
--the number '30' came up a lot in the math stuff bleow,
--so i assigned it to a variable to save characters
t=30
--the player's x position
x=t
--the player's FIST position, relative to the player
--(it's always four pixels away from the player in the direction they're facing,
--but storing the offset in a variable saves chars when drawing later on)
f=4
--making aliases for some commonly used functions to save chars later on
z=rectfill
y=rnd
a=abs
--cooldown timer for the player's punch
c=0
--x position of red ninjas coming in from the right/left respectively
--every time we do this we randomize their position slightly,
--so the ninjas always come at the player at different times
r=130+y(30)
l=y(30)-82
--the player's score and the high score
s=0
h=0
--changing to low res mode (64x64 resolution)
poke(0x5f2c,3)
--the UPDATE LOOP--
function _update60()
 --if the player presses left or right then move them in that direction
 if btn(⬅️)
  then x=max(x-1,3)
  f=-4
 end
 if btn(➡️)then
  x=min(x+1,62)
  f=4 end
 end
 --if the player presses 'O' then punch,
 --but only if the cooldown timer from the last punch is finished
 if c==0 then
  if(btnp(🅾️)) c=10
 end
 --updating the cooldown timer for this frame
 c=max(c-1,0)
 --moving the two red ninjas towards the player
 l+=.7
 r-=.7
 --if the left ninja has run all the way off screen then reset them
 --also: some more character optimization seems possible here!
 --must have missed it at the time :-D
 if l>70 then
  l=y(t)-t
 end
 -- likewise, if the right ninja has ran all the way off the screen then reset them
 if(r<-10) r=y(t)+70
 --ALSO: ^^^^ do i even need to check for the ninjas running off screen?
 --they should collide with the player and reset before they reach the other side.
 --going to look into this, I might be able to create an even more optimized version! \o/
 --PUNCH CHECKING. if the punch cooldown is greater than zero,
 --then check if the player's arm is close enough to an enemy ninja to hit them
 --if it is then we add one to the score and reset the ninja's position off-screen
 if c>0 then
  if a(x-l+f)<4 then
   s+=1l=y(t)-t
  end
  if a(x-r+f)<4 then
   s+=1r=y(t)+70
  end
 end
 -- if the player has beaten the high score then we update the hi-score
 if(s>h) h=s
 -- if the player has collided with either of the two ninjas
 -- we start a new game (reset the score and move the two ninjas to their start points)
 if a(x-r)<2or a(x-l)<2 then
  s=0
  r=y(t)+130
  l=y(t)-82
 end
-- finally, the DRAW LOOP--
-- (naughtily done in _update60() to save chars)
 -- clear the screen
 cls()
 --draw two rectangles for the ground and sky
 z(0,14,64,49,12)
 z(0,43,64,49,5)
 --draw the player
 ?"웃",x-4,39,0
 --if the player is punching, draw a "-" for the player's extended arm
 if c>0 then
  ?"-",x+f-2,39,0
 end
 --draw the two red ninjas
 ?"웃",l-3,39,8
 ?"웃",r-3,39,8
 --print the score and high score at the top
 ?s,6,16,10
 ?h,54,16,10
end