class_name Wintermaul extends Stage signal lives_changed class Teams extends Resource: var top := Team.new() var bottom := Team.new() func list() -> Array[Team]: return [top, bottom] class Team extends Resource: var lives := 0 var players: Array[Player] = [] var teams := Teams.new() var income_frequency := 15.0 var price_map = { "tower": { "cost": 5, "attack_range": func(attack_range: int, number_of_towers: int = 1): return (attack_range / 8.0) * 10 * number_of_towers , "attack_power": func(attack_power: int, number_of_towers: int = 1): return attack_power * 10 * number_of_towers , "attack_speed": func(attack_speed: int, number_of_towers: int = 1): return attack_speed * 10 * number_of_towers , }, "unit": { "tiers": [ { "cost": 5, "income": 1, }, ], }, } func _init(): super._init() set_player_script(preload("res://Stages/Wintermaul/player.gd")) teams.top.lives = 10 teams.bottom.lives = 10 func _ready(): super._ready() # initialize player resources if multiplayer.is_server(): for player in Network.get_players(): Network.update_player.rpc(player.id, { "money": 50, "income": 5, }) # set camera limits $Camera.limit_left = $Map.get_used_rect().position.x * %Map.tile_set.tile_size.x - %Map.tile_set.tile_size.x - 8 * %Map.tile_set.tile_size.y $Camera.limit_right = $Map.get_used_rect().end.x * %Map.tile_set.tile_size.x - %Map.tile_set.tile_size.x + 8 * %Map.tile_set.tile_size.y $Camera.limit_top = %Map.get_used_rect().position.y * %Map.tile_set.tile_size.y - 8 * %Map.tile_set.tile_size.y $Camera.limit_bottom = %Map.get_used_rect().end.y * %Map.tile_set.tile_size.y + 8 * %Map.tile_set.tile_size.y # add players to teams Network.player_joined.connect(add_player) for id in Network.get_ordered_player_ids(): add_player(Network.get_player(id)) # set camera for local player if get_team(Client.player) == teams.top: $Camera.set_center($BuilderCollisions/TeamTop/CollisionShape2D.global_position) elif get_team(Client.player) == teams.bottom: $Camera.set_center($BuilderCollisions/TeamBottom/CollisionShape2D.global_position) # set players for HUD teams %HUD.get_node("%TeamTop").players = teams.top.players %HUD.get_node("%TeamBottom").players = teams.bottom.players # initialize timer and start $IncomeTimer.wait_time = income_frequency $IncomeTimer.start() # initialize lives display update_lives("top", 0) update_lives("bottom", 0) func _process(_delta: float) -> void: %HUD.time.text = "Time: %.0fs" % clamp($IncomeTimer.time_left + 0.5, 0, $IncomeTimer.wait_time) @rpc("any_peer", "call_local") func place_tower(remote_data: Dictionary): var data: Tower.NetworkData = dict_to_inst(remote_data) var tower = Tower.from_network_data(data) var player = Network.get_player(tower.owner_id) player.towers[tower.global_position] = tower player.money -= price_map.tower.cost Network.players_changed.emit() _place_tower(%Towers, tower) Client.placed_tower.emit(tower) @rpc("any_peer", "call_local") func spawn_unit(remote_data: Dictionary): var data: Unit.NetworkData = dict_to_inst(remote_data) var unit := Unit.from_network_data(data) var player = Network.get_player(unit.owner_id) player.units.append(unit) player.money -= price_map.unit.tiers[0].cost player.income += price_map.unit.tiers[0].income Network.players_changed.emit() if multiplayer.is_server(): unit.reached_goal.connect(func(): var team = get_team(player) if team == teams.top: update_lives.rpc("bottom", -1) elif team == teams.bottom: update_lives.rpc("top", -1) ) _spawn_unit(%Towers, unit) func can_place_tower(): if Client.player.money < price_map.tower.cost: add_status_message("Not enough money to build tower") return false return true func can_spawn_unit(tier_idx: int = 0): if Client.player.money < price_map.unit.tiers[tier_idx].cost: add_status_message("Not enough money to spawn unit") return false return true func add_player(player: Player): if teams.bottom.players.size() < teams.top.players.size(): teams.bottom.players.append(player) else: teams.top.players.append(player) func get_team(player: Player) -> Team: for team in teams.list(): if player in team.players: return team return null func get_spawn(): return %Spawn func get_overwrite_target(): var team = get_team(Client.player) if team == teams.top: return [$Paths/PathNodeLeftDown, $Paths/PathNodeRightDown].pick_random() elif team == teams.bottom: return [$Paths/PathNodeLeftUp, $Paths/PathNodeRightUp].pick_random() func get_builder_collision_masks(): var team = get_team(Client.player) if team == teams.top: return [28] elif team == teams.bottom: return [27] func _on_income_timer_timeout() -> void: if multiplayer.is_server(): for player in Network.get_players(): Network.update_player.rpc(player.id, { "money": player.income, }) reset_timer.rpc() @rpc("authority", "call_local") func reset_timer(): $IncomeTimer.wait_time = income_frequency $IncomeTimer.start() @rpc("authority", "call_local") func update_lives(team: String, lives: int): teams[team].lives += lives lives_changed.emit() if lives < 0: add_status_message("Team " + team + " lost " + str(abs(lives)) + " life") if teams[team].lives <= 0: add_status_message("Team " + team + " lost the game")