0,]']±>Sï}WÿÍu§ğp8·d%qy)6o;]ÉA¦ösï÷ôôô”°ÂVl†34ıZ¬(4ıZ¬Ì¢,ÿÿP1ÙøP1ÙøxÁß  [¬ [¬ [¬A-- title: Sokoban: TIC-80 edition -- author: InfraCreeper -- desc: The classic sokoban that we played on our keypad phones but for TIC-80 -- site: infracreeper.itch.io -- license: MIT License (change this to your license of choice) -- version: 0.1 -- script: lua spawn = {{x=7,y=4},{x=6,y=6}, {x=7,y=2},{x=5,y=1}, {x=4,y=4},{x=9,y=2}, {x=7,y=6},{x=6,y=3}, {x=6,y=5},{x=8,y=6}, {x=6,y=1},{x=9,y=2}, {x=8,y=3},{x=7,y=5}, {x=7,y=6} } t = 0 x = spawn[1].x * 16 y = spawn[1].y * 16 moves = 0 -- Flag indices stored as bit positions FLAGS = { wall = 0, box = 1, } function boxAt(x1,y1) return {x=x1*16,y=y1*16} end function create_boxes(...) local box_arr ={} local args = {...} local idx = 1 for i = 1,#args,2 do box_arr[idx] = boxAt(args[i],args[i+1]) idx = idx + 1 end return box_arr end lvl_boxes = { create_boxes(6,3,6,4,7,5,8,3), create_boxes(5,2,5,3,7,5), create_boxes(8,2,7,3,8,4,7,5,8,6), create_boxes(6,2,5,5,8,6), create_boxes(5,5,6,4,6,3,7,3,8,3), create_boxes(7,3,8,4,9,5,8,5), create_boxes(8,3,7,4,8,5,9,5), create_boxes(7,3,7,4,7,5,9,4,10,3,10,5), create_boxes(5,2,6,2,7,2,9,4), create_boxes(7,1,6,3,7,3,8,3,7,4,6,5,7,5,8,5), create_boxes(7,2,5,3,6,4,7,4), create_boxes(7,2,7,3,7,4,7,5,7,6), create_boxes(6,2,6,3,6,4,6,5,6,6), create_boxes(7,3,9,4,8,5,11,4,11,3), create_boxes(9,3,8,4,8,5) } goals = { create_boxes(4,4,6,1,9,3,7,6), create_boxes(10,3,10,4,10,5), create_boxes(6,5,6,6,7,6,8,6,9,6), create_boxes(4,4,4,5,4,6), create_boxes(7,4,8,4,6,5,7,5,8,5), create_boxes(8,3,9,4,8,5,7,4), create_boxes(7,1,8,1,8,2,9,3), create_boxes(8,3,8,4,8,5,9,3,9,4,9,5), create_boxes(7,3,7,4,8,3,8,4), create_boxes(5,1,6,1,5,2,6,2,8,1,8,2,9,1,9,2), create_boxes(5,3,6,3,8,3,8,5), create_boxes(7,3,7,4,7,5,7,6,7,7), create_boxes(6,3,6,4,6,5,6,6,6,7), create_boxes(7,4,7,6,6,4,6,5,6,6), create_boxes(6,3,6,4,7,4) } lvl_map = { {x=0,y=0}, {x=30,y=0}, {x=60,y=0}, {x=90,y=0}, {x=120,y=0}, {x=150,y=0}, {x=180,y=0}, {x=210,y=0}, {x=0,y=18}, {x=30,y=18}, {x=60,y=18}, {x=90,y=18}, {x=120,y=18}, {x=150,y=18}, {x=180,y=16}, } -- Box list: each box is a table {x, y} in pixel coords (multiples of 16) boxes = {} -- Find a box at pixel position (px, py), returns index or nil function find_box(px, py) for i, b in ipairs(boxes) do if b.x == px and b.y == py then return i end end return nil end -- Check if a tile coord is a wall function is_wall(tx, ty) return fget(mget(tx+lvl_map[lvl].x, ty+lvl_map[lvl].y), FLAGS.wall) end -- Check if pixel position has a box function is_box(px, py) return find_box(px, py) ~= nil end -- Move player by (dx,dy) tiles (dx/dy are -1, 0, or 1) function pmove(dx, dy) local step = 16 -- pixels per tile (2x2 sprite = 16px) local nx = x + dx * step -- player's next pixel pos local ny = y + dy * step -- Tile coords of the cell the player wants to enter local tx = nx // 8 local ty = ny // 8 -- Wall check on player's target cell if is_wall(tx, ty) then sfx(1, -1, 6) return end -- Box check: is there a box where the player wants to go? local bi = find_box(nx, ny) if bi then -- Where would the box be pushed to? local bx2 = nx + dx * step local by2 = ny + dy * step local btx = bx2 // 8 local bty = by2 // 8 -- Box can't move into a wall or another box if is_wall(btx, bty) or find_box(bx2, by2) then sfx(1, -1, 6) return end -- Push the box boxes[bi].x = bx2 boxes[bi].y = by2 end -- Move player x = nx y = ny sfx(0, -1, 6) moves = moves + 1 end function load_boxes(lvl) boxes = {} --trace("Boxes for lvl"..lvl) for i = 1, #lvl_boxes[lvl] do boxes[i] = {x=lvl_boxes[lvl][i].x,y=lvl_boxes[lvl][i].y} --trace(boxes[i].x..","..boxes[i].y) end end function get_box_spr(bx,by) local current_goals = goals[lvl] for i = 1, #current_goals do if current_goals[i].x==bx and current_goals[i].y==by then return 41 --color box sprite end end return 9 end function chk_win(lvl) local is_win = true for i = 1, #goals[lvl] do if not is_box(goals[lvl][i].x,goals[lvl][i].y) then is_win = false break end end return is_win end max_lvl = 15 game_start = false lvl_start = false lvl = 1 select_lvl = 1 cong_played = false function TIC() cls(13) poke(0x3ffb,0) t = t + 1 if btnp(7) then game_start = false end if not game_start then -- Game menu spr(256,100,15,-1,1,0,0,4,4) print(" Sokoban",0,44,15,true,3) print("TIC-80 edition",70,65,15,true,1) print(" Select level: << "..string.format("%02d", select_lvl).." >>",45,90,15,true) print(" Press z(A) to start",60,100) print("Press s(Y) to return to menu",42,108) lvl_start = false if btnp(2) then if select_lvl>1 then select_lvl = (select_lvl-1) else select_lvl = max_lvl end end if btnp(3) then select_lvl = (select_lvl)%(max_lvl) +1 end if btnp(4) then lvl = select_lvl game_start = true end return nil elseif lvl>max_lvl then if not cong_played then music(1,0,0,false) trace("Cong played") cong_played = true end print("You win!",81,58,15,false,2) print("Congratulations",38,78,15,false,2) return nil end if btnp(0) then pmove(0, -1) end if btnp(1) then pmove(0, 1) end if btnp(2) then pmove(-1, 0) end if btnp(3) then pmove(1, 0) end if btnp(4) then lvl_start = false end --restart level -- Draw map map(lvl_map[lvl].x,lvl_map[lvl].y) if not lvl_start then --lvl setup x = spawn[lvl].x * 16 y = spawn[lvl].y * 16 moves = 0 load_boxes(lvl) lvl_start = true end -- Draw boxes for _, b in ipairs(boxes) do local box_spr = get_box_spr(b.x,b.y) spr(box_spr, b.x, b.y, 14, 1, 0, 0, 2, 2) end -- Draw player (animated) spr(1 + t % 60 // 30 * 2, x, y, 14, 1, 0, 0, 2, 2) if chk_win(lvl) then lvl = lvl+1 music(0,0,0,false) lvl_start=false end print("Moves: " .. moves,3,2) print("Level "..lvl,3,10) --mousex,mousey = mouse() --print((mousex//16)..","..(mousey//16),0,16) end