Skip to content

Zyndric/Soko-Chan

Repository files navigation

namespace SpriteKind { export const Crate = SpriteKind.create() } function reset_states () { pressed_up = 0 pressed_down = 0 pressed_left = 0 pressed_right = 0 pressed_A = 0 pressed_B = 0 undo = [] count_moves = 0 count_pushes = 0 tiles.destroySpritesOfKind(SpriteKind.Player) tiles.destroySpritesOfKind(SpriteKind.Crate) tiles.destroySpritesOfKind(SpriteKind.Text) scene.centerCameraAt(80, 60) } function set_up_selection () { state_level = 0 button_lag = 6 menu_selection = 1 select_level = level select_levelset = levelset scene.centerCameraAt(80, 60) mySprite2 = sprites.create(assets.imagebg selection, SpriteKind.Text) text_title = textsprite.create(" ", 0, 7) text_title.setMaxFontHeight(8) text_title.setPosition(24, 15) text_title.setBorder(1, 0, 2) text_title.setText("Soko-Chan Menu") menu_items = [] add_menu_item(35, "Group", true) add_menu_item(50, "Level", true) add_menu_item(65, "Help", false) add_menu_item(80, "Credits", false) text_footer = textsprite.create("=Choose A=OK B=Back", 0, 13) text_footer.setMaxFontHeight(8) text_footer.setIcon(assets.imageicon arrows updown) text_footer.setPosition(80, 110) minimap = sprites.create(scale_thumbnail(get_level_asset(select_levelset, select_level)), SpriteKind.Text) minimap.setPosition(122, 64) text_best = textsprite.create("00/00", 0, 6) text_best.setMaxFontHeight(8) text_best.setPosition(120, 90) hilight_menu_item() draw_selection() state_selection = 1 reset_buttons() } function set_up_level () { reset_states() state_selection = 0 blockSettings.writeNumber("recent group", levelset) blockSettings.writeNumber("recent level", level) scene.setTileMap(get_level_asset(levelset, level)) set_level_skin(false) realize_tilemap() return_to_level() introduce_level() } function reset_buttons () { pressed_up = button_lag pressed_down = button_lag pressed_left = button_lag pressed_right = button_lag pressed_A = button_lag pressed_B = button_lag } function get_level_asset_cantrip (lv: number) { if (lv == 1) { return assets.imagelevel cantrip 01 } else if (lv == 2) { return assets.imagelevel cantrip 02 } else if (lv == 3) { return assets.imagelevel cantrip 03 } else if (lv == 4) { return assets.imagelevel cantrip 04 } else if (lv == 5) { return assets.imagelevel cantrip 05 } else if (lv == 6) { return assets.imagelevel cantrip 06 } else if (lv == 7) { return assets.imagelevel cantrip 07 } else if (lv == 8) { return assets.imagelevel cantrip 08 } else if (lv == 9) { return assets.imagelevel cantrip 09 } else if (lv == 10) { return assets.imagelevel cantrip 10 } else if (lv == 11) { return assets.imagelevel cantrip 11 } else if (lv == 12) { return assets.imagelevel cantrip 12 } else if (lv == 13) { return assets.imagelevel cantrip 13 } else if (lv == 14) { return assets.imagelevel cantrip 14 } else if (lv == 15) { return assets.imagelevel cantrip 15 } else if (lv == 16) { return assets.imagelevel cantrip 16 } else if (lv == 17) { return assets.imagelevel cantrip 17 } else if (lv == 18) { return assets.imagelevel cantrip 18 } else if (lv == 19) { return assets.imagelevel cantrip 19 } else if (lv == 20) { return assets.imagelevel cantrip 20 } return assets.imagelevel cantrip 01 } function get_level_asset_declercq (lv: number) { return [ assets.imagelevel blocks 01, assets.imagelevel blocks 02, assets.imagelevel blocks 03, assets.imagelevel blocks 04, assets.imagelevel blocks 05, assets.imagelevel blocks 06, assets.imagelevel blocks 07, assets.imagelevel blocks 08, assets.imagelevel blocks 09, assets.imagelevel blocks 10, assets.imagelevel various 01, assets.imagelevel various 02, assets.imagelevel various 03, assets.imagelevel various 04, assets.imagelevel various 05, assets.imagelevel various 06, assets.imagelevel various 07, assets.imagelevel various 08, assets.imagelevel various 09, assets.imagelevel various 10 ][lv - 1] } function add_menu_item (y: number, text: string, changeable: boolean) { t = textsprite.create(" ", 0, 6) t.setMaxFontHeight(8) t.setPosition(24, y) if (changeable) { t.setIcon(assets.imageicon arrows leftright) } t.setBorder(1, 0, 2) t.setText(text) menu_items[menu_items.length] = t } function get_level_asset_petitesse (lv: number) { if (lv == 1) { return assets.imagelevel petitesse 01 } else if (lv == 2) { return assets.imagelevel petitesse 02 } else if (lv == 3) { return assets.imagelevel petitesse 03 } else if (lv == 4) { return assets.imagelevel petitesse 04 } else if (lv == 5) { return assets.imagelevel petitesse 05 } else if (lv == 6) { return assets.imagelevel petitesse 06 } else if (lv == 7) { return assets.imagelevel petitesse 07 } else if (lv == 8) { return assets.imagelevel petitesse 08 } else if (lv == 9) { return assets.imagelevel petitesse 09 } else if (lv == 10) { return assets.imagelevel petitesse 10 } else if (lv == 11) { return assets.imagelevel petitesse 11 } else if (lv == 12) { return assets.imagelevel petitesse 12 } else if (lv == 13) { return assets.imagelevel petitesse 13 } else if (lv == 14) { return assets.imagelevel petitesse 14 } else if (lv == 15) { return assets.imagelevel petitesse 15 } else if (lv == 16) { return assets.imagelevel petitesse 16 } else if (lv == 17) { return assets.imagelevel petitesse 17 } else if (lv == 18) { return assets.imagelevel petitesse 18 } return assets.imagelevel petitesse 01 } function update_moves () { update_camera() text_moves.setText("" + convertToText(count_moves) + "/" + convertToText(count_pushes)) text_moves.setPosition(scene.cameraProperty(CameraProperty.X) + 81 - text_moves.width / 2, scene.cameraProperty(CameraProperty.Y) - 55) } function set_level_skin (random: boolean) { level_skin = levelset if (random) { level_skin = randint(1, 9) } if (level_skin == 1) { list_skin_sprites = [assets.imagewall purple bricks, assets.imagecrate wood, assets.imagecrate wood on target, assets.imagefloor dark purple, assets.imagetarget dark purple] } else if (level_skin == 2) { list_skin_sprites = [assets.imagewall steel, assets.imagecrate wood2, assets.imagecrate wood2 on target, assets.imagefloor tan dotted, assets.imagetarget tan dotted] } else if (level_skin == 3) { list_skin_sprites = [assets.imagewall dark brown bricks, assets.imagecrate drawer, assets.imagecrate drawer on target, assets.imagefloor tan dotted, assets.imagetarget tan dotted] } else if (level_skin == 4) { list_skin_sprites = [assets.imagewall dark purple bricks, assets.imagecrate wood2, assets.imagecrate wood2 on target, assets.imagefloor tan dotted, assets.imagetarget tan dotted] } else if (level_skin == 5) { list_skin_sprites = [assets.imagewall steel, assets.imagecrate wood2, assets.imagecrate wood2 on target, assets.imagefloor tan dotted, assets.imagetarget tan dotted] } else if (level_skin == 6) { list_skin_sprites = [assets.imagewall dark steel, assets.imagecrate chest, assets.imagecrate chest on target, assets.imagefloor light purple dotted, assets.imagetarget light purple dotted] } else if (level_skin == 7) { list_skin_sprites = [assets.imagewall steel, assets.imagecrate wood, assets.imagecrate wood on target, assets.imagefloor tan dotted, assets.imagetarget tan dotted] } else if (level_skin == 8) { list_skin_sprites = [assets.imagewall dark brown bricks, assets.imagecrate drawer, assets.imagecrate drawer on target, assets.imagefloor tan dotted, assets.imagetarget tan dotted] } else if (level_skin == 9) { list_skin_sprites = [assets.imagewall teal bricks, assets.imagecrate wood, assets.imagecrate wood on target, assets.imagefloor tan dotted, assets.imagetarget tan dotted] } else { list_skin_sprites = [assets.imagewall steel, assets.imagecrate wood, assets.imagecrate wood on target, assets.imagefloor tan dotted, assets.imagetarget tan dotted] } } function level_best_id (group: number, level: number) { return "best-" + convertToText(group) + "-" + convertToText(level) } function scale_thumbnail (src: Image) { thumbnail = image.create(45, 36) for (let x = 0; x <= 14; x++) { for (let y = 0; y <= 11; y++) { thumbnail.fillRect(x * 3, y * 3, 3, 3, src.getPixel(x, y)) } } thumbnail.drawLine(0, 0, 44, 0, 6) thumbnail.drawLine(0, 35, 44, 35, 6) thumbnail.drawLine(0, 0, 0, 35, 6) thumbnail.drawLine(44, 0, 44, 35, 6) return thumbnail } function show_help () { game.showLongText("--- Soko-Chan Help --- " + " " + "Push the crates onto " + "the targets. You win " + "when all targets are " + "occupied by crates." + " " + " " + "- Arrow keys - Move " + "- B button - Undo " + "- A button - Menu ", DialogLayout.Full) game.showLongText("--- Soko-Chan Help --- " + " " + "When in menu, press A immediately to " + "reset the current level, or choose a different level, then press A." + " " + "When in menu, press B to " + "return to the level as you left it.", DialogLayout.Full) } controller.down.onEvent(ControllerButtonEvent.Released, function () { pressed_down = 0 }) function get_level_asset_takaken (lv: number) { return [ assets.imagelevel takaken 1, assets.imagelevel takaken 2, assets.imagelevel takaken 3, assets.imagelevel takaken 4, assets.imagelevel takaken 5, assets.imagelevel takaken 6, assets.imagelevel takaken 7 ][lv - 1] } function get_level_asset_microcosmos (lv: number) { if (lv == 1) { return assets.imagelevel microcosmos 01 } else if (lv == 2) { return assets.imagelevel microcosmos 02 } else if (lv == 3) { return assets.imagelevel microcosmos 03 } else if (lv == 4) { return assets.imagelevel microcosmos 04 } else if (lv == 5) { return assets.imagelevel microcosmos 05 } else if (lv == 6) { return assets.imagelevel microcosmos 06 } else if (lv == 7) { return assets.imagelevel microcosmos 07 } else if (lv == 8) { return assets.imagelevel microcosmos 08 } else if (lv == 9) { return assets.imagelevel microcosmos 09 } else if (lv == 10) { return assets.imagelevel microcosmos 10 } else if (lv == 11) { return assets.imagelevel microcosmos 11 } else if (lv == 12) { return assets.imagelevel microcosmos 12 } else if (lv == 13) { return assets.imagelevel microcosmos 13 } else if (lv == 14) { return assets.imagelevel microcosmos 14 } else if (lv == 15) { return assets.imagelevel microcosmos 15 } else if (lv == 16) { return assets.imagelevel microcosmos 16 } else if (lv == 17) { return assets.imagelevel microcosmos 17 } else if (lv == 18) { return assets.imagelevel microcosmos 18 } else if (lv == 19) { return assets.imagelevel microcosmos 19 } else if (lv == 20) { return assets.imagelevel microcosmos 20 } else if (lv == 21) { return assets.imagelevel microcosmos 21 } else if (lv == 22) { return assets.imagelevel microcosmos 22 } else if (lv == 23) { return assets.imagelevel microcosmos 23 } else if (lv == 24) { return assets.imagelevel microcosmos 24 } else if (lv == 25) { return assets.imagelevel microcosmos 25 } else if (lv == 26) { return assets.imagelevel microcosmos 26 } else if (lv == 27) { return assets.imagelevel microcosmos 27 } else if (lv == 28) { return assets.imagelevel microcosmos 28 } else if (lv == 29) { return assets.imagelevel microcosmos 29 } else if (lv == 30) { return assets.imagelevel microcosmos 30 } else if (lv == 31) { return assets.imagelevel microcosmos 31 } else if (lv == 32) { return assets.imagelevel microcosmos 32 } else if (lv == 33) { return assets.imagelevel microcosmos 33 } else if (lv == 34) { return assets.imagelevel microcosmos 34 } else if (lv == 35) { return assets.imagelevel microcosmos 35 } else if (lv == 36) { return assets.imagelevel microcosmos 36 } else if (lv == 37) { return assets.imagelevel microcosmos 37 } else if (lv == 38) { return assets.imagelevel microcosmos 38 } else if (lv == 39) { return assets.imagelevel microcosmos 39 } else if (lv == 40) { return assets.imagelevel microcosmos 40 } return assets.imagelevel microcosmos 01 } function move_to (tx: number, ty: number, push_tx: number, push_ty: number) { if (!(tiles.tileIsWall(tiles.getTileLocation(tx, ty)))) { if (box_on_tile(tx, ty)) { if (!(tiles.tileIsWall(tiles.getTileLocation(push_tx, push_ty)))) { if (!(box_on_tile(push_tx, push_ty))) { undo.push([ tiles.locationXY(tiles.locationOfSprite(ban), tiles.XY.column), tiles.locationXY(tiles.locationOfSprite(ban), tiles.XY.row), tx, ty, push_tx, push_ty ]) move_box(tx, ty, push_tx, push_ty) move_ban(tx, ty) count_moves += 1 count_pushes += 1 } } } else { undo.push([tiles.locationXY(tiles.locationOfSprite(ban), tiles.XY.column), tiles.locationXY(tiles.locationOfSprite(ban), tiles.XY.row)]) music.footstep.play() move_ban(tx, ty) count_moves += 1 } update_moves() } } function ask_for_next_level () { str_record = "New best solution." str_score_action = "" if (blockSettings.exists(level_best_id(levelset, level))) { record = blockSettings.readNumberArray(level_best_id(levelset, level)) str_record = "Your best: " + record[0] + "/" + record[1] + game.isSokobanRecord( levelset, level - 1, record[0], record[1] ) if (count_moves < record[0] || record[0] == 0) { str_score_action = "New best! " blockSettings.writeNumberArray(level_best_id(levelset, level), [count_moves, count_pushes]) } } else { blockSettings.writeNumberArray(level_best_id(levelset, level), [count_moves, count_pushes]) } return game.askNextLevel("Moves/Pushes: " + count_moves + "/" + count_pushes + game.isSokobanRecord( levelset, level - 1, count_moves, count_pushes ), str_record, str_score_action) } function hilight_menu_item () { for (let t = 0; t <= 3; t++) { if (t == menu_selection) { menu_items[t].setBorder(1, 9, 2) } else { menu_items[t].setBorder(1, 0, 2) } } } /**

  • tx, ty are tileset coordinates
  • dtx, dty are relative deviations of tileset coordinates
  • x, y are pixel screen coordinates / function walk (dtx: number, dty: number) { move_to(tiles.locationXY(tiles.locationOfSprite(ban), tiles.XY.column) + dtx, tiles.locationXY(tiles.locationOfSprite(ban), tiles.XY.row) + dty, tiles.locationXY(tiles.locationOfSprite(ban), tiles.XY.column) + 2 * dtx, tiles.locationXY(tiles.locationOfSprite(ban), tiles.XY.row) + 2 * dty) } function draw_selection () { menu_items[0].setText("Group: " + list_levelsets[select_levelset]) menu_items[1].setText("Level: " + convertToText(select_level)) if (blockSettings.exists(level_best_id(select_levelset, select_level)) && blockSettings.readNumberArray(level_best_id(select_levelset, select_level))[0] > 0) { text_best.setText("" + blockSettings.readNumberArray(level_best_id(select_levelset, select_level))[0] + "/" + blockSettings.readNumberArray(level_best_id(select_levelset, select_level))[1] + game.isSokobanRecord( select_levelset, select_level - 1, blockSettings.readNumberArray(level_best_id(select_levelset, select_level))[0], blockSettings.readNumberArray(level_best_id(select_levelset, select_level))[1] )) } else { text_best.setText("") } minimap.setImage(scale_thumbnail(get_level_asset(select_levelset, select_level))) } controller.right.onEvent(ControllerButtonEvent.Released, function () { pressed_right = 0 }) controller.left.onEvent(ControllerButtonEvent.Released, function () { pressed_left = 0 }) function show_credits () { game.showLongText("--- Level Credits --- " + " " + "Tutorial " + ": by Moobot " + "Microban (easy) " + ": by David Skinner " + "Blocks+co (easy/tricky) " + ": by Dries de Clercq " + "Microcosmos (tricky) " + ": by Aymeric du Peloux " + "Cantrip (tricky/hard) " + ": by David Holland", DialogLayout.Full) game.showLongText("--- Level Credits --- " + " " + "Takaken (hard) " + ": by Kenichiro Takahashi " + "Sokogen (easy) " + ": genr.by Jacques Duthen " + "Murase (tricky) " + ": gener.by Yoshio Murase " + "Nabokosmos (hard) " + ": by Aymeric du Peloux " + "Petitesse (tricky) " + ": by niwa", DialogLayout.Full) } /*
  • Check win condition and manage buttons in a continuous loop.
  • A win is when all boxes stand on a target tile.
  • Direction buttons can be pressed repeatedly without delay. They can be pressed continuously, in which case Soko-Chan continues to move, but not too fast.
  • Button B must be blocked during menu, otherwise a B press during menu will be handled as undo action when the menu returns. / function next_level () { level += 1 if (level > list_groupsize[levelset]) { level = 1 levelset += 1 game.splash("You finished this group.", "Next group: " + list_levelsets[levelset]) if (levelset >= list_levelsets.length) { levelset = 0 } } set_up_level() } /*
  • Determine if a box is on a specific tile by comparing their absolute x and y pixel coordiates. Use pixels, because the color-coded Tile object lacks a mechanism to get its tileset coordinates. / function all_boxes_fit () { for (let c of sprites.allOfKind(SpriteKind.Crate)) { if (!(target_tile(c.x, c.y))) { return 0 } } if (sprites.allOfKind(SpriteKind.Crate).length > 0) { if (count_pushes > 0) { return 1 } } return 0 } function undo_move () { if (undo.length > 0) { undo_step = undo.pop() move_ban(undo_step[0], undo_step[1]) count_moves += -1 if (undo_step.length == 6) { move_box(undo_step[4], undo_step[5], undo_step[2], undo_step[3]) count_pushes += -1 } else { music.footstep.play() } update_moves() } } function control_level () { if (all_boxes_fit()) { pause(500) ban.setImage(assets.imagesokochan win) music.playTone(392, music.beat(BeatFraction.Quarter)) music.playTone(523, music.beat(BeatFraction.Whole)) if (ask_for_next_level()) { next_level() } else { undo_move() pressed_B = button_lag } } if (controller.up.isPressed() && !(pressed_up)) { walk(0, -1) pressed_up = button_lag } if (controller.down.isPressed() && !(pressed_down)) { walk(0, 1) pressed_down = button_lag } if (controller.left.isPressed() && !(pressed_left)) { walk(-1, 0) pressed_left = button_lag } if (controller.right.isPressed() && !(pressed_right)) { walk(1, 0) pressed_right = button_lag } if (controller.A.isPressed() && !(pressed_A)) { set_up_selection() reset_buttons() } if (controller.B.isPressed() && !(pressed_B)) { undo_move() pressed_B = button_lag } } function return_to_level () { state_selection = 0 button_lag = 9 tiles.destroySpritesOfKind(SpriteKind.Text) scene.centerCameraAt(screen_center_x(), screen_center_y()) if (scroll_level()) { scene.cameraFollowSprite(ban) } update_camera() text_moves = textsprite.create("0/0", 0, 11) text_moves.setOutline(1, 15) text_moves.setBorder(1, 0) text_moves.setMaxFontHeight(8) update_moves() reset_buttons() state_level = 1 } function scroll_level () { if (levelset == 1) { // Microban return [8, 35, 36, 49].indexOf(level) >= 0 } if (levelset == 8) { // Nabokosmos return [ 2, 7, 11, 16, 34, 39 ].indexOf(level) >= 0 } if (levelset == 5) { // Takaken return [3, 6, 7].indexOf(level) >= 0 } if (levelset == 4) { // Cantrip return [4, 15, 16, 20].indexOf(level) >= 0 } if (levelset == 3) { // Microcosmos return [ 2, 10, 14, 22, 26, 30 ].indexOf(level) >= 0 } return false } // Force camera to update its position right now, following the moved sprite. Otherwise, the fixed text (e.g. move counter) shuffles around, because it renders either too early, or too late. function update_camera () { game.currentScene().camera.update() } controller.A.onEvent(ControllerButtonEvent.Released, function () { pressed_A = 0 }) function introduce_level () { text_frame = textsprite.create(" ", 13, 13) text_introduction = textsprite.create("" + list_levelsets[levelset] + " " + convertToText(level), 0, 12) text_introduction.setMaxFontHeight(16) text_frame.setMaxFontHeight(20) text_frame.setBorder(1, 12) text_introduction.setPosition(scene.cameraProperty(CameraProperty.X), scene.cameraProperty(CameraProperty.Y)) text_frame.setPosition(scene.cameraProperty(CameraProperty.X), scene.cameraProperty(CameraProperty.Y)) music.bigCrash.play() pause(1000) text_introduction.destroy() text_frame.destroy() } controller.up.onEvent(ControllerButtonEvent.Released, function () { pressed_up = 0 }) function move_ban (to_tx: number, to_ty: number) { tiles.placeOnTile(ban, tiles.getTileLocation(to_tx, to_ty)) if (target_tile(tiles.locationXY(tiles.getTileLocation(to_tx, to_ty), tiles.XY.x), tiles.locationXY(tiles.getTileLocation(to_tx, to_ty), tiles.XY.y))) { ban.setImage(assets.imagesokochan on target) } else { ban.setImage(assets.imagesokochan) } } function get_level_asset_sokogen (lv: number) { return [ assets.imagelevel sokogen 01, assets.imagelevel sokogen 02, assets.imagelevel sokogen 03, assets.imagelevel sokogen 04, assets.imagelevel sokogen 05, assets.imagelevel sokogen 06, assets.imagelevel sokogen 07, assets.imagelevel sokogen 08, assets.imagelevel sokogen 09, assets.imagelevel sokogen 10, assets.imagelevel sokogen 11, assets.imagelevel sokogen 12, assets.imagelevel sokogen 13, assets.imagelevel sokogen 14, assets.imagelevel sokogen 15, assets.imagelevel sokogen 16, assets.imagelevel sokogen 17, assets.imagelevel sokogen 18, assets.imagelevel sokogen 19, assets.imagelevel sokogen 20 ][lv - 1] } function box_on_tile (tx: number, ty: number) { for (let c of sprites.allOfKind(SpriteKind.Crate)) { if (tiles.locationXY(tiles.locationOfSprite(c), tiles.XY.column) == tx) { if (tiles.locationXY(tiles.locationOfSprite(c), tiles.XY.row) == ty) { return 1 } } } return 0 } /*
  • Soko-Chan
  • TODO
    • fix: on scrolling levels that have a width of 11 tiles, the move counter jumps around a bit (Nabokosmos 7)
  • Included Features
    • many puzzles from different puzzle sets
    • unlimited undo
    • push/move counter
    • remember personal best move scores between power-offs
    • remember recently opened puzzle between power-offs
    • continuous movement when button is being held down
    • different sprites when on target tile
    • puzzle selection menu with minimap
    • help and credits
    • puzzle reset
    • puzzles of up to 11x9 tiles show without scrolling (up to 10x7 tiles of walkable area)
    • different tile sets for different puzzle sets
  • Nice to Have
    • a way to handle large levels without scrolling, maybe through smaller 8x8 sprite tilemaps / function screen_center_x () { return tiles.tilemapColumns() * tiles.tileWidth() / 2 } function get_level_asset_microban (lv: number) { if (lv == 1) { return assets.imagelevel microban 01 } else if (lv == 2) { return assets.imagelevel microban 02 } else if (lv == 3) { return assets.imagelevel microban 03 } else if (lv == 4) { return assets.imagelevel microban 04 } else if (lv == 5) { return assets.imagelevel microban 05 } else if (lv == 6) { return assets.imagelevel microban 06 } else if (lv == 7) { return assets.imagelevel microban 07 } else if (lv == 8) { return assets.imagelevel microban 08 } else if (lv == 9) { return assets.imagelevel microban 09 } else if (lv == 10) { return assets.imagelevel microban 10 } else if (lv == 11) { return assets.imagelevel microban 11 } else if (lv == 12) { return assets.imagelevel microban 12 } else if (lv == 13) { return assets.imagelevel microban 13 } else if (lv == 14) { return assets.imagelevel microban 14 } else if (lv == 15) { return assets.imagelevel microban 15 } else if (lv == 16) { return assets.imagelevel microban 16 } else if (lv == 17) { return assets.imagelevel microban 17 } else if (lv == 18) { return assets.imagelevel microban 18 } else if (lv == 19) { return assets.imagelevel microban 19 } else if (lv == 20) { return assets.imagelevel microban 20 } else if (lv == 21) { return assets.imagelevel microban 21 } else if (lv == 22) { return assets.imagelevel microban 22 } else if (lv == 23) { return assets.imagelevel microban 23 } else if (lv == 24) { return assets.imagelevel microban 24 } else if (lv == 25) { return assets.imagelevel microban 25 } else if (lv == 26) { return assets.imagelevel microban 26 } else if (lv == 27) { return assets.imagelevel microban 27 } else if (lv == 28) { return assets.imagelevel microban 28 } else if (lv == 29) { return assets.imagelevel microban 29 } else if (lv == 30) { return assets.imagelevel microban 30 } else if (lv == 31) { return assets.imagelevel microban 31 } else if (lv == 32) { return assets.imagelevel microban 32 } else if (lv == 33) { return assets.imagelevel microban 33 } else if (lv == 34) { return assets.imagelevel microban 34 } else if (lv == 35) { return assets.imagelevel microban 35 } else if (lv == 36) { return assets.imagelevel microban 36 } else if (lv == 37) { return assets.imagelevel microban 37 } else if (lv == 38) { return assets.imagelevel microban 38 } else if (lv == 39) { return assets.imagelevel microban 39 } else if (lv == 40) { return assets.imagelevel microban 40 } else if (lv == 41) { return assets.imagelevel microban 41 } else if (lv == 42) { return assets.imagelevel microban 42 } else if (lv == 43) { return assets.imagelevel microban 43 } else if (lv == 44) { return assets.imagelevel microban 44 } else if (lv == 45) { return assets.imagelevel microban 45 } else if (lv == 46) { return assets.imagelevel microban 46 } else if (lv == 47) { return assets.imagelevel microban 47 } else if (lv == 48) { return assets.imagelevel microban 48 } else if (lv == 49) { return assets.imagelevel microban 49 } else if (lv == 50) { return assets.imagelevel microban 50 } else if (lv == 51) { return assets.imagelevel microban 51 } else if (lv == 52) { return assets.imagelevel microban 52 } return assets.imagelevel microban 01 } controller.B.onEvent(ControllerButtonEvent.Released, function () { pressed_B = 0 }) function get_level_asset (group: number, lv: number) { if (group == 1) { return get_level_asset_microban(lv) } else if (group == 2) { return get_level_asset_declercq(lv) } else if (group == 3) { return get_level_asset_microcosmos(lv) } else if (group == 4) { return get_level_asset_cantrip(lv) } else if (group == 5) { return get_level_asset_takaken(lv) } else if (group == 6) { return get_level_asset_sokogen(lv) } else if (group == 7) { return get_level_asset_murase(lv) } else if (group == 8) { return get_level_asset_nabo(lv) } else if (group == 9) { return get_level_asset_petitesse(lv) } else { return get_level_asset_tutorial(lv) } } function move_box (from_tx: number, from_ty: number, to_tx: number, to_ty: number) { for (let c of sprites.allOfKind(SpriteKind.Crate)) { if (c.x == tiles.locationXY(tiles.getTileLocation(from_tx, from_ty), tiles.XY.x) && c.y == tiles.locationXY(tiles.getTileLocation(from_tx, from_ty), tiles.XY.y)) { tiles.placeOnTile(c, tiles.getTileLocation(to_tx, to_ty)) if (target_tile(tiles.locationXY(tiles.getTileLocation(to_tx, to_ty), tiles.XY.x), tiles.locationXY(tiles.getTileLocation(to_tx, to_ty), tiles.XY.y))) { music.knock.play() c.setImage(list_skin_sprites[2]) } else { music.thump.play() c.setImage(list_skin_sprites[1]) } return } } } function screen_center_y () { return tiles.tilemapRows() * tiles.tileWidth() / 2 } function control_selection () { if (controller.up.isPressed() && !(pressed_up)) { menu_selection += -1 menu_selection = (menu_selection + 4) % 4 hilight_menu_item() music.footstep.play() pressed_up = button_lag } if (controller.down.isPressed() && !(pressed_down)) { menu_selection += 1 menu_selection = (menu_selection + 4) % 4 hilight_menu_item() music.footstep.play() pressed_down = button_lag } if (menu_selection == 0) { if (controller.left.isPressed() && !(pressed_left)) { select_levelset += -1 select_levelset = (select_levelset + list_levelsets.length) % list_levelsets.length if (select_level > list_groupsize[select_levelset]) { select_level = list_groupsize[select_levelset] } draw_selection() music.knock.play() pressed_left = button_lag } if (controller.right.isPressed() && !(pressed_right)) { select_levelset += 1 select_levelset = (select_levelset + list_levelsets.length) % list_levelsets.length if (select_level > list_groupsize[select_levelset]) { select_level = list_groupsize[select_levelset] } draw_selection() music.knock.play() pressed_right = button_lag } } if (menu_selection == 1) { if (controller.left.isPressed() && !(pressed_left)) { select_level += -1 select_level = (select_level - 1 + list_groupsize[select_levelset]) % list_groupsize[select_levelset] + 1 draw_selection() music.thump.play() pressed_left = button_lag } if (controller.right.isPressed() && !(pressed_right)) { select_level += 1 select_level = (select_level - 1 + list_groupsize[select_levelset]) % list_groupsize[select_levelset] + 1 draw_selection() music.thump.play() pressed_right = button_lag } } if (controller.A.isPressed() && !(pressed_A)) { if (menu_selection <= 1) { level = select_level levelset = select_levelset set_up_level() } else if (menu_selection == 2) { show_help() pressed_A = button_lag } else { show_credits() pressed_A = button_lag } } if (controller.B.isPressed() && !(pressed_B)) { return_to_level() } } function decay_button_lag () { if (pressed_up) { pressed_up += -1 } if (pressed_down) { pressed_down += -1 } if (pressed_left) { pressed_left += -1 } if (pressed_right) { pressed_right += -1 } if (pressed_A) { pressed_A += -1 } if (pressed_B) { pressed_B += -1 } } function get_level_asset_murase (lv: number) { if (lv == 1) { return assets.imagelevel murase 01 } else if (lv == 2) { return assets.imagelevel murase 02 } else if (lv == 3) { return assets.imagelevel murase 03 } else if (lv == 4) { return assets.imagelevel murase 04 } else if (lv == 5) { return assets.imagelevel murase 05 } else if (lv == 6) { return assets.imagelevel murase 06 } else if (lv == 7) { return assets.imagelevel murase 07 } else if (lv == 8) { return assets.imagelevel murase 08 } else if (lv == 9) { return assets.imagelevel murase 09 } else if (lv == 10) { return assets.imagelevel murase 10 } else if (lv == 11) { return assets.imagelevel murase 11 } else if (lv == 12) { return assets.imagelevel murase 12 } else if (lv == 13) { return assets.imagelevel murase 13 } else if (lv == 14) { return assets.imagelevel murase 14 } else if (lv == 15) { return assets.imagelevel murase 15 } else if (lv == 16) { return assets.imagelevel murase 16 } else if (lv == 17) { return assets.imagelevel murase 17 } else if (lv == 18) { return assets.imagelevel murase 18 } else if (lv == 19) { return assets.imagelevel murase 19 } else if (lv == 20) { return assets.imagelevel murase 20 } return assets.imagelevel murase 01 } /*
  • Tile coding:
  • 14 brown -- wall (#)
  • 3 pink -- target (.)
  • 7 green -- player (@)
  • 6 teal -- player on target (+)
  • 4 orange -- crate ($)
  • 2 red -- crate on target (*)
  • 13 tan -- floor / function realize_tilemap () { for (let e of scene.getTilesByType(2)) { box = sprites.create(list_skin_sprites[2], SpriteKind.Crate) scene.place(e, box) scene.setTileAt(e, 3) } for (let e of scene.getTilesByType(4)) { box = sprites.create(list_skin_sprites[1], SpriteKind.Crate) scene.place(e, box) scene.setTileAt(e, 13) } for (let e of scene.getTilesByType(6)) { ban = sprites.create(assets.imagesokochan on target, SpriteKind.Player) scene.place(e, ban) scene.setTileAt(e, 3) } for (let e of scene.getTilesByType(7)) { ban = sprites.create(assets.imagesokochan, SpriteKind.Player) scene.place(e, ban) scene.setTileAt(e, 13) } scene.setTile(3, list_skin_sprites[4], false) scene.setTile(13, list_skin_sprites[3], false) scene.setTile(14, list_skin_sprites[0], true) } /*
  • When the user opens the system menu, it does some sort of context switch, but continues executing any functions. When any function waits on a "pause" return, the system menu opens in between, and the "pause" returns, any succeeding commands execute right then, even if they cannot do much, because the variables have been switched away.
  • This results in broken levels and banners when the user opens the system menu during the game or level introduction. / /*
  • Variables
  • setup scope
  • e
  • control scope
  • c, t, x, y */ function introduce_game () { scene.setTileMap(assets.imagegame intro) set_level_skin(true) realize_tilemap() scene.centerCameraAt(screen_center_x(), screen_center_y()) update_camera() text_frame = textsprite.create(" ", 13, 13) text_introduction = textsprite.create("SOKOCHAN", 0, 12) text_introduction.setMaxFontHeight(16) text_frame.setMaxFontHeight(20) text_frame.setBorder(1, 12) text_introduction.setPosition(scene.cameraProperty(CameraProperty.X), 40) text_frame.setPosition(scene.cameraProperty(CameraProperty.X), 40) music.playTone(440, music.beat(BeatFraction.Half)) music.playTone(349, music.beat(BeatFraction.Whole)) ban.setImage(assets.imagesokochan win) music.playTone(392, music.beat(BeatFraction.Half)) music.playTone(523, music.beat(BeatFraction.Whole)) pause(1500) ban.destroy() text_introduction.destroy() text_frame.destroy() } function get_level_asset_nabo (lv: number) { if (lv == 1) { return assets.imagelevel nabo 01 } else if (lv == 2) { return assets.imagelevel nabo 02 } else if (lv == 3) { return assets.imagelevel nabo 03 } else if (lv == 4) { return assets.imagelevel nabo 04 } else if (lv == 5) { return assets.imagelevel nabo 05 } else if (lv == 6) { return assets.imagelevel nabo 06 } else if (lv == 7) { return assets.imagelevel nabo 07 } else if (lv == 8) { return assets.imagelevel nabo 08 } else if (lv == 9) { return assets.imagelevel nabo 09 } else if (lv == 10) { return assets.imagelevel nabo 10 } else if (lv == 11) { return assets.imagelevel nabo 11 } else if (lv == 12) { return assets.imagelevel nabo 12 } else if (lv == 13) { return assets.imagelevel nabo 13 } else if (lv == 14) { return assets.imagelevel nabo 14 } else if (lv == 15) { return assets.imagelevel nabo 15 } else if (lv == 16) { return assets.imagelevel nabo 16 } else if (lv == 17) { return assets.imagelevel nabo 17 } else if (lv == 18) { return assets.imagelevel nabo 18 } else if (lv == 19) { return assets.imagelevel nabo 19 } else if (lv == 20) { return assets.imagelevel nabo 20 } else if (lv == 21) { return assets.imagelevel nabo 21 } else if (lv == 22) { return assets.imagelevel nabo 22 } else if (lv == 23) { return assets.imagelevel nabo 23 } else if (lv == 24) { return assets.imagelevel nabo 24 } else if (lv == 25) { return assets.imagelevel nabo 25 } else if (lv == 26) { return assets.imagelevel nabo 26 } else if (lv == 27) { return assets.imagelevel nabo 27 } else if (lv == 28) { return assets.imagelevel nabo 28 } else if (lv == 29) { return assets.imagelevel nabo 29 } else if (lv == 30) { return assets.imagelevel nabo 30 } else if (lv == 31) { return assets.imagelevel nabo 31 } else if (lv == 32) { return assets.imagelevel nabo 32 } else if (lv == 33) { return assets.imagelevel nabo 33 } else if (lv == 34) { return assets.imagelevel nabo 34 } else if (lv == 35) { return assets.imagelevel nabo 35 } else if (lv == 36) { return assets.imagelevel nabo 36 } else if (lv == 37) { return assets.imagelevel nabo 37 } else if (lv == 38) { return assets.imagelevel nabo 38 } else if (lv == 39) { return assets.imagelevel nabo 39 } else if (lv == 40) { return assets.imagelevel nabo 40 } return assets.imagelevel nabo 01 } function get_level_asset_tutorial (lv: number) { if (lv == 1) { return assets.imagelevel easy 01 } else if (lv == 2) { return assets.imagelevel easy 02 } else if (lv == 3) { return assets.imagelevel easy 03 } else if (lv == 4) { return assets.imagelevel easy 04 } else if (lv == 5) { return assets.imagelevel easy 05 } else if (lv == 6) { return assets.imagelevel easy 06 } else if (lv == 7) { return assets.imagelevel easy 07 } else if (lv == 8) { return assets.imagelevel easy 08 } else if (lv == 9) { return assets.imagelevel easy 10 } else if (lv == 10) { return assets.imagelevel easy 11 } return assets.imagelevel easy 01 } function target_tile (x: number, y: number) { for (let t of scene.getTilesByType(3)) { if (x == t.x) { if (y == t.y) { return 1 } } } return 0 } let box: Sprite = null let text_introduction: TextSprite = null let text_frame: TextSprite = null let undo_step: number[] = [] let record: number[] = [] let str_score_action = "" let str_record = "" let ban: Sprite = null let thumbnail: Image = null let list_skin_sprites: Image[] = [] let level_skin = 0 let text_moves: TextSprite = null let t: TextSprite = null let state_selection = 0 let text_best: TextSprite = null let minimap: Sprite = null let text_footer: TextSprite = null let menu_items: TextSprite[] = [] let text_title: TextSprite = null let mySprite2: Sprite = null let select_levelset = 0 let select_level = 0 let menu_selection = 0 let button_lag = 0 let state_level = 0 let count_pushes = 0 let count_moves = 0 let undo: number[][] = [] let pressed_B = 0 let pressed_A = 0 let pressed_right = 0 let pressed_left = 0 let pressed_down = 0 let pressed_up = 0 let level = 0 let levelset = 0 let list_groupsize: number[] = [] let list_levelsets: string[] = [] introduce_game() list_levelsets = [ "Tutorial", "Microban", "Blocks+co", "Microcosm", "Cantrip", "Takaken", "Sokogen", "Murase", "Nabokosmos", "Petitesse" ] list_groupsize = [ 10, 52, 20, 40, 20, 7, 20, 20, 40, 18 ] levelset = 0 level = 1 if (blockSettings.exists("recent group") && blockSettings.exists("recent level")) { levelset = blockSettings.readNumber("recent group") level = blockSettings.readNumber("recent level") } set_up_level() forever(function () { if (state_selection) { control_selection() } if (state_level) { control_level() } decay_button_lag() })

About

Sudoku clone for Meowbit

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors