Skip to content

Instantly share code, notes, and snippets.

@JoWovrin
Created June 3, 2025 00:11
Show Gist options
  • Save JoWovrin/e428958769552dca74a311843579477b to your computer and use it in GitHub Desktop.
Save JoWovrin/e428958769552dca74a311843579477b to your computer and use it in GitHub Desktop.
Sokoban in Space (Puzzlescript Next Script)
Play this game by pasting the script into https://puzzlescriptnext.polyomino.com/editor.html
title Sokoban in Space
author JoWovrin
homepage www.puzzlescript.net
again_interval 0.1
verbose_logging
level_select
norepeat_action
mouse_clicks
mouse_left roll_left
mouse_right roll_right
=====
TAGS
=====
nr = 1 2 3 4
notleft = right down up
notup = right left down
notdown = right left up
notright = left down up
=========
MAPPINGS
=========
directions => numbers
right left down up -> 1 2 3 4
========
OBJECTS
========
Background
green
roll_left l
transparent
roll_right r
transparent
Target
transparent
(white red
00000
01110
01010
01110
00000)
Wall #
brown
Player -
darkbrown
.....
.000.
.000.
.000.
.....
(
black orange lightgreen blue
.000.
.111.
22222
.333.
.3.3.)
Box:1
orange
00000
0...0
0...0
0...0
00000
Box:2
pink
00000
0...0
0...0
0...0
00000
Box:3
blue
00000
0...0
0...0
0...0
00000
Box:4
darkgreen
00000
0...0
0...0
0...0
00000
Spike s
white gray
.0.0.
00100
.111.
00100
.0.0.
dead t
red
0...0
..0..
.0.0.
..0..
0...0
falling f
transparent
(red
.....
.....
..0..
.....
.....)
lost_travel z
transparent
levitation x
red
gravity g
gray
jumped j
transparent
.....
..0..
.....
..0..
.0.0.
cur:directions d
transparent
..0..
.000.
00000
..0..
..0..
rot:up:>
arm:directions
gray darkbrown
00000
..1..
..1..
..1..
.....
rot:up:>
extends !
red
=======
LEGEND
=======
. = Background
O = Target
p = player and arm:up and arm:down and arm:left and arm:right
1 = Box:1
2 = Box:2
3 = Box:3
4 = Box:4
pushable = Player or Box:nr or arm:directions
pushable2 = Player or Box:nr or arm:directions
pushable3 = Player or Box:nr or arm:directions
object = Player or Wall or Box:nr or spike or arm:directions
obstacle = Wall or spike
=======
SOUNDS
=======
================
COLLISIONLAYERS
================
Background
roll_left
roll_right
lost_travel
levitation
gravity
jumped
extends
Target
Player, Wall, Box:nr, Spike
falling
directions -> arm:directions
directions -> cur:directions
dead
======
RULES
======
[dead] -> cancel
(toggle gravity/levitate mode)
[action Player][levitation] -> [Player][gravity]
[action Player][gravity] -> [Player][levitation]
(extend an arm)
[> Player arm:>] -> [Player > arm:>]
(if arm hits air, don't use movement system and just move the arm manually)
[> arm:> | no object] -> [ | arm:>]
(retract an arm)
[> Player | arm:>] -> [Player arm:> | ]
[gravity] -> gosub gravity-rules
[levitation] -> gosub levitation-rules
(emergency cancel)
[> arm:directions | stationary object] -> cancel
late [gravity] -> gosub LATE-gravity-rules
late [levitation] -> gosub LATE-levitation-rules
late [Player dead][target] -> [Player dead][]
late [jumped] -> []
late [lost_travel] -> []
late [extends] -> []
late [falling] -> again
late [cur:directions] -> again
late [arm:directions obstacle] -> cancel
late [arm:directions box:nr] -> cancel
=======================================================================================================
subroutine gravity-rules
=======================================================================================================
(gravity from "again" call)
[pushable falling] -> [down pushable falling]
down [ pushable falling | object no falling] -> [ pushable | object no falling]
[roll_left][Player arm:right arm:left arm:down arm:up] -> [roll_left][left Player arm:right arm:left arm:down arm:up]
[roll_right][Player arm:right arm:left arm:down arm:up] -> [roll_right][right Player arm:right arm:left arm:down arm:up]
[horizontal Player stationary arm:directions] -> [horizontal Player horizontal arm:directions]
[> arm:> stationary Player | spike] -> [arm:> Player dead| spike]
startloop
(pushables can push other pushables along)
[> pushable | pushable] -> [> pushable | > pushable]
(Propagate movements through connected boxes)
[moving Box:1][Box:1] -> [moving Box:1][moving Box:1]
[moving Box:2][Box:2] -> [moving Box:2][moving Box:2]
[moving Box:3][Box:3] -> [moving Box:3][moving Box:3]
[moving Box:4][Box:4] -> [moving Box:4][moving Box:4]
(if arm pushes against a wall, all their movement is stopped and all other arms are moved in the opposite direction)
[stationary Background > arm:> | wall] -> [> Background > arm:> | wall]
[stationary Background > arm:>][> box:nr | obstacle] -> [> Background > arm:>][box:nr | obstacle]
[> box:nr | stationary box:nr] -> [box:nr | stationary box:nr]
left[> Background > arm:> Player][stationary arm:notleft] -> [> Background > arm:> < Player][< arm:notleft]
right[> Background > arm:> Player][stationary arm:notright] -> [> Background > arm:> < Player][< arm:notright]
up[> Background > arm:> Player][stationary arm:notup] -> [> Background > arm:> < Player][< arm:notup]
down[> Background > arm:> Player][stationary arm:notdown] -> [> Background > arm:> < Player][< arm:notdown]
(check if a box is pushed against a wall)
[> box:nr | obstacle] -> [box:nr | obstacle]
(propagate non-movement through connected boxes)
[moving Box:1][stationary Box:1] -> [stationary Box:1][stationary Box:1]
[moving Box:2][stationary Box:2] -> [stationary Box:2][stationary Box:2]
[moving Box:3][stationary Box:3] -> [stationary Box:3][stationary Box:3]
[moving Box:4][stationary Box:4] -> [stationary Box:4][stationary Box:4]
[> Background > arm:>] -> [Background arm:>]
[stationary arm:>][> arm:directions][Player] -> [arm:>][arm:directions][Player]
[stationary arm:>][stationary arm:<][stationary arm:^][stationary arm:v][moving Player] -> [arm:>][arm:<][arm:^][arm:v][Player]
endloop
(arm pushing into spike -> dead)
[> Player][stationary Background > arm:> | spike] -> [dead Player][> Background > arm:> | spike]
[> arm:directions | spike][Player] -> [arm:directions | spike][dead Player]
[dead Player][> arm:directions] -> [dead stationary Player][arm:directions]
(cancel turn if an arm is pushing into a stationary object)
[> arm:directions | stationary object] -> cancel
=======================================================================================================
subroutine LATE-gravity-rules
=======================================================================================================
(clear falling from just fallen objects)
late [falling] -> []
(pushable thing becomes falling if nothing underneath, or if thing underneath is falling)
late down [pushable no falling| no object] -> [pushable falling | ]
late down [arm:directions | spike] -> [arm:directions falling | spike]
late down [pushable no falling | falling] -> [pushable falling | falling]
(propagate falling through connected boxes and through arms)
late [box:1 no falling][box:1 falling] -> [box:1 falling][box:1 falling]
+late [box:2 no falling][box:2 falling] -> [box:2 falling][box:2 falling]
+late [box:3 no falling][box:3 falling] -> [box:3 falling][box:3 falling]
+late [box:4 no falling][box:4 falling] -> [box:4 falling][box:4 falling]
+late [arm:directions no falling][arm:directions falling] -> [arm:directions falling][arm:directions falling]
(falling above not falling object -> not falling!)
late down [box:nr falling | object no falling] -> [box:nr | object]
+late down [arm:directions falling | object no spike no falling] -> [arm:directions | object]
(propagate not falling through connected boxes and through the arms)
+late [box:1 no falling][box:1 falling] -> [box:1 no falling][box:1 no falling]
+late [box:2 no falling][box:2 falling] -> [box:2 no falling][box:2 no falling]
+late [box:3 no falling][box:3 falling] -> [box:3 no falling][box:3 no falling]
+late [box:4 no falling][box:4 falling] -> [box:4 no falling][box:4 no falling]
+late [arm:directions no falling][arm:directions falling] -> [arm:directions no falling][arm:directions no falling]
late [arm:directions no falling][Player falling] -> [arm:directions no falling][Player]
late [arm:directions falling][Player no falling] -> [arm:directions falling][Player falling]
late down[falling Player | spike] -> [dead Player | spike]
late [roll_left] -> []
late [roll_right] -> []
=======================================================================================================
subroutine levitation-rules
=======================================================================================================
(give player movement based on cur:directions)
[Player cur:>] -> [> Player > cur:>]
(propagate player movement through arms)
[> Player][stationary arm:directions] -> [> Player][> arm:directions]
(give boxes movement based on cur:directions)
[stationary Box:nr cur:>] -> [> Box:nr > cur:>]
(Propagate movements through connected boxes)
+[> Box:1 cur:>][Box:1 no cur:>] -> [> Box:1 > cur:>][> Box:1 > cur:>]
+[> Box:2 cur:>][Box:2 no cur:>] -> [> Box:2 > cur:>][> Box:2 > cur:>]
+[> Box:3 cur:>][Box:3 no cur:>] -> [> Box:3 > cur:>][> Box:3 > cur:>]
+[> Box:4 cur:>][Box:4 no cur:>] -> [> Box:4 > cur:>][> Box:4 > cur:>]
(push off of a box)
[> arm:> stationary Player | stationary box:nr] -> [ > arm:> < Player < jumped < cur:< extends| > box:nr > cur:>]
(push off of a wall)
[> arm:> stationary Player | wall] -> [> arm:> < Player < jumped < cur:< | wall]
(push off of a spike -> deadly)
[> arm:> stationary Player | spike] -> [arm:> Player dead| spike]
(non-pushing arms get movement of player)
[> Player][stationary arm:directions] -> [> Player][> arm:directions]
(arm which you extended gets movement revoked)
[> Player][< arm:<] -> [> Player][arm:<]
(if arm hits a wall, stop player)
[> arm:directions | wall][moving Player cur:directions] -> [arm:directions | wall][Player]
(if arm hits a stationary pushable, transfer movement and stop player)
+[> arm:directions | stationary box:nr][> Player no jumped cur:>] -> [arm:directions | > box:nr > cur:>][Player stationary cur:>]
+[> arm:directions | stationary box:nr][> Player > jumped cur:>] -> [> arm:directions | > box:nr > cur:>][> Player > jumped stationary cur:>]
+[> arm:directions][Player no cur:>] -> [stationary arm:directions][Player]
(if arm hits spike, kill player)
+[> arm:directions | spike][moving Player cur:directions] -> [arm:directions | spike][Player dead]
[stationary cur:>] -> []
===================================================
(main loop for collisions with boxes in levitation)
===================================================
(box hits other box -> transfer movement/cur:dir)
[> box:nr > cur:> | stationary box:nr no lost_travel] -> [box:nr lost_travel | > box:nr > cur:>]
(propagate lost_travel through boxes)
+[lost_travel box:1][> box:1 cur:>] -> [lost_travel box:1][lost_travel box:1]
+[lost_travel box:2][> box:2 cur:>] -> [lost_travel box:2][lost_travel box:2]
+[lost_travel box:3][> box:3 cur:>] -> [lost_travel box:3][lost_travel box:3]
+[lost_travel box:4][> box:4 cur:>] -> [lost_travel box:4][lost_travel box:4]
(propagate movement/cur:dir through connected boxes)
+[stationary box:1][> box:1 > cur:>] -> [> box:1 > cur:>][> box:1 > cur:>]
+[stationary box:2][> box:2 > cur:>] -> [> box:2 > cur:>][> box:2 > cur:>]
+[stationary box:3][> box:3 > cur:>] -> [> box:3 > cur:>][> box:3 > cur:>]
+[stationary box:4][> box:4 > cur:>] -> [> box:4 > cur:>][> box:4 > cur:>]
(box hits a wall -> remove cur:dir and movement)
+[> box:nr cur:> | obstacle] -> [box:nr lost_travel | obstacle]
+[> box:nr cur:> | box:nr lost_travel] -> [box:nr lost_travel | box:nr lost_travel]
+[> arm:directions | lost_travel] -> [arm:directions lost_travel | lost_travel]
(remove cur:directions and movement from connected boxes)
+[stationary box:1][> box:1 cur:>] -> [box:1][box:1]
+[stationary box:2][> box:2 cur:>] -> [box:2][box:2]
+[stationary box:3][> box:3 cur:>] -> [box:3][box:3]
+[stationary box:4][> box:4 cur:>] -> [box:4][box:4]
====================
(end of loop)
====================
[arm:directions lost_travel][> Player cur:>] -> [arm:directions][Player]
[stationary Player][> arm:directions] -> [Player][arm:directions]
(remove temp objects)
[lost_travel] -> []
[roll_left] -> []
[roll_right] -> []
================================================================================
subroutine LATE-levitation-rules
================================================================================
late [Player cur:directions | jumped] -> [Player | ]
(manually move arm after pushing a box)
late [arm:> extends | no object | box:nr cur:>][Player no cur:directions] -> [ | arm:> extends | box:nr cur:>][Player]
==============
WINCONDITIONS
==============
all Player on Target
=======
LEVELS
=======
section 1
g#####
##...#
#...##
#....o
#..#.#
##...#
#p...#
######
section 2
g########
#s......#
#.......#
#....#..#
#..#....o
#.......#
#.......#
#p......#
###s#s###
(section 3
g###########
#..#....#..#
#..........#
#........#.#
#...#s...s.#
#.s....#...#
#.#....s...#
#..........#
#.s#s......#
#..#.......o
#p.........s
###s###s####)
section 3
g#########
#........#
#..ss..3.#
#..ss..2p#
s.4...s###
####..##.o
#........#
#.....#..#
##.....#s#
##########
section 4
g########
#..###..#
#.......#
#...3...#
#...#...#
#.......o
#.......#
#.......#
#p....###
#########
section 5
go#########
#......####
#..#......#
#s..p.....#
#...##....#
#....1..#.#
#...###...#
##......###
####....###
###########
(x#####
##...#
#...##
#....o
#..#.#
##...#
#p...#
######
x#########
#.########
o.#..1.###
#...p2..##
#..###...#
#........#
#.......##
##########
x##########
#..3.....##
#.s#....###
#..s.42..##
#....#s..##
#.....#...o
#........s#
#p.......##
######..###
###########
x#########
#........#
#..ss..3.#
#..ss..2p#
s.4...s###
####..##.o
#........#
#.....#..#
##.....#s#
##########
x########o####
##..........##
#.......#...##
#...4.3.#...##
#...####....##
#p..........##
#####..#.....#
s.s.##.##....#
....s#.......#
.....#..#s.s##
....s#########)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment