110 lines
3.3 KiB
GDScript
110 lines
3.3 KiB
GDScript
extends Node3D
|
|
|
|
@onready var camera: Camera3D = $Camera
|
|
|
|
var hist := UndoRedo.new()
|
|
@onready var board := Board.from_string("")
|
|
var player: Piece
|
|
var level_num := -1
|
|
var levels_src: PackedStringArray
|
|
|
|
@onready var sound: AudioStreamPlayer = $Sound
|
|
@onready var sounds_hit := audio_stream_randomizer_from_dir("res://sfx/hit")
|
|
@onready var sounds_undo := audio_stream_randomizer_from_dir("res://sfx/undo")
|
|
@onready var sounds_redo := audio_stream_randomizer_from_dir("res://sfx/redo")
|
|
|
|
func _ready() -> void:
|
|
var file := FileAccess.open("res://microban-1.txt", FileAccess.READ)
|
|
levels_src = file.get_as_text().split("\n\n")
|
|
advance_level()
|
|
|
|
func _process(delta: float) -> void:
|
|
if $TopLeft.is_on_screen() and $BottomRight.is_on_screen():
|
|
return
|
|
camera.position.y += 10*delta
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event.is_action_pressed("u", true, true):
|
|
step(Vector2i.UP)
|
|
elif event.is_action_pressed("d", true, true):
|
|
step(Vector2i.DOWN)
|
|
elif event.is_action_pressed("l", true, true):
|
|
step(Vector2i.LEFT)
|
|
elif event.is_action_pressed("r", true, true):
|
|
step(Vector2i.RIGHT)
|
|
elif event.is_action_pressed("undo", true, true):
|
|
if hist.undo():
|
|
sound.stream = sounds_undo
|
|
sound.play()
|
|
elif event.is_action_pressed("redo", true, true):
|
|
if hist.redo():
|
|
sound.stream = sounds_redo
|
|
sound.play()
|
|
elif event.is_action_pressed("restart", true, true):
|
|
restart()
|
|
|
|
# TODO:
|
|
func restart():
|
|
pass
|
|
|
|
func step(move: Vector2i):
|
|
var pos := player.lpos
|
|
var box := board.find_piece_at(pos + move, func(p): return p.type == Piece.Type.Box)
|
|
if board.passable_at(pos + move):
|
|
hist.create_action("move")
|
|
hist.add_do_method(player.do_move(move))
|
|
hist.add_undo_method(player.undo_move())
|
|
hist.commit_action()
|
|
elif box != null and board.passable_at(pos + move * 2):
|
|
hist.create_action("push")
|
|
hist.add_do_method(player.do_move(move))
|
|
hist.add_do_method(box.do_move(move))
|
|
hist.add_undo_method(player.undo_move())
|
|
hist.add_undo_method(box.undo_move())
|
|
hist.commit_action()
|
|
else:
|
|
sound.stream = sounds_hit
|
|
sound.play()
|
|
|
|
if won() or Input.is_action_pressed("restart"):
|
|
advance_level()
|
|
|
|
func won() -> bool:
|
|
for piece in board.pieces():
|
|
if piece.type == Piece.Type.Goal:
|
|
var covered := board.any_at(piece.lpos, func(p): return p.type == Piece.Type.Box)
|
|
if !covered:
|
|
return false
|
|
return true
|
|
|
|
func advance_level():
|
|
level_num += 1
|
|
if level_num >= levels_src.size():
|
|
print("you win")
|
|
return
|
|
while "@" not in levels_src[level_num] and "+" not in levels_src[level_num]:
|
|
level_num += 1
|
|
board.queue_free()
|
|
board = Board.from_string(levels_src[level_num])
|
|
var wall_count := 0
|
|
for piece in board.pieces():
|
|
if piece.type == Piece.Type.Player:
|
|
player = piece
|
|
add_child(board)
|
|
$TopLeft.aabb = board.top_left_aabb()
|
|
$BottomRight.aabb = board.bottom_right_aabb()
|
|
var center := (board.top_left_aabb().position + board.bottom_right_aabb().position)/2
|
|
camera.position = Vector3(center.x, 2, center.z)
|
|
|
|
func audio_stream_randomizer_from_dir(dir: String) -> AudioStreamRandomizer:
|
|
var stream := AudioStreamRandomizer.new()
|
|
stream.random_pitch = 1.1
|
|
var hit_dir := DirAccess.open(dir)
|
|
hit_dir.list_dir_begin()
|
|
var file_name := hit_dir.get_next()
|
|
while file_name != "":
|
|
if file_name.ends_with("ogg"):
|
|
stream.add_stream(-1, load(dir+"/"+file_name))
|
|
file_name = hit_dir.get_next()
|
|
return stream
|