213 lines
5.6 KiB
GDScript
213 lines
5.6 KiB
GDScript
tool
|
|
|
|
extends TileMap
|
|
|
|
class_name Level
|
|
|
|
export (PackedScene) var next_level
|
|
|
|
onready var _floor := $Floor as TileMap
|
|
onready var _props := $Props as TileMap
|
|
onready var _waste := $Waste as TileMap
|
|
onready var _player := $Player as Player
|
|
onready var _stairs := $Stairs as AnimatedSprite
|
|
onready var _reservoir := $Reservoir as AnimatedSprite
|
|
onready var _wastesound := $Waste/Sound as AudioStreamPlayer
|
|
|
|
export var start_x := 0
|
|
export var start_y := 0
|
|
|
|
export var stairs_x := 0
|
|
export var stairs_y := 0
|
|
|
|
var completed := false
|
|
var initial_state
|
|
|
|
func _ready():
|
|
_player.level = self
|
|
_player.tile_position = Vector2(start_x, start_y)
|
|
_stairs.visible = false
|
|
_stairs.modulate = Color.white
|
|
initial_state = {
|
|
waste = {},
|
|
reservoir = _player.reservoir
|
|
}
|
|
for w in _waste.get_used_cells():
|
|
initial_state.waste[w] = _waste.get_cellv(w)
|
|
|
|
func _process(_delta):
|
|
|
|
if Engine.editor_hint:
|
|
|
|
if not _floor is TileMap:
|
|
_floor = $Floor as TileMap
|
|
|
|
if not _player is Player:
|
|
_player = $Player as Player
|
|
|
|
player_initial_position()
|
|
|
|
if not _stairs is AnimatedSprite:
|
|
_stairs = $Stairs as AnimatedSprite
|
|
|
|
|
|
_stairs.position = _floor.map_to_world(Vector2(stairs_x, stairs_y))
|
|
|
|
if not _reservoir is AnimatedSprite:
|
|
_reservoir = $Reservoir as AnimatedSprite
|
|
|
|
|
|
var self_cells = self.get_used_cells()
|
|
if not self_cells.empty():
|
|
_floor.clear()
|
|
for cell in self_cells:
|
|
_floor.set_cellv(cell, self.get_cellv(cell))
|
|
self.clear()
|
|
|
|
|
|
update_reservoir()
|
|
|
|
|
|
class Tile:
|
|
var x :int
|
|
var y :int
|
|
var level :Level
|
|
|
|
func get_tile(var tile_map :TileMap) -> int:
|
|
return tile_map.get_cell(x, y)
|
|
|
|
func has_tile(var tile_map :TileMap) -> bool:
|
|
return get_tile(tile_map) >= 0
|
|
|
|
func set_tile(var tile_map :TileMap, var tile :int) -> void:
|
|
tile_map.set_cell(x, y, tile)
|
|
|
|
func swap_tile(var tile_map:TileMap, var other :Tile) -> void:
|
|
var tile := other.get_tile(tile_map)
|
|
other.set_tile(tile_map, self.get_tile(tile_map))
|
|
self.set_tile(tile_map, tile)
|
|
|
|
func has_floor() -> bool:
|
|
return has_tile(level._floor)
|
|
|
|
func has_prop() -> bool:
|
|
return has_tile(level._props)
|
|
|
|
func has_waste() -> bool:
|
|
return has_tile(level._waste)
|
|
|
|
func is_stairs():
|
|
return level.completed and (x == level.stairs_x or x == level.stairs_x - 1) and (y == level.stairs_y or y == level.stairs_y - 1)
|
|
|
|
func is_stairs_entrance():
|
|
return level.completed and x == level.stairs_x - 1 and y == level.stairs_y - 1
|
|
|
|
func can_walk(var direction := Vector2.ZERO) -> bool:
|
|
if is_stairs_entrance() and direction == Vector2.DOWN:
|
|
return true
|
|
return has_floor() and not has_prop() and not has_waste() and not is_stairs()
|
|
|
|
func get_next_tile(var direction :Vector2) -> Tile:
|
|
return level.get_tile(x + direction.x, y + direction.y)
|
|
|
|
func can_push(var direction :Vector2) -> bool:
|
|
if has_waste():
|
|
return get_next_tile(direction).can_push(direction)
|
|
elif has_prop() or is_stairs():
|
|
return false
|
|
elif has_floor():
|
|
return true
|
|
else:
|
|
return false
|
|
|
|
func get_waste_line(var direction :Vector2, var continuous := false, var max_tiles := -1) -> Array:
|
|
var waste_line := []
|
|
if max_tiles != 0 and (has_waste() and has_floor() or continuous and can_walk()):
|
|
waste_line = get_next_tile(direction).get_waste_line(direction, continuous, max_tiles - 1)
|
|
if has_waste():
|
|
waste_line.push_front(self)
|
|
return waste_line
|
|
|
|
func push(var direction :Vector2) -> void:
|
|
if can_push(direction):
|
|
var waste_line := get_waste_line(direction)
|
|
if not waste_line.empty():
|
|
var last = waste_line.pop_back()
|
|
last.push_r(direction, waste_line)
|
|
|
|
func push_r(var direction: Vector2, var waste_line := []) -> void:
|
|
var empty_tile = get_next_tile(direction)
|
|
swap_tile(level._waste, empty_tile)
|
|
if not waste_line.empty():
|
|
waste_line.pop_back().push_r(direction, waste_line)
|
|
return
|
|
|
|
func dash(var direction: Vector2, var tile_limit = INF, var waste_limit = INF) -> Tile:
|
|
var waste_line = get_waste_line(direction, true, tile_limit)
|
|
waste_line.resize(min(waste_limit, waste_line.size()))
|
|
for tile in waste_line:
|
|
tile.set_tile(level._waste, -1)
|
|
level.check_completed()
|
|
level.waste_sound(waste_line.size())
|
|
return waste_line.back() if not waste_line.empty() else self
|
|
|
|
func get_tile_v(var position :Vector2) -> Tile:
|
|
return get_tile(position.x, position.y)
|
|
|
|
func get_tile(var x :int, var y :int) -> Tile:
|
|
var tile = Tile.new()
|
|
tile.x = x
|
|
tile.y = y
|
|
tile.level = self
|
|
return tile
|
|
|
|
func check_completed() -> void:
|
|
var left = _waste.get_used_cells()
|
|
if left.empty():
|
|
show_stairs()
|
|
|
|
func show_stairs() -> void:
|
|
_stairs.frame = 0
|
|
_stairs.visible = true
|
|
_stairs.play()
|
|
($Stairs/Sound as AudioStreamPlayer).play()
|
|
completed = true
|
|
|
|
func update_reservoir() -> void:
|
|
_reservoir.frame = _player.reservoir
|
|
|
|
func waste_sound(var number :int):
|
|
for _i in range(number):
|
|
_wastesound.play()
|
|
yield(_wastesound, "finished")
|
|
|
|
func player_initial_position():
|
|
_player.level = self
|
|
_player.tile_position = Vector2(start_x, start_y)
|
|
_player.update_position()
|
|
if not Engine.editor_hint:
|
|
_player.current_direction = _player.movements.back()
|
|
_player.update_animation()
|
|
|
|
func reset():
|
|
if not completed:
|
|
|
|
_waste.clear()
|
|
for w in initial_state.waste:
|
|
_waste.set_cellv(w, initial_state.waste[w])
|
|
|
|
player_initial_position()
|
|
|
|
_player.reservoir = initial_state.reservoir
|
|
update_reservoir()
|
|
|
|
func end_of_level():
|
|
_player.visible = false
|
|
remove_child(_player)
|
|
var downstairs = $Stairs/Downstairs as AnimatedSprite
|
|
downstairs.visible = true
|
|
downstairs.play()
|
|
downstairs.connect("animation_finished", self, "next_level")
|
|
|
|
func next_level():
|
|
get_tree().change_scene_to(next_level)
|