clockwork-city/scenes/board_game.gd

294 lines
9.5 KiB
GDScript3
Raw Normal View History

class_name BoardGame extends Node
signal all_players_ready_for_day_start
const HOME_SCENE = preload("uid://bto4vblqk2inb")
const HQ_SCENE = preload("uid://wdgig5aclnpx")
#const DOWN_SPAWN_SCENE = preload("uid://d4ltd1geg7s2p")
const BANK_SCENE = preload("uid://c06fsqdixer1c")
const BAR_SCENE = preload("uid://cfk268flnsbhb")
const CAFE_SCENE = preload("uid://bgtw051fiveeo")
const FORK_SCENE = preload("uid://cphy0vtj14ob0")
const GUN_SHOP_SCENE = preload("uid://c1kyedmrep0tu")
const HOSPITAL_SCENE = preload("uid://bytldu3y1jak3")
const OFFICE_SCENE = preload("uid://mixrqf035krk")
const SHOP_SCENE = preload("uid://dbn63mv0peqf")
const CHURCH_SCENE = preload("uid://brn0nbkela0m4")
const CITY_HALL_SCENE = preload("uid://dtnejoimqiu0o")
const BASE_DECK = [
BANK_SCENE,
BAR_SCENE,
CAFE_SCENE,
FORK_SCENE,
GUN_SHOP_SCENE,
HOSPITAL_SCENE,
OFFICE_SCENE,
SHOP_SCENE,
CHURCH_SCENE,
CITY_HALL_SCENE
]
var citizen_count: int = 0:
set(value):
#print(value)
citizen_count = value
if citizen_count == 0:
handle_citizens_finished()
var buildings_added_to_draft: int = 0
var spawn_placement_actions: int = 0
var draft_index_to_be_deleted: int = -1
var num_players_ready_for_day_start: int = 0
var is_playing_day: bool = false
var current_board_state: BoardState:
set(value):
current_board_state = value
#controls.check_controls_enabled()
#controls.set_info()
var pending_board_state: BoardState:
set(value):
pending_board_state = value
#controls.check_controls_enabled()
var original_board_state: BoardState
var deck: Array[Building] = []
@onready var board: Board = %Board
@onready var controls: Controls = %Controls
@onready var game_over: Control = %GameOver
func _init() -> void:
Globals.board_game = self
@rpc("any_peer", "call_local", "reliable")
func setup_building_deck() -> void:
for i in range(current_board_state.players.size()):
for scene in BASE_DECK:
deck.append(scene.instantiate())
@rpc("any_peer", "call_local", "reliable")
func advance_board_state(board_state: Dictionary) -> void:
pending_board_state = null
current_board_state = BoardState.deserialize(board_state)
board.reset()
board.set_board_state(current_board_state)
controls.set_board_state(current_board_state)
if current_board_state.state == BoardState.State.INITIAL_SETUP:
if current_board_state.turn >= 0:
current_board_state.players.reverse()
current_board_state.current_player = current_board_state.players[0]
controls.set_info()
start_day()
elif Globals.game.this_player.id == current_board_state.current_player.id:
if current_board_state.turn >= -current_board_state.players.size():
board.set_active_building(HQ_SCENE.instantiate())
else:
board.set_active_building(HOME_SCENE.instantiate())
elif current_board_state.state == BoardState.State.PLACING_SPAWNS:
start_day()
if current_board_state.players_passed == Globals.game.players.size():
current_board_state.players_passed = 0
end_day()
controls.check_controls_enabled()
controls.set_info()
@rpc("any_peer", "call_local", "reliable")
func update_board_state(board_state: Dictionary) -> void:
current_board_state = BoardState.deserialize(board_state)
board.reset()
board.set_board_state(current_board_state)
controls.set_board_state(current_board_state)
controls.check_controls_enabled()
controls.set_info()
@rpc("any_peer", "call_local", "reliable")
func add_building_to_draft(building_data: Dictionary) -> void:
current_board_state.real_estate_market.append(Building.deserialize(building_data))
buildings_added_to_draft += 1
if buildings_added_to_draft >= Globals.game.players.size():
buildings_added_to_draft = 0
current_board_state.state = BoardState.State.PLAY
controls.check_controls_enabled()
controls.set_info()
original_board_state = BoardState.deserialize(current_board_state.serialize())
update_board_state.rpc(current_board_state.serialize())
@rpc("any_peer", "call_local", "reliable")
func ready_for_day_start() -> void:
num_players_ready_for_day_start += 1
if num_players_ready_for_day_start >= Globals.game.players.size():
all_players_ready_for_day_start.emit()
func select_tile(tile: Tile) -> void:
board.set_active_tile(Tile.deserialize(tile.serialize()))
func select_building(building: Building) -> void:
if building is Home:
board.remove_home(current_board_state.current_player)
if building is HQ:
board.remove_hq(current_board_state.current_player)
board.set_active_building(Building.deserialize(building.serialize()))
draft_index_to_be_deleted = current_board_state.real_estate_market.find_custom(
func(b: Building) -> bool:
return (
b.get_script() == building.get_script()
and b.cost == building.cost
and b.player == building.player
)
)
func cancel_placement() -> void:
if is_instance_valid(board.active_tile):
board.active_tile.queue_free()
board.active_tile = null
if is_instance_valid(board.active_building):
board.active_building.queue_free()
board.active_building = null
func start_day() -> void:
if current_board_state.day > 0 and current_board_state.state != BoardState.State.PLACING_SPAWNS:
current_board_state.players.sort_custom(
func(p1: Player, p2: Player) -> bool: return p1.money > p2.money
)
current_board_state.current_player = current_board_state.players[0]
await all_players_ready_for_day_start
if current_board_state.state == BoardState.State.PLACING_SPAWNS:
if current_board_state.spawn_placements > 0:
if current_board_state.current_player.id == Globals.game.this_player.id:
board.call_deferred(
"set_active_building", load("uid://d4ltd1geg7s2p").instantiate()
)
return
current_board_state.state = BoardState.State.DRAFT
current_board_state.day += 1
current_board_state.turn = 1
current_board_state.state = BoardState.State.DRAFT
for p in current_board_state.players:
p.build_actions_taken = 0
tally_votes()
reduce_draft_costs()
seed(Globals.game.sum_player_ids())
deck.shuffle()
var turn_index := current_board_state.get_this_player_index()
controls.give_hand(deck.slice(0 + (3 * turn_index), 3 + (3 * turn_index)))
controls.set_info()
func end_day() -> void:
controls.end_day()
get_tree().call_group("Pausable", "unpause")
is_playing_day = true
func update_player_votes(player: Player, votes: int) -> void:
var idx = current_board_state.get_player_index(player)
current_board_state.players[idx].votes = votes
func update_player_money(player: Player, money: int) -> void:
var idx = current_board_state.get_player_index(player)
current_board_state.players[idx].money = money
func reduce_draft_costs() -> void:
for building in current_board_state.real_estate_market:
building.cost = ceili(building.cost / 2.0)
controls.set_board_state(current_board_state)
func handle_board_state_changed() -> void:
pending_board_state = BoardState.new()
pending_board_state.day = current_board_state.day
pending_board_state.spawn_placements = current_board_state.spawn_placements
if (
current_board_state.state != BoardState.State.DRAFT
and current_board_state.state != BoardState.State.PLACING_SPAWNS
):
pending_board_state.turn = current_board_state.turn + 1
pending_board_state.state = current_board_state.state
pending_board_state.players = current_board_state.players
pending_board_state.players.push_back(pending_board_state.players.pop_front())
if (
pending_board_state.state == BoardState.State.INITIAL_SETUP
and pending_board_state.turn == -pending_board_state.players.size()
):
pending_board_state.players.reverse()
pending_board_state.current_player = current_board_state.players[0]
pending_board_state.tiles = board.tiles.values()
for building in board.buildings.values():
if !pending_board_state.buildings.has(building):
pending_board_state.buildings.append(building)
pending_board_state.real_estate_market = current_board_state.real_estate_market
controls.check_controls_enabled()
controls.set_info()
func handle_board_state_confirmed() -> void:
if draft_index_to_be_deleted != -1:
pending_board_state.real_estate_market.remove_at(draft_index_to_be_deleted)
draft_index_to_be_deleted = -1
advance_board_state.rpc(pending_board_state.serialize())
func handle_pass() -> void:
current_board_state.players_passed += 1
current_board_state.turn += 1
current_board_state.players.push_back(current_board_state.players.pop_front())
current_board_state.current_player = current_board_state.players[0]
advance_board_state.rpc(current_board_state.serialize())
func reset_turn() -> void:
pending_board_state = null
update_board_state.rpc(original_board_state.serialize())
func handle_citizens_finished() -> void:
for child in board.board_state.get_children():
if child.get_groups().has("PostTurnActions"):
child.handle_post_turn_actions()
is_playing_day = false
controls.reset_turn()
var winning_player_idx = current_board_state.players.find_custom(
func(p: Player) -> bool: return p.money >= 100
)
if winning_player_idx != -1:
game_over.set_winning_player(current_board_state.players[winning_player_idx])
else:
start_day()
ready_for_day_start.rpc()
func tally_votes() -> void:
var most_votes: int = (
current_board_state.players.map(func(p: Player) -> int: return p.votes).max()
)
var players_with_most_votes: Array[Player] = current_board_state.players.filter(
func(p: Player) -> bool: return p.votes == most_votes
)
if players_with_most_votes.size() == 1:
players_with_most_votes[0].building_permits += 1
func queue_spawn_placement(num_placements: int) -> void:
current_board_state.spawn_placements += num_placements * current_board_state.players.size()
current_board_state.state = BoardState.State.PLACING_SPAWNS