MODULE GAMEPAD
VAR LEFT: BOOL
VAR RIGHT: BOOL
VAR UP: BOOL
VAR DOWN: BOOL
VAR BUTTON_A: BOOL
VAR BUTTON_B: BOOL
VAR BUTTON_C: BOOL
VAR BUTTON_D: BOOL
END MODULE
CLASS TILE_LAYER
VAR TILEMAP: TILEMAP
VAR TILESET: TILESET
VAR IO_TILEMAP: IO_TILEMAP
VAR IO_TILESET_ADDRESSES: INT[SIZE 1024]
VAR X: INT, Y: INT
VAR SCREEN_SPACE: BOOL
VAR WRAP: BOOL
VAR _TILE_DIMENSION: INT
FUNC NEW(IO_TILEMAP: IO_TILEMAP, IO_TILESET_ADDRESSES: INT[SIZE 1024])
IO_TILEMAP -> .IO_TILEMAP
IO_TILESET_ADDRESSES -> .IO_TILESET_ADDRESSES
END FUNC
FUNC LOAD_TILESET(TILESET: TILESET)
TILESET -> .TILESET
VAR IO_TILEMAP: IO_TILEMAP
.IO_TILEMAP -> IO_TILEMAP
VAR IO_TILESET_ADDRESSES: INT[SIZE 1024]
.IO_TILESET_ADDRESSES -> IO_TILESET_ADDRESSES
IF TILESET = NULL THEN
0 -> IO_TILEMAP.JUMBO
0 -> IO_TILEMAP.TILE_COUNT
RETURN
END IF
VAR OLD_TILE_COUNT: PAIR
IO_TILEMAP.TILE_COUNT -> OLD_TILE_COUNT
VAR TILE_COUNT: PAIR, P: PAIR
IF TILESET.JUMBO THEN
1 -> IO_TILEMAP.JUMBO
16 -> ._TILE_DIMENSION
ELSE
0 -> IO_TILEMAP.JUMBO
8 -> ._TILE_DIMENSION
END IF
TO_PAIR(TILESET.TILES.SIZE) -> TILE_COUNT
IF TILE_COUNT > 1024
DO 1024 -> TILE_COUNT
TILE_COUNT -> IO_TILEMAP.TILE_COUNT
0 -> P
LOOP
IF P >= TILE_COUNT
DO DROP
VAR TILE: TILE
TILESET.TILES[P] -> TILE
IF TILE <> NULL THEN
TO_ADDRESS(TILE.PIXELS) + 3 -> IO_TILESET_ADDRESSES[P]
END IF
TO_PAIR(P + 1) -> P
END LOOP
LOOP
IF P >= OLD_TILE_COUNT
DO DROP
0 -> IO_TILESET_ADDRESSES[P]
TO_PAIR(P + 1) -> P
END LOOP
END FUNC
FUNC LOAD_TILEMAP(TILEMAP: TILEMAP)
TILEMAP -> .TILEMAP
VAR IO_TILEMAP: IO_TILEMAP
.IO_TILEMAP -> IO_TILEMAP
IF TILEMAP = NULL THEN
0 -> IO_TILEMAP.COL_COUNT
0 -> IO_TILEMAP.ROW_COUNT
0 -> IO_TILEMAP.TILE_CODES_ADDRESS
0 -> IO_TILEMAP.EDGE_MODE
RETURN
END IF
TILEMAP.COL_COUNT -> IO_TILEMAP.COL_COUNT
TILEMAP.ROW_COUNT -> IO_TILEMAP.ROW_COUNT
TO_ADDRESS(TILEMAP.TILE_CODES) + 3 -> IO_TILEMAP.TILE_CODES_ADDRESS
END FUNC
FUNC _RENDER()
VAR IO_TILEMAP: IO_TILEMAP
.IO_TILEMAP -> IO_TILEMAP
IF .TILEMAP <> NULL THEN
VAR X: INT, Y: INT
VAR X_PAIR: PAIR, Y_PAIR: PAIR
.X -> X
.Y -> Y
IF NOT .SCREEN_SPACE THEN
X - ENGINE::CAMERA_X -> X
Y - ENGINE::CAMERA_Y -> Y
END IF
TO_PAIR(X) -> X_PAIR
TO_PAIR(Y) -> Y_PAIR
VAR CLIP_EDGE: BOOL
NOT .WRAP -> CLIP_EDGE
TO_BYTE(CLIP_EDGE) -> IO_TILEMAP.EDGE_MODE
IF CLIP_EDGE AND (X_PAIR <> X OR Y_PAIR <> Y) THEN
-16384 -> IO_TILEMAP.X
ELSE
X_PAIR -> IO_TILEMAP.X
Y_PAIR -> IO_TILEMAP.Y
END IF
END IF
END FUNC
FUNC GET_TILE_AT_COLROW(COL: INT, ROW: INT): PAIR
VAR TILEMAP: TILEMAP
.TILEMAP -> TILEMAP
VAR TILE_CODE: PAIR
VAR COL_COUNT: INT, ROW_COUNT: INT
TILEMAP.COL_COUNT -> COL_COUNT
TILEMAP.ROW_COUNT -> ROW_COUNT
IF COL >= 0 AND COL < COL_COUNT AND ROW >= 0 AND ROW < ROW_COUNT THEN
TILEMAP.TILE_CODES[ROW * COL_COUNT + COL] -> TILE_CODE
ELSE
-1 -> TILE_CODE
END IF
RETURN TILE_CODE
END FUNC
FUNC SET_TILE_AT_COLROW(COL: INT, ROW: INT, TILE_CODE: PAIR)
VAR TILEMAP: TILEMAP
.TILEMAP -> TILEMAP
VAR COL_COUNT: INT, ROW_COUNT: INT
TILEMAP.COL_COUNT -> COL_COUNT
TILEMAP.ROW_COUNT -> ROW_COUNT
IF COL >= 0 AND COL < COL_COUNT AND ROW >= 0 AND ROW < ROW_COUNT THEN
TILE_CODE -> TILEMAP.TILE_CODES[ROW * COL_COUNT + COL]
END IF
END FUNC
FUNC GET_TILE_AT_XY(X: INT, Y: INT): PAIR
VAR TILE_DIMENSION: INT
._TILE_DIMENSION -> TILE_DIMENSION
VAR RESULT: PAIR
.GET_TILE_AT_COLROW(X / TILE_DIMENSION, Y / TILE_DIMENSION) -> RESULT
RETURN RESULT
END FUNC
FUNC SET_TILE_AT_XY(X: INT, Y: INT, TILE_CODE: PAIR)
VAR TILE_DIMENSION: INT
._TILE_DIMENSION -> TILE_DIMENSION
.SET_TILE_AT_COLROW(X / TILE_DIMENSION, Y / TILE_DIMENSION, TILE_CODE)
END FUNC
FUNC GET_COLOR_AT_XY(X: INT, Y: INT): BYTE
VAR TILE_CODE: PAIR, TX: INT, TY: INT
VAR TILE: TILE, COLOR: BYTE
VAR TILESET: TILESET
.TILESET -> TILESET
VAR TILE_DIMENSION: INT
._TILE_DIMENSION -> TILE_DIMENSION
.GET_TILE_AT_COLROW(X / TILE_DIMENSION, Y / TILE_DIMENSION) -> TILE_CODE
VAR TILE_INDEX: PAIR
TO_PAIR(MATH::BIT_AND(TILE_CODE, $03FF)) -> TILE_INDEX
IF TILE_CODE >= 0 AND TILE_INDEX < TILESET.TILES.SIZE THEN
TILESET.TILES[TILE_INDEX] -> TILE
IF TILE <> NULL THEN
X % TILE_DIMENSION -> TX
Y % TILE_DIMENSION -> TY
TILE.PIXELS[TY * TILE_DIMENSION + TX] -> COLOR
RETURN COLOR
END IF
END IF
0 -> COLOR
RETURN COLOR
END FUNC
END CLASS
MODULE ENGINE
VAR CAMERA_X: INT, CAMERA_Y: INT
VAR TILE_LAYER_A: TILE_LAYER
VAR TILE_LAYER_B: TILE_LAYER
VAR TILE_LAYER_C: TILE_LAYER
VAR FRAME_COUNTER: PAIR
VAR _THINKLIST_HEAD: ACTOR
VAR _THINKLIST_TAIL: ACTOR
VAR _RENDERLIST_FENCE: ACTOR
VAR _INSERTION_POINTS: ACTOR[SIZE 4]
VAR _LAST_RENDER_ACTOR: ACTOR
VAR _ACTOR_COUNT: INT
VAR _USED_SPRITES: INT
VAR _BUSY: BYTE
FUNC INIT()
0 -> IO::PAINT_MODE
IO::FRAME_COUNTER -> ENGINE::FRAME_COUNTER
NULL -> ENGINE::_THINKLIST_HEAD
NULL -> ENGINE::_THINKLIST_TAIL
VAR INSERTION_POINTS: ACTOR[SIZE 4]
NEW ACTOR[SIZE 4]() -> INSERTION_POINTS
INSERTION_POINTS -> ENGINE::_INSERTION_POINTS
VAR RENDERLIST_FENCE: ACTOR
NEW ACTOR() -> RENDERLIST_FENCE
RENDERLIST_FENCE -> RENDERLIST_FENCE._RENDERLIST_PREV_LINK
RENDERLIST_FENCE -> RENDERLIST_FENCE._RENDERLIST_NEXT_LINK
RENDERLIST_FENCE -> INSERTION_POINTS[0]
RENDERLIST_FENCE -> INSERTION_POINTS[1]
RENDERLIST_FENCE -> INSERTION_POINTS[2]
RENDERLIST_FENCE -> INSERTION_POINTS[3]
RENDERLIST_FENCE -> ENGINE::_LAST_RENDER_ACTOR
RENDERLIST_FENCE -> ENGINE::_RENDERLIST_FENCE
0 -> ENGINE::_ACTOR_COUNT
0 -> ENGINE::_USED_SPRITES
IO::BACKGROUND_COLOR <-- 13
NEW TILE_LAYER(IO::TILEMAP_A, IO::TILESET_A_ADDRESSES)
| -> ENGINE::TILE_LAYER_A
NEW TILE_LAYER(IO::TILEMAP_B, IO::TILESET_B_ADDRESSES)
| -> ENGINE::TILE_LAYER_B
NEW TILE_LAYER(IO::TILEMAP_C, IO::TILESET_C_ADDRESSES)
| -> ENGINE::TILE_LAYER_C
END FUNC
FUNC LOAD_ACTOR_SPOT(SPOT: S_ACTOR_SPOT): ACTOR
VAR ACTOR: ACTOR
IF SPOT.ACTOR_FACTORY <> NULL THEN
SPOT.ACTOR_FACTORY() -> ACTOR
ELSE
NEW ACTOR() -> ACTOR
END IF
ACTOR.APPLY_SPOT(SPOT)
ENGINE::ADD_ACTOR_BEHIND(ACTOR)
RETURN ACTOR
END FUNC
FUNC LOAD_ACTOR_SPOTS(SPOTS: S_ACTOR_SPOT[])
VAR I, SIZE
SPOTS.SIZE -> SIZE
0 -> I
LOOP
IF I >= SIZE
DO DROP
ENGINE::LOAD_ACTOR_SPOT(SPOTS[I])
I + 1 -> I
END LOOP
END FUNC
FUNC CLEAR_ACTORS()
VAR OLD_BUSY: BYTE
ENGINE::_BUSY -> OLD_BUSY
IF OLD_BUSY = 3
DO RETURN
IF OLD_BUSY = 2
DO KERNEL::FAIL("OPERATION IS NOT ALLOWED")
3 -> ENGINE::_BUSY
VAR ACTOR: ACTOR
ENGINE::_THINKLIST_HEAD -> ACTOR
LOOP
IF ACTOR = NULL
DO DROP
IF ACTOR._RENDERLIST_PREV_LINK <> NULL THEN
NULL -> ACTOR._RENDERLIST_PREV_LINK
NULL -> ACTOR._RENDERLIST_NEXT_LINK
ENGINE::_ACTOR_COUNT - 1 -> ENGINE::_ACTOR_COUNT
ACTOR.ON_REMOVED()
END IF
ACTOR._THINKLIST_NEXT_LINK -> ACTOR
END LOOP
ENGINE::_PRUNE_THINKLIST()
VAR RENDERLIST_FENCE: ACTOR
ENGINE::_RENDERLIST_FENCE -> RENDERLIST_FENCE
RENDERLIST_FENCE -> RENDERLIST_FENCE._RENDERLIST_PREV_LINK
RENDERLIST_FENCE -> RENDERLIST_FENCE._RENDERLIST_NEXT_LINK
VAR INSERTION_POINTS: ACTOR[SIZE 4]
ENGINE::_INSERTION_POINTS -> INSERTION_POINTS
RENDERLIST_FENCE -> INSERTION_POINTS[0]
RENDERLIST_FENCE -> INSERTION_POINTS[1]
RENDERLIST_FENCE -> INSERTION_POINTS[2]
RENDERLIST_FENCE -> INSERTION_POINTS[3]
RENDERLIST_FENCE -> ENGINE::_LAST_RENDER_ACTOR
0 -> ENGINE::_ACTOR_COUNT
OLD_BUSY -> ENGINE::_BUSY
END FUNC
FUNC ADD_ACTOR(ACTOR: ACTOR)
ENGINE::_ADD_ACTOR(ACTOR, FALSE)
ACTOR.ON_ADDED()
END FUNC
FUNC ADD_ACTOR_BEHIND(ACTOR: ACTOR)
ENGINE::_ADD_ACTOR(ACTOR, TRUE)
ACTOR.ON_ADDED()
END FUNC
FUNC _ADD_ACTOR(ACTOR: ACTOR, BEHIND: BOOL)
IF ENGINE::_BUSY >= 2
DO KERNEL::FAIL("OPERATION IS NOT ALLOWED")
IF ACTOR._RENDERLIST_PREV_LINK <> NULL
DO KERNEL::FAIL("ACTOR ALREADY ADDED")
IF ENGINE::_THINKLIST_TAIL = NULL THEN
ACTOR -> ENGINE::_THINKLIST_HEAD
ACTOR -> ENGINE::_THINKLIST_TAIL
NULL -> ACTOR._THINKLIST_NEXT_LINK
ELSIF ACTOR._THINKLIST_NEXT_LINK = NULL
| AND ENGINE::_THINKLIST_TAIL <> ACTOR THEN
ACTOR -> ENGINE::_THINKLIST_TAIL._THINKLIST_NEXT_LINK
ACTOR -> ENGINE::_THINKLIST_TAIL
END IF
VAR INSERTION_POINTS: ACTOR[SIZE 4]
ENGINE::_INSERTION_POINTS -> INSERTION_POINTS
VAR DEPTH: BYTE
ACTOR._DEPTH -> DEPTH
VAR INSERTION_POINT: ACTOR
INSERTION_POINTS[DEPTH] -> INSERTION_POINT
IF BEHIND THEN
VAR NEXT_INSERTION_POINT: ACTOR
IF DEPTH < 3 THEN
INSERTION_POINTS[DEPTH + 1] -> NEXT_INSERTION_POINT
ELSE
ENGINE::_RENDERLIST_FENCE -> NEXT_INSERTION_POINT
END IF
IF INSERTION_POINT = NEXT_INSERTION_POINT THEN
FALSE -> BEHIND
ELSE
NEXT_INSERTION_POINT -> INSERTION_POINT
END IF
END IF
INSERTION_POINT -> ACTOR._RENDERLIST_NEXT_LINK
INSERTION_POINT._RENDERLIST_PREV_LINK -> ACTOR._RENDERLIST_PREV_LINK
ACTOR -> ACTOR._RENDERLIST_PREV_LINK._RENDERLIST_NEXT_LINK
ACTOR -> INSERTION_POINT._RENDERLIST_PREV_LINK
IF NOT BEHIND THEN
ACTOR -> INSERTION_POINTS[DEPTH]
LOOP
IF DEPTH = 0
DO DROP
TO_BYTE(DEPTH - 1) -> DEPTH
IF INSERTION_POINTS[DEPTH] = INSERTION_POINT
DO ACTOR -> INSERTION_POINTS[DEPTH]
END LOOP
END IF
ENGINE::_ACTOR_COUNT + 1 -> ENGINE::_ACTOR_COUNT
END FUNC
FUNC REMOVE_ACTOR(ACTOR: ACTOR)
ENGINE::_REMOVE_ACTOR(ACTOR)
ACTOR.ON_REMOVED()
END FUNC
FUNC _REMOVE_ACTOR(ACTOR: ACTOR)
IF ENGINE::_BUSY = 2
DO KERNEL::FAIL("OPERATION IS NOT ALLOWED")
VAR INSERTION_POINTS: ACTOR[SIZE 4]
VAR NEXT_LINK: ACTOR
ENGINE::_INSERTION_POINTS -> INSERTION_POINTS
ACTOR._RENDERLIST_NEXT_LINK -> NEXT_LINK
IF NEXT_LINK = NULL OR ACTOR = ENGINE::_RENDERLIST_FENCE
DO KERNEL::FAIL("ACTOR NOT ADDED")
IF INSERTION_POINTS[0] = ACTOR
DO NEXT_LINK -> INSERTION_POINTS[0]
IF INSERTION_POINTS[1] = ACTOR
DO NEXT_LINK -> INSERTION_POINTS[1]
IF INSERTION_POINTS[2] = ACTOR
DO NEXT_LINK -> INSERTION_POINTS[2]
IF INSERTION_POINTS[3] = ACTOR
DO NEXT_LINK -> INSERTION_POINTS[3]
IF ENGINE::_LAST_RENDER_ACTOR = ACTOR
DO ACTOR._RENDERLIST_PREV_LINK -> ENGINE::_LAST_RENDER_ACTOR
ACTOR._RENDERLIST_PREV_LINK -> ACTOR._RENDERLIST_NEXT_LINK._RENDERLIST_PREV_LINK
ACTOR._RENDERLIST_NEXT_LINK -> ACTOR._RENDERLIST_PREV_LINK._RENDERLIST_NEXT_LINK
NULL -> ACTOR._RENDERLIST_PREV_LINK
NULL -> ACTOR._RENDERLIST_NEXT_LINK
ENGINE::_ACTOR_COUNT - 1 -> ENGINE::_ACTOR_COUNT
END FUNC
FUNC GET_FIRST_ACTOR(): ACTOR
VAR ACTOR: ACTOR
ENGINE::_THINKLIST_HEAD -> ACTOR
LOOP
IF ACTOR = NULL OR ACTOR._RENDERLIST_PREV_LINK <> NULL
DO DROP
ACTOR._THINKLIST_NEXT_LINK -> ACTOR
END LOOP
RETURN ACTOR
END FUNC
FUNC GET_NEXT_ACTOR(CURRENT: ACTOR): ACTOR
VAR ACTOR: ACTOR
IF CURRENT = NULL THEN
NULL -> ACTOR
ELSE
CURRENT._THINKLIST_NEXT_LINK -> ACTOR
LOOP
IF ACTOR = NULL OR ACTOR._RENDERLIST_PREV_LINK <> NULL
DO DROP
ACTOR._THINKLIST_NEXT_LINK -> ACTOR
END LOOP
END IF
RETURN ACTOR
END FUNC
FUNC _PRUNE_THINKLIST()
VAR CURRENT: ACTOR
VAR PREVIOUS: ACTOR
NULL -> PREVIOUS
ENGINE::_THINKLIST_HEAD -> CURRENT
LOOP
IF CURRENT = NULL THEN
IF PREVIOUS = NULL THEN
NULL -> ENGINE::_THINKLIST_HEAD
NULL -> ENGINE::_THINKLIST_TAIL
ELSE
PREVIOUS -> ENGINE::_THINKLIST_TAIL
NULL -> PREVIOUS._THINKLIST_NEXT_LINK
END IF
DROP
END IF
VAR NEXT: ACTOR
CURRENT._THINKLIST_NEXT_LINK -> NEXT
IF CURRENT._RENDERLIST_PREV_LINK = NULL THEN
NULL -> CURRENT._THINKLIST_NEXT_LINK
ELSE
IF PREVIOUS = NULL THEN
CURRENT -> ENGINE::_THINKLIST_HEAD
ELSE
CURRENT -> PREVIOUS._THINKLIST_NEXT_LINK
END IF
CURRENT -> PREVIOUS
END IF
NEXT -> CURRENT
END LOOP
END FUNC
FUNC GET_CAMERA_CX(): INT
VAR RESULT
ENGINE::CAMERA_X + 160 -> RESULT
RETURN RESULT
END FUNC
FUNC SET_CAMERA_CX(VALUE: INT)
VALUE - 160 -> ENGINE::CAMERA_X
END FUNC
FUNC GET_CAMERA_CY(): INT
VAR RESULT
ENGINE::CAMERA_Y + 112 -> RESULT
RETURN RESULT
END FUNC
FUNC SET_CAMERA_CY(VALUE: INT)
VALUE - 112 -> ENGINE::CAMERA_Y
END FUNC
FUNC RENDER()
IF ENGINE::_BUSY <> 0
DO KERNEL::FAIL("OPERATION IS NOT ALLOWED")
2 -> ENGINE::_BUSY
ENGINE::TILE_LAYER_A._RENDER()
ENGINE::TILE_LAYER_B._RENDER()
ENGINE::TILE_LAYER_C._RENDER()
VAR FRAME_DELTA: PAIR
ENGINE::FRAME_COUNTER -> FRAME_DELTA
IO::FRAME_COUNTER -> ENGINE::FRAME_COUNTER
TO_PAIR(ENGINE::FRAME_COUNTER - FRAME_DELTA) -> FRAME_DELTA
IF FRAME_DELTA < 0
DO 1 -> FRAME_DELTA
VAR RENDERLIST_FENCE: ACTOR
VAR END_ACTOR: ACTOR
ENGINE::_RENDERLIST_FENCE -> RENDERLIST_FENCE
ENGINE::_LAST_RENDER_ACTOR -> END_ACTOR
VAR SPRITE_INDEX: INT
0 -> SPRITE_INDEX
IF END_ACTOR = RENDERLIST_FENCE THEN
RENDERLIST_FENCE._RENDERLIST_PREV_LINK -> END_ACTOR
END IF
IF END_ACTOR <> RENDERLIST_FENCE THEN
VAR SPRITES_LEFT: BYTE
64 -> SPRITES_LEFT
VAR ACTOR: ACTOR
END_ACTOR -> ACTOR
LOOP
ACTOR._RENDERLIST_NEXT_LINK -> ACTOR
IF ACTOR = RENDERLIST_FENCE
DO DROP
IF ACTOR.VISIBLE THEN
TO_BYTE(SPRITES_LEFT - 1) -> SPRITES_LEFT
IF SPRITES_LEFT = 0
DO DROP
END IF
END LOOP
IF SPRITES_LEFT = 0 THEN
ACTOR -> ENGINE::_LAST_RENDER_ACTOR
ELSE
LOOP
ACTOR._RENDERLIST_NEXT_LINK -> ACTOR
IF ACTOR.VISIBLE THEN
ACTOR.RENDER(SPRITE_INDEX, FRAME_DELTA)
SPRITE_INDEX + 1 -> SPRITE_INDEX
TO_BYTE(SPRITES_LEFT - 1) -> SPRITES_LEFT
IF SPRITES_LEFT = 0
DO DROP
END IF
IF ACTOR = END_ACTOR
DO DROP
END LOOP
ACTOR -> ENGINE::_LAST_RENDER_ACTOR
END IF
64 -> SPRITES_LEFT
END_ACTOR -> ACTOR
LOOP
ACTOR._RENDERLIST_NEXT_LINK -> ACTOR
IF ACTOR = RENDERLIST_FENCE
DO DROP
IF ACTOR.VISIBLE THEN
ACTOR.RENDER(SPRITE_INDEX, FRAME_DELTA)
SPRITE_INDEX + 1 -> SPRITE_INDEX
TO_BYTE(SPRITES_LEFT - 1) -> SPRITES_LEFT
IF SPRITES_LEFT = 0
DO DROP
END IF
END LOOP
END IF
VAR I: INT
SPRITE_INDEX -> I
LOOP
IF I >= ENGINE::_USED_SPRITES
DO DROP
IF I >= 64
DO DROP
0 -> IO::SPRITES[I].PIXELS_ADDRESS
I + 1 -> I
END LOOP
SPRITE_INDEX -> ENGINE::_USED_SPRITES
0 -> ENGINE::_BUSY
END FUNC
FUNC WAIT_FOR_PAINT()
1 -> IO::IRQ_PENDING
3 -> IO::PAINT_MODE
1 -> IO::IRQ_WAKE_MASK
KERNEL::SLEEP()
END FUNC
FUNC THINK()
IF ENGINE::_BUSY <> 0
DO KERNEL::FAIL("OPERATION IS NOT ALLOWED")
1 -> ENGINE::_BUSY
VAR BUTTONS: BYTE
IO::GAMEPAD_0.BUTTONS --> BUTTONS
MATH::BIT_AND(BUTTONS, 1) <> 0 -> GAMEPAD::BUTTON_A
MATH::BIT_AND(BUTTONS, 2) <> 0 -> GAMEPAD::BUTTON_B
MATH::BIT_AND(BUTTONS, 4) <> 0 -> GAMEPAD::BUTTON_C
MATH::BIT_AND(BUTTONS, 8) <> 0 -> GAMEPAD::BUTTON_D
FALSE -> GAMEPAD::LEFT
FALSE -> GAMEPAD::RIGHT
FALSE -> GAMEPAD::UP
FALSE -> GAMEPAD::DOWN
VAR P: PAIR
IO::GAMEPAD_0.X -> P
IF P >= 512 THEN
TRUE -> GAMEPAD::RIGHT
ELSIF P <= -512 THEN
TRUE -> GAMEPAD::LEFT
END IF
IO::GAMEPAD_0.Y -> P
IF P >= 512 THEN
TRUE -> GAMEPAD::DOWN
ELSIF P <= -512 THEN
TRUE -> GAMEPAD::UP
END IF
VAR ACTOR: ACTOR
ENGINE::GET_FIRST_ACTOR() -> ACTOR
LOOP
IF ACTOR = NULL
DO DROP
IF ACTOR._RENDERLIST_PREV_LINK <> NULL
DO ACTOR.THINK()
ENGINE::GET_NEXT_ACTOR(ACTOR) -> ACTOR
END LOOP
ENGINE::_PRUNE_THINKLIST()
0 -> ENGINE::_BUSY
END FUNC
END MODULE