{deck}
version:1
card:0
size:[512,342]
name:"Decker Sokoban"
author:"John Earnest"

{sounds}
thud:"%%SND0/CYZEQsG3Ojw9vn7/iQYDwoGBuHr8vf6+/7/IxcPCgYEA+Hs8vf5/P7///4eFA0IBQMBAd/q8vb6+/7+//8AAAAcEw0IBQMBAQEAAObv9fj7/f3//wAAAAAAAAAAAAMRDAcEAgEAAQAAAAAAAADt8vb5+/7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAUEAQ=="
scrape:"%%SND0AAAAAAAA/wD8AgAA/wAA/gD//AUAAAAAAAD+AAIE/QAAAAABAPQIAf4AAAD+Afz9EewLAAD/Af4ABQDvCAAA/wAA/wDxAAAIAQAA/wD++QQR5QkAAAD//gEA/QMKA/X9BP8A/AP9Ef3u+AsA/gAA/gEE9Av+Cvv/A/4BAfwAAAgF4A/7//8A//4B/Qb08gP8HfkABP4A/vwCAwjkAfwOAwAAAAAA+gr89xf61QMICwAA/v8C/P4O8wz99wvXJQ38/AAE/f8DAvUHCd0h7+P9CAgDAv4AAPgF9wUN7ArmKhLSCAAA/vYB/wH7Av/6C/oG4BIOJ9cj+QoAAAD/AP//BPv8EAAA7u8RFQXox1T/ywEF+/MDBPcFAfoG8/4BAQ0J8e0C/wALPqM97iUJ++r+AAD//gAG+gv49QEH+woJ8Qz0DuQFJvbb7kbgAesS0QNTzAAR/vn+/P4M/PUE9QMD//z9BAH2BQD/+QIJAwD1AAj57B8A6xfbFvTsGuIxD9wlAAXYNcoFA+fy9zXKABL1B1bfG6Zz4R7lzykT2/jfUT/kl2AKG/aRSQ4NlfJa8wm3Jy0g55tm1iTs9wkIzAjqJ80iCOPqKOn1F+gr0yvmGuEKEOUX8wr0AwP0A/n8BgD8BAz4FgIRHvUM3QbaEfUzFhnlEA3RLZgR6AEfEfj6D/XxCPoR+PgB+voECAEF7foJLNjnMfL5QbH97CIEBP74Cvv/BPUHAv8A/+379BQzt1Db2xcH7vsHCP0A/wT0A/7+BPU6oCUS5fnrFA/u+wkE//kCBf8ABAPuJsP88/4I+v8J+wUB/v4BBvcMG+ryCvQADPkAAAP9AP0B8AICEPkF/wH7A/4BAAH7BfQI9hD6AQAA/v4A/QD7CQPzAAA="
step:"%%SND0BfD4ADMP9/ATC9L1C/34/BIPCgkPBRMQ6gkB+QoIFOj/3fUO/QsF5gfr4PXtB/kT8RoLFfoOAxr58f0E7wLoBfvy7wAD8gYK+Q8G+QX9/gsTAPn9EPT4//cJAPr9D/4M8PPz+w8QAPz88AAB9gb59v8B/vwB+voDAPYAB/33/AT8/gAI/gYA+gAAAQT+AP/+AgD+/v//AAD/AAAAAA=="
reset:"%%[encoded data, 4816 characters]"
chime:"%%[encoded data, 8980 characters]"

{card:game}
image:"%%[encoded data, 13140 characters]"
script:"game.0"
{widgets}
reset:{"type":"button","size":[64,32],"pos":[428,282],"script":"game.1","show":"transparent","text":"Reset","style":"rect","shortcut":"r"}
level:{"type":"slider","size":[100,25],"pos":[403,25],"script":"game.2","show":"none","interval":[0,2],"format":"Level %f","style":"compact"}
event_pump:{"type":"button","size":[64,32],"pos":[416,64],"animated":1,"script":"game.3","show":"none"}
undo:{"type":"button","size":[64,32],"pos":[20,282],"locked":1,"script":"game.4","show":"transparent","text":"Undo","style":"rect","shortcut":"z"}
hist:{"type":"grid","size":[100,50],"pos":[20,29],"show":"none","format":"j","value":{"actors":[]}}
box1:{"type":"contraption","size":[32,32],"pos":[256,160],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"box"}}}
player:{"type":"contraption","size":[32,32],"pos":[160,160],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[152,160],\"dest\":[160,160]}"},"i":{"value":"player"}}}

{script:game.0}
CELL:32 # grid size

deltas.left :-1, 0
deltas.right: 1, 0
deltas.up   : 0,-1
deltas.down : 0, 1

on resetLevel do
 card.remove[findActors[]]
 l:deck.cards["level_%i" format level.value]
 card.image.paste[l.image.copy[]]
 card.paste[l.copy[l.widgets]]
 hist.value:0 take hist.value
 undo.locked:1
end

on isTile pos tile do
 0<card.image.copy[pos CELL,CELL].hist[tile]
end
on isWall pos do isTile[pos 20] end
on isGoal pos do isTile[pos 29] end
on findActors do
 extract value where value..type="contraption" from card.widgets
end
on findBoxes do
 extract value where value..name like "box*" from findActors[]
end
on findActor pos do
 b:findActors[]
 ((b..pos)dict b)[pos]
end
on thud pos do
 play["thud"]
 player.bounce[pos]
end

on navigate dir do
 moved:0
 act:act:findActors[]
 before:(act..name) dict (act..dest)
 
 d:deltas[dir]
 a:player.dest
 b:a+d*CELL
 
 if isWall[b]
  thud[b]
 elseif f:findActor[b]
  fa:f.dest
  fb:fa+d*CELL
  if findActor[fb] unless isWall[fb]
   thud[b]
  else
   play["scrape"]
   f.move[fb]
   player.move[b]
   moved:1
  end
 else
  play["step"]
  player.move[b]
  moved:1
 end
 if moved
  hist.value:hist.value,insert actors with before end
  undo.locked:0
 end
end

on check_board do
 won:min each box in findBoxes[]
  isGoal[box.dest]&box.done
 end
 if won
  sleep[30]
  play["chime"]
  if level.value<last level.interval
   go[black "BoxOut" 10]
   level.value:level.value+1
   resetLevel[]
   go[game "BoxIn" 10]
  else
   go[win "BoxIn"]
  end
 end
end
{end}

{script:game.1}
on click do
 resetLevel[]
 play["reset"]
end
{end}

{script:game.2}
on change val do
 resetLevel[]
end
{end}

{script:game.3}
on view do
 check_board[]
end
{end}

{script:game.4}
on click do
 each pos name in first last hist.value
  card.widgets[name].pos:pos
 end
 hist.value:-1 drop hist.value
 undo.locked:0~count hist.value
 play["reset"]
end
{end}

{card:win}
image:"%%[encoded data, 5952 characters]"
script:"win.0"
{widgets}
button1:{"type":"button","size":[96,32],"pos":[384,288],"script":"win.1","text":"Play Again?","shortcut":"r"}

{script:win.0}
on navigate do end
{end}

{script:win.1}
on click do
 game.widgets.level.value:0
 game.event["resetLevel"]
 play["reset"]
 go[game "BoxIn"]
end
{end}

{card:black}
image:"%%IMG2AgABVhf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8X/xf/F/8Xrg=="

{card:sprites}
image:"%%IMG2AgABVgD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8AAgELABUBCwD/ANIBEAAQARAA/wDPARUACwEVAP8AywEHIAsBBQAJAQcgCwEFAP8AyQEEIBABBQAHAQQgEAEFAP8AxwEDIBQBBAAFAQMgFAEEAP8AxgEDIAgBASAMAQMABQEDIAgBASAMAQMA/wDGAQMgBwEDIAwBAwAEAQMgBwEDIAwBAwD/AMUBAyAIAQEgCQEBIAMBBAADAQMgCAEBIAkBASADAQQA/wDFAQMgEAEDIAMBAwAEAQMgEAEDIAMBAwD/AMUBAyARAQEgBAEDAAQBAyARAQEgBAEDAP8AxgEDIBUBAwAFAQMgFQEDAP8AxwEEIBMBAwAGAQQgEwEDAP8AyAEFIBEBAwAHAQUgEQEDAP8AyQEGIAEBASALAQUACAEGIAEBASALAQUA/wDKARYACgEWAP8AywEUAAwBFAD/AM0BAwABAQ4ADgEDAAEBDgD/AM8BAwACAQMAAQEGABEBAwACAQMAAQEGAP8A0QEEAAIBAwABAQcAEAEDAAIBAwABAQYA/wDQAQQAAwEDAAEBAwABAQUADgECAAMBAwABAQcA/wDOAQQABAEDAAEBBAACAQQADAEDAAMBAwABAQMAAQEEAP8AzAEEAAQBBAACAQMAAwEFAAoBAwADAQMAAQEDAAEBBAD/AMoBBQAFAQMAAwEFAAIBBQAIAQMABAEDAAEBAwACAQQA/wDIAQUABgEDAAQBBQADAQIACAEEAAUBAwABAQMAAgEFAP8AxwECAAgBAwAFAQQADQEEAAUBBwADAQUA/wDRAQMABgEDAAsBBAAGAQcABAEDAP8A0gEDAAcBAQANAQIACAEDAAEBAQD/ANsBAQAhAQEA/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AB0BCQD/APcBGQD/AOkBGQD/AOcBAw0HARAA/wDnAQMNFAEDAP8A5wEDDRQBAwD/AOcBAw0UAQMA/wDnAQMNFAEDAP8A5wEDDRQBAwD/AOcBAw0UAQMA/wDnAQMNFAEDAP8A5wEDDRQBAwD/AOcBAw0UAQMA/wDnAQMNFAEDAP8A5wEDDRQBAwD/AOcBAw0UAQMA/wDnAQMNFAEDAP8A5wEDDRQBAwD/AOcBAw0UAQMA/wDnAQMNFAEDAP8A5wEDDRQBAwD/AOcBAw0UAQMA/wDoARENBQEDAP8A5wEaAP8A6AEZAP8A+QEHAP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wDm"
{widgets}
player:{"type":"button","size":[64,32],"pos":[80,80],"show":"none"}
box:{"type":"button","size":[32,32],"pos":[80,144],"show":"none"}

{card:level_0}
image:"%%[encoded data, 13140 characters]"
script:"level_0.0"
{widgets}
box1:{"type":"contraption","size":[32,32],"pos":[256,160],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"box"}}}
player:{"type":"contraption","size":[32,32],"pos":[160,160],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"player"}}}

{script:level_0.0}
on view do
 
end
{end}

{card:level_1}
image:"%%[encoded data, 5780 characters]"
{widgets}
box2:{"type":"contraption","size":[32,32],"pos":[288,128],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"box"}}}
box1:{"type":"contraption","size":[32,32],"pos":[192,192],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"box"}}}
player:{"type":"contraption","size":[32,32],"pos":[256,160],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"player"}}}

{card:level_2}
image:"%%[encoded data, 5124 characters]"
{widgets}
player:{"type":"contraption","size":[32,32],"pos":[256,224],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"player"}}}
box2:{"type":"contraption","size":[32,32],"pos":[224,192],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"box"}}}
box1:{"type":"contraption","size":[32,32],"pos":[192,160],"show":"transparent","def":"mover","widgets":{"c":{},"s":{"value":"{\"anim\":0,\"orig\":[256,160],\"dest\":[100,100]}"},"i":{"value":"box"}}}

{contraption:mover}
size:[32,32]
margin:[0,0,0,0]
description:"A self-tweening sprite."
script:"mover.0p"
attributes:{"name":["img"],"label":["Image"],"type":["string"]}
{widgets}
c:{"type":"canvas","size":[32,32],"pos":[0,0],"locked":1,"animated":1,"volatile":1,"show":"transparent","border":0,"scale":1}
s:{"type":"field","size":[100,22],"pos":[71,-36],"show":"none","style":"plain","value":"{}"}
i:{"type":"field","size":[100,20],"pos":[64,0],"show":"none","style":"plain"}

{script:mover.0p}
on get_img     do i.text   end
on set_img   x do i.text:x end
on get_state   do "%j" parse s.text end
on set_state x do s.text:"%j"format x end

STEPS:4

on tween a b t do
 a+(b-a)*t
end

on view do
 spc:deck.cards.sprites
 spb:spc.widgets[i.text]
 spn:floor spb.size[0]/card.size[0]
 spi:floor spn%sys.frame/15
 c.clear[]
 c.paste[spc.image.copy[spb.pos+(spi*card.size*1,0) card.size]]
 st:get_state[]
 if st.anim>0
  card.pos:tween[st.orig st.dest (STEPS-st.anim)/STEPS-1]
  st.anim:st.anim-1
 end
 set_state[st]
end

on get_dest do
 st:get_state[]
 if st.anim>0
  st.dest
 else
  card.pos
 end
end

on get_done do
 st:get_state[]
 st.anim~0
end

on get_move do
 on move pos do 
  st:get_state[]
  if st.anim card.pos:st.dest end
  st.anim:STEPS
  st.orig:card.pos
  st.dest:pos
  set_state[st]
 end
end

on get_bounce do
 on bounce pos do
  st:get_state[]
  if st.anim card.pos:st.dest end
  st.anim:STEPS
  st.orig:tween[card.pos pos 0.25]
  st.dest:card.pos
  set_state[st]
 end
end
{end}

