generated from krampus/template-godot4
333 lines
11 KiB
GDScript
333 lines
11 KiB
GDScript
class_name Board extends Node2D
|
|
|
|
signal board_state_changed
|
|
|
|
enum Direction { NONE, UP, DOWN, LEFT, RIGHT }
|
|
|
|
const GROUND = preload("uid://c5y5ksmwhevd")
|
|
const UP_SPAWN = preload("uid://6ywvgci44ttv")
|
|
const RIGHT_SPAWN = preload("uid://c1y3s7daosghf")
|
|
const DOWN_SPAWN = preload("uid://d4ltd1geg7s2p")
|
|
const LEFT_SPAWN = preload("uid://noi2ko4hceus")
|
|
const SOUP_KITCHEN_SCENE = preload("uid://dmfnipmjntenc")
|
|
|
|
var tiles: Dictionary[Vector2i, Tile] = {}
|
|
var buildings: Dictionary[Vector2i, Building] = {}
|
|
var active_building: Building
|
|
var active_tile: Tile
|
|
var current_map_coord: Vector2i
|
|
var prev_map_coord: Vector2i
|
|
var is_controlling_camera: bool = false
|
|
|
|
@onready var tile_map: TileMapLayer = %Tiles
|
|
@onready var board_state: Node2D = %BoardState
|
|
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event.is_action_pressed("camera_engage"):
|
|
is_controlling_camera = true
|
|
return
|
|
if event.is_action_released("camera_engage"):
|
|
is_controlling_camera = false
|
|
if is_controlling_camera:
|
|
return
|
|
#if Globals.board_game.current_board_state.current_player != Globals.game.this_player:
|
|
#return
|
|
if event is InputEventMouseMotion:
|
|
current_map_coord = tile_map.local_to_map(tile_map.get_local_mouse_position())
|
|
if active_tile != null:
|
|
active_tile.position = tile_map.map_to_local(current_map_coord)
|
|
if active_building != null:
|
|
active_building.position = tile_map.map_to_local(current_map_coord)
|
|
prev_map_coord = current_map_coord
|
|
if event.is_action_pressed("select"):
|
|
if active_tile != null:
|
|
place_active_tile()
|
|
elif active_building != null:
|
|
place_active_building()
|
|
_handle_building_rotation(event)
|
|
_handle_spawn_rotation(event)
|
|
|
|
|
|
func set_active_tile(tile: Tile) -> void:
|
|
active_tile = tile
|
|
board_state.add_child(active_tile)
|
|
active_tile.modulate = Color(1, 1, 1, 0.5)
|
|
active_tile.player = Globals.board_game.current_board_state.current_player
|
|
active_tile.is_placing = true
|
|
|
|
|
|
func set_active_building(building: Building) -> void:
|
|
active_building = building
|
|
board_state.add_child(active_building)
|
|
active_building.player = Globals.board_game.current_board_state.current_player
|
|
active_building.modulate = Color(1, 1, 1, 0.5)
|
|
active_building.is_placing = true
|
|
|
|
|
|
func place_active_tile() -> void:
|
|
if tiles.has(current_map_coord) and tiles[current_map_coord] is Ground:
|
|
tiles[current_map_coord].free()
|
|
tiles.erase(current_map_coord)
|
|
if !tiles.has(current_map_coord) and !buildings.has(current_map_coord):
|
|
Globals.board_game.current_board_state.players[0].money -= active_tile.cost
|
|
if Globals.board_game.current_board_state.state != BoardState.State.INITIAL_SETUP:
|
|
Globals.board_game.current_board_state.players[0].build_actions_taken += 1
|
|
active_tile.modulate = Color(1, 1, 1, 1)
|
|
active_tile.coords = current_map_coord
|
|
active_tile.day_placed = Globals.board_game.current_board_state.day
|
|
tiles[current_map_coord] = active_tile
|
|
active_tile = null
|
|
board_state_changed.emit()
|
|
elif (
|
|
tiles.has(current_map_coord)
|
|
and tiles[current_map_coord].day_placed < Globals.board_game.current_board_state.day
|
|
):
|
|
var tile = tiles[current_map_coord]
|
|
if (
|
|
Globals.board_game.current_board_state.players[0].money
|
|
>= ((tile.cost * 2) + active_tile.cost)
|
|
):
|
|
var tile_player_index = Globals.board_game.current_board_state.get_player_index(
|
|
tile.player
|
|
)
|
|
Globals.board_game.current_board_state.players[tile_player_index].money += tile.cost * 2
|
|
Globals.board_game.current_board_state.players[0].money -= tile.cost * 2
|
|
Globals.board_game.current_board_state.players[0].money -= active_tile.cost
|
|
tiles[current_map_coord].free()
|
|
active_tile.modulate = Color(1, 1, 1, 1)
|
|
active_tile.coords = current_map_coord
|
|
active_tile.day_placed = Globals.board_game.current_board_state.day
|
|
tiles[current_map_coord] = active_tile
|
|
active_tile = null
|
|
board_state_changed.emit()
|
|
|
|
|
|
func place_active_building() -> void:
|
|
active_building.starting_coord = current_map_coord
|
|
active_building.player = Globals.board_game.current_board_state.current_player
|
|
for coord in active_building.get_tile_coords():
|
|
if tiles.has(coord) and !(tiles[coord] is Ground):
|
|
return
|
|
if buildings.has(coord):
|
|
return
|
|
for surr_coord in tile_map.get_surrounding_cells(coord):
|
|
if buildings.has(surr_coord):
|
|
return
|
|
Globals.board_game.current_board_state.players[0].money -= active_building.cost
|
|
if Globals.board_game.current_board_state.state != BoardState.State.INITIAL_SETUP:
|
|
Globals.board_game.current_board_state.players[0].build_actions_taken += 1
|
|
active_building.modulate = Color(1, 1, 1, 1)
|
|
for coord in active_building.get_tile_coords():
|
|
buildings[coord] = active_building
|
|
tiles[coord].free()
|
|
tiles.erase(coord)
|
|
if active_building is Spawn:
|
|
Globals.board_game.current_board_state.spawn_placements -= 1
|
|
board_state_changed.emit()
|
|
active_building = null
|
|
|
|
|
|
func remove_home(player: Player) -> void:
|
|
for coord in buildings.keys():
|
|
var building = buildings[coord]
|
|
if building is Home and building.player.id == player.id:
|
|
remove_building(coord, building)
|
|
|
|
|
|
func remove_hq(player: Player) -> void:
|
|
for coord in buildings.keys():
|
|
var building = buildings[coord]
|
|
if building is HQ and building.player.id == player.id:
|
|
remove_building(coord, building)
|
|
|
|
|
|
func remove_building(coord: Vector2i, building: Building) -> void:
|
|
buildings.erase(coord)
|
|
building.free()
|
|
var ground: Ground = GROUND.instantiate()
|
|
board_state.add_child(ground)
|
|
ground.position = tile_map.map_to_local(coord)
|
|
ground.coords = coord
|
|
tiles[coord] = ground
|
|
|
|
|
|
func _handle_building_rotation(event: InputEvent) -> void:
|
|
if active_building == null or active_building is Spawn:
|
|
return
|
|
if event.is_action_pressed("rotate_tile_up"):
|
|
active_building.rotation_degrees += 90
|
|
active_building.tile_rotation = get_next_direction(active_building.tile_rotation)
|
|
elif event.is_action_pressed("rotate_tile_down"):
|
|
active_building.rotation_degrees -= 90
|
|
active_building.tile_rotation = get_previous_direction(active_building.tile_rotation)
|
|
|
|
|
|
func _handle_spawn_rotation(event: InputEvent) -> void:
|
|
if active_building == null or active_building is not Spawn:
|
|
return
|
|
if event.is_action_pressed("rotate_tile_up"):
|
|
var curr_position = active_building.position
|
|
active_building.queue_free()
|
|
match active_building.direction:
|
|
Direction.UP:
|
|
set_active_building(RIGHT_SPAWN.instantiate())
|
|
Direction.RIGHT:
|
|
set_active_building(DOWN_SPAWN.instantiate())
|
|
Direction.DOWN:
|
|
set_active_building(LEFT_SPAWN.instantiate())
|
|
Direction.LEFT:
|
|
set_active_building(UP_SPAWN.instantiate())
|
|
active_building.position = curr_position
|
|
elif event.is_action_pressed("rotate_tile_down"):
|
|
var curr_position = active_building.position
|
|
active_building.queue_free()
|
|
match active_building.direction:
|
|
Direction.UP:
|
|
set_active_building(LEFT_SPAWN.instantiate())
|
|
Direction.RIGHT:
|
|
set_active_building(UP_SPAWN.instantiate())
|
|
Direction.DOWN:
|
|
set_active_building(RIGHT_SPAWN.instantiate())
|
|
Direction.LEFT:
|
|
set_active_building(DOWN_SPAWN.instantiate())
|
|
active_building.position = curr_position
|
|
|
|
|
|
func reset() -> void:
|
|
for child in board_state.get_children():
|
|
child.free()
|
|
|
|
|
|
func set_board_state(bs: BoardState) -> void:
|
|
tiles.clear()
|
|
buildings.clear()
|
|
for tile in bs.tiles:
|
|
board_state.add_child(tile)
|
|
tiles[tile.coords] = tile
|
|
tile.position = tile_map.map_to_local(tile.coords)
|
|
for building in bs.buildings:
|
|
board_state.add_child(building)
|
|
for coord in building.get_tile_coords():
|
|
buildings[coord] = building
|
|
building.position = tile_map.map_to_local(building.starting_coord)
|
|
building.rotation_degrees += 90 * building.get_rotation_count()
|
|
|
|
|
|
func initialize() -> void:
|
|
for i in range(Globals.game.players.size()):
|
|
var random_spawn = Vector2i(randi_range(0, 9), randi_range(0, 9))
|
|
for x in range(10):
|
|
for y in range(10):
|
|
var coord = Vector2i(x, y)
|
|
if i == 1:
|
|
coord.x += 10
|
|
if i == 2:
|
|
coord.y += 10
|
|
if i == 3:
|
|
coord += Vector2i(10, 10)
|
|
if x == random_spawn.x and y == random_spawn.y:
|
|
var possible_spawns = [UP_SPAWN, RIGHT_SPAWN, DOWN_SPAWN, LEFT_SPAWN]
|
|
if random_spawn.x == 9:
|
|
possible_spawns.erase(RIGHT_SPAWN)
|
|
elif random_spawn.x == 0:
|
|
possible_spawns.erase(LEFT_SPAWN)
|
|
if random_spawn.y == 9:
|
|
possible_spawns.erase(DOWN_SPAWN)
|
|
elif random_spawn.y == 0:
|
|
possible_spawns.erase(UP_SPAWN)
|
|
var spawn: Building = possible_spawns.pick_random().instantiate()
|
|
board_state.add_child(spawn)
|
|
spawn.starting_coord = coord
|
|
spawn.position = tile_map.map_to_local(coord)
|
|
buildings[coord] = spawn
|
|
else:
|
|
var ground: Tile = GROUND.instantiate()
|
|
board_state.add_child(ground)
|
|
ground.coords = coord
|
|
ground.position = tile_map.map_to_local(coord)
|
|
tiles[coord] = ground
|
|
var extra_spawn_coord := get_random_available_tile_coord()
|
|
var extra_spawn = [UP_SPAWN, RIGHT_SPAWN, DOWN_SPAWN, LEFT_SPAWN].pick_random().instantiate()
|
|
board_state.add_child(extra_spawn)
|
|
extra_spawn.starting_coord = extra_spawn_coord
|
|
extra_spawn.position = tile_map.map_to_local(extra_spawn_coord)
|
|
tiles[extra_spawn_coord].queue_free()
|
|
tiles.erase(extra_spawn_coord)
|
|
buildings[extra_spawn_coord] = extra_spawn
|
|
|
|
var soup_kitchen_coords := get_random_available_tile_coord()
|
|
var soup_kitchen: SoupKitchen = SOUP_KITCHEN_SCENE.instantiate()
|
|
board_state.add_child(soup_kitchen)
|
|
soup_kitchen.starting_coord = soup_kitchen_coords
|
|
for skc in soup_kitchen.get_tile_coords():
|
|
buildings[skc] = soup_kitchen
|
|
tiles[skc].free()
|
|
tiles.erase(skc)
|
|
soup_kitchen.position = tile_map.map_to_local(soup_kitchen_coords)
|
|
|
|
|
|
func get_random_available_tile_coord() -> Vector2i:
|
|
return tiles.keys().filter(is_cross_shape_available).pick_random()
|
|
|
|
|
|
func is_cross_shape_available(coord: Vector2i) -> bool:
|
|
return (
|
|
tiles[coord] is Ground
|
|
and !buildings.has(coord)
|
|
and tiles.get(Vector2i(coord.x + 1, coord.y)) is Ground
|
|
and !buildings.has(Vector2i(coord.x + 1, coord.y))
|
|
and tiles.get(Vector2i(coord.x - 1, coord.y)) is Ground
|
|
and !buildings.has(Vector2i(coord.x - 1, coord.y))
|
|
and tiles.get(Vector2i(coord.x, coord.y + 1)) is Ground
|
|
and !buildings.has(Vector2i(coord.x, coord.y + 1))
|
|
and tiles.get(Vector2i(coord.x, coord.y - 1)) is Ground
|
|
and !buildings.has(Vector2i(coord.x, coord.y - 1))
|
|
)
|
|
|
|
|
|
static func get_next_direction(direction: Direction, count: int = 1) -> Direction:
|
|
var result := direction
|
|
if count == 0:
|
|
return result
|
|
match direction:
|
|
Direction.UP:
|
|
result = Direction.RIGHT
|
|
Direction.RIGHT:
|
|
result = Direction.DOWN
|
|
Direction.DOWN:
|
|
result = Direction.LEFT
|
|
Direction.LEFT:
|
|
result = Direction.UP
|
|
if count == 1:
|
|
return result
|
|
return get_next_direction(result, count - 1)
|
|
|
|
|
|
static func get_previous_direction(direction: Direction) -> Direction:
|
|
match direction:
|
|
Direction.UP:
|
|
return Direction.LEFT
|
|
Direction.RIGHT:
|
|
return Direction.UP
|
|
Direction.DOWN:
|
|
return Direction.RIGHT
|
|
Direction.LEFT:
|
|
return Direction.DOWN
|
|
_:
|
|
return direction
|
|
|
|
|
|
static func get_direction_vector(direction: Direction) -> Vector2i:
|
|
match direction:
|
|
Direction.UP:
|
|
return Vector2i.UP
|
|
Direction.RIGHT:
|
|
return Vector2i.RIGHT
|
|
Direction.DOWN:
|
|
return Vector2i.DOWN
|
|
Direction.LEFT:
|
|
return Vector2i.LEFT
|
|
_:
|
|
return Vector2i.ZERO
|