diff options
author | Daniel Weipert <git@mail.dweipert.de> | 2024-10-12 23:09:56 +0200 |
---|---|---|
committer | Daniel Weipert <git@mail.dweipert.de> | 2024-10-12 23:09:56 +0200 |
commit | 0697f674ec33f8381ba68cf064732ee40e6e584f (patch) | |
tree | 89334f288356390d193fa327bb3895fa366985b5 /UI | |
parent | 647e2e1812c00e29337a61560644f7aa91d0eb0f (diff) |
next commit
Diffstat (limited to 'UI')
-rw-r--r-- | UI/Camera.gd | 44 | ||||
-rw-r--r-- | UI/HUD.gd | 46 | ||||
-rw-r--r-- | UI/HUD.tscn | 309 | ||||
-rw-r--r-- | UI/PlayersList.tscn | 2 | ||||
-rw-r--r-- | UI/collision_visibility_area.gd | 2 | ||||
-rw-r--r-- | UI/lobby.gd | 6 | ||||
-rw-r--r-- | UI/players_list.gd | 24 | ||||
-rw-r--r-- | UI/spawn_button.gd | 2 |
8 files changed, 56 insertions, 379 deletions
diff --git a/UI/Camera.gd b/UI/Camera.gd index 8f075cd..6c22d44 100644 --- a/UI/Camera.gd +++ b/UI/Camera.gd @@ -1,10 +1,11 @@ +class_name Camera extends Camera2D var is_in_drag_mode = false var drag_anchor = Vector2.ZERO -@export var speed = 5 +@export var speed = 25 @export_group("Zoom", "zoom") @export var zoom_min: float = 0.5 @@ -12,10 +13,27 @@ var drag_anchor = Vector2.ZERO @export var zoom_step: float = 0.01 +func _ready(): + get_viewport().size_changed.connect(func(): + set_new_position(global_position) + var new_zoom = Vector2( + get_rect().size.x / limit_right, + get_rect().size.y / limit_bottom + ) + zoom = Vector2( + new_zoom[new_zoom.max_axis_index()], + new_zoom[new_zoom.max_axis_index()] + ) + ) + + func _input(event): if event.is_action("camera_zoom_out"): - var min_zoom_min = limit_right / (get_viewport_rect().size.x / zoom.x) - if min_zoom_min >= 1.0: + var can_zoom_out = ( + limit_right / get_rect().end.x > 1.0 and + limit_bottom / get_rect().end.y > 1.0 + ) + if can_zoom_out: var new_zoom = max(zoom.x - zoom_step, zoom_min) zoom = Vector2(new_zoom, new_zoom) if event.is_action("camera_zoom_in"): @@ -29,7 +47,7 @@ func _input(event): is_in_drag_mode = false -func _process(_delta): +func _process(delta): if is_in_drag_mode: set_new_position(global_position + drag_anchor - get_global_mouse_position()) @@ -37,25 +55,37 @@ func _process(_delta): var direction_v = Input.get_axis("ui_up", "ui_down") if direction_h != 0 or direction_v != 0: - set_new_position(global_position + Vector2(direction_h * speed, direction_v * speed)) + set_new_position( + lerp( + global_position, + global_position + Vector2(direction_h * speed, direction_v * speed), + speed * delta + ) + ) func set_new_position(new_position: Vector2): new_position.x = clamp( new_position.x, limit_left, - limit_right - (get_viewport_rect().size.x / zoom.x) + limit_right - get_rect().size.x ) new_position.y = clamp( new_position.y, limit_top, - limit_bottom - (get_viewport_rect().size.y / zoom.y) + limit_bottom - get_rect().size.y ) global_position = new_position +func set_center(center_position: Vector2): + set_new_position( + center_position - (get_rect().size / 2) + ) + + func get_rect(): var viewport = get_viewport_rect() diff --git a/UI/HUD.gd b/UI/HUD.gd deleted file mode 100644 index 023f157..0000000 --- a/UI/HUD.gd +++ /dev/null @@ -1,46 +0,0 @@ -class_name HUD -extends CanvasLayer - - -@onready var score: Label = %Score -@onready var tower: Label = %Tower -@onready var spawn_box: Control = %SpawnBox -@onready var players_list: PanelContainer = %PlayersList - - -func _ready(): - Client.player.score_changed.connect(func(): - score.text = str(Client.player.score) - ) - - Client.stage_state_changed.connect(func(state: State): - if state is StateBuild: - $TowerConfigurationsContainer.visible = true - else: - $TowerConfigurationsContainer.visible = false - ) - - -func _input(event: InputEvent): - if event.is_action_pressed("spawn_box_toggle"): - spawn_box.visible = not spawn_box.visible - if event.is_action_pressed("players_list_toggle"): - players_list.visible = not players_list.visible - - -func _on_build_mode_button_gui_input(event: InputEvent) -> void: - if event.is_action_pressed("select"): - if Client.state is StateDefault: - get_tree().current_scene.get_node("StateManager").set_state("StateBuild") - elif Client.state is StateBuild: - get_tree().current_scene.get_node("StateManager").set_state("StateDefault") - - -func _on_spawner_box_button_gui_input(event: InputEvent) -> void: - if event.is_action_pressed("select"): - spawn_box.visible = not spawn_box.visible - - -func _on_player_list_button_gui_input(event: InputEvent) -> void: - if event.is_action_pressed("select"): - players_list.visible = not players_list.visible diff --git a/UI/HUD.tscn b/UI/HUD.tscn deleted file mode 100644 index f968c16..0000000 --- a/UI/HUD.tscn +++ /dev/null @@ -1,309 +0,0 @@ -[gd_scene load_steps=24 format=3 uid="uid://bylx30cweulmk"] - -[ext_resource type="Script" path="res://UI/HUD.gd" id="1_2bu0v"] -[ext_resource type="Texture2D" uid="uid://dlg78heamuf5g" path="res://Assets/UI/tilemap_white.png" id="2_dyehp"] -[ext_resource type="PackedScene" uid="uid://x6kohecnw7f5" path="res://UI/SpawnButton.tscn" id="3_7eaea"] -[ext_resource type="Texture2D" uid="uid://up1rtweit3ut" path="res://Assets/Mobs/angesnow-menu01.png" id="4_w7sef"] -[ext_resource type="Theme" uid="uid://c7f1ftrx53ag1" path="res://theme.tres" id="5_121ry"] -[ext_resource type="Texture2D" uid="uid://dq2i36oe1wj0m" path="res://Assets/Mobs/mob-pressed.png" id="5_xcxr8"] -[ext_resource type="Texture2D" uid="uid://dnkr5y0cfxu68" path="res://Assets/Mobs/mob-hovered.png" id="6_4go2d"] -[ext_resource type="Texture2D" uid="uid://dsy7k2v5fhh6v" path="res://Assets/Mobs/angesnow-front.png" id="7_ba5tw"] -[ext_resource type="Texture2D" uid="uid://dsui46tcf0pys" path="res://Assets/Mobs/banling-menu01.png" id="8_wmbg8"] -[ext_resource type="Texture2D" uid="uid://d3modiw2b30kh" path="res://Assets/Mobs/banling-front.png" id="9_nmd8t"] -[ext_resource type="Texture2D" uid="uid://75o7x0jadi08" path="res://Assets/Mobs/firomenis-menu01.png" id="10_daowa"] -[ext_resource type="Texture2D" uid="uid://bxr5ckrvhyp1t" path="res://Assets/Mobs/firomenis-front.png" id="11_yxcwt"] -[ext_resource type="Texture2D" uid="uid://byrx3c087exvb" path="res://Assets/Mobs/windeye-menu01.png" id="12_20egp"] -[ext_resource type="Texture2D" uid="uid://coiiq1yaonxeg" path="res://Assets/Mobs/windeye-front.png" id="13_iq5a7"] -[ext_resource type="Texture2D" uid="uid://dr02nqmrnciy0" path="res://Assets/Mobs/mob.png" id="14_t3qlu"] -[ext_resource type="PackedScene" uid="uid://cxd6c4kbnk04c" path="res://UI/PlayersList.tscn" id="16_mq4um"] -[ext_resource type="PackedScene" uid="uid://c05aq7xd4kx1p" path="res://UI/TowerConfiguration.tscn" id="17_1c5dq"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3rjde"] -bg_color = Color(0, 0, 0, 0.54902) - -[sub_resource type="AtlasTexture" id="AtlasTexture_byi0r"] -atlas = ExtResource("2_dyehp") -region = Rect2(392, 69, 13, 13) - -[sub_resource type="AtlasTexture" id="AtlasTexture_dixt2"] -atlas = ExtResource("2_dyehp") -region = Rect2(341, 35, 13, 13) - -[sub_resource type="AtlasTexture" id="AtlasTexture_tuk1j"] -atlas = ExtResource("2_dyehp") -region = Rect2(443, 35, 13, 13) - -[sub_resource type="InputEventAction" id="InputEventAction_t6x4q"] -action = &"spawn_unit" - -[sub_resource type="Shortcut" id="Shortcut_i6rmj"] -events = [SubResource("InputEventAction_t6x4q")] - -[node name="HUD" type="CanvasLayer"] -script = ExtResource("1_2bu0v") - -[node name="Panel" type="PanelContainer" parent="."] -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 29.0 -grow_horizontal = 2 -theme_override_styles/panel = SubResource("StyleBoxFlat_3rjde") - -[node name="VBoxContainer" type="VBoxContainer" parent="Panel"] -layout_mode = 2 - -[node name="Container" type="HBoxContainer" parent="Panel/VBoxContainer"] -layout_mode = 2 - -[node name="GridContainer" type="GridContainer" parent="Panel/VBoxContainer/Container"] -layout_mode = 2 -columns = 3 - -[node name="MarginContainer" type="MarginContainer" parent="Panel/VBoxContainer/Container/GridContainer"] -layout_mode = 2 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 - -[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer"] -layout_mode = 2 - -[node name="BuildModeButton" type="TextureRect" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer/HBoxContainer"] -texture_filter = 1 -custom_minimum_size = Vector2(24, 24) -layout_mode = 2 -texture = SubResource("AtlasTexture_byi0r") -expand_mode = 1 - -[node name="Label" type="Label" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer/HBoxContainer"] -layout_mode = 2 -text = "Build Mode" - -[node name="MarginContainer2" type="MarginContainer" parent="Panel/VBoxContainer/Container/GridContainer"] -layout_mode = 2 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 - -[node name="HBoxContainer2" type="HBoxContainer" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer2"] -layout_mode = 2 - -[node name="SpawnerBoxButton" type="TextureRect" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer2/HBoxContainer2"] -texture_filter = 1 -custom_minimum_size = Vector2(24, 24) -layout_mode = 2 -texture = SubResource("AtlasTexture_dixt2") -expand_mode = 1 - -[node name="Label" type="Label" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer2/HBoxContainer2"] -layout_mode = 2 -text = "Spawn Box" - -[node name="MarginContainer3" type="MarginContainer" parent="Panel/VBoxContainer/Container/GridContainer"] -layout_mode = 2 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 - -[node name="HBoxContainer2" type="HBoxContainer" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer3"] -layout_mode = 2 - -[node name="PlayerListButton" type="TextureRect" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer3/HBoxContainer2"] -texture_filter = 1 -custom_minimum_size = Vector2(24, 24) -layout_mode = 2 -texture = SubResource("AtlasTexture_tuk1j") -expand_mode = 1 - -[node name="Label" type="Label" parent="Panel/VBoxContainer/Container/GridContainer/MarginContainer3/HBoxContainer2"] -layout_mode = 2 -text = "Players List" - -[node name="Control" type="Control" parent="Panel/VBoxContainer/Container"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="MarginContainer" type="MarginContainer" parent="Panel/VBoxContainer/Container"] -layout_mode = 2 -theme_override_constants/margin_right = 8 - -[node name="Score" type="Label" parent="Panel/VBoxContainer/Container/MarginContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "0" - -[node name="ColorRect" type="ColorRect" parent="Panel/VBoxContainer"] -custom_minimum_size = Vector2(0, 1) -layout_mode = 2 - -[node name="SpawnBox" type="PanelContainer" parent="."] -unique_name_in_owner = true -anchors_preset = 3 -anchor_left = 1.0 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = -148.0 -offset_top = -116.0 -offset_right = -4.0 -offset_bottom = -4.0 -grow_horizontal = 0 -grow_vertical = 0 - -[node name="MarginContainer" type="MarginContainer" parent="SpawnBox"] -layout_mode = 2 -theme_override_constants/margin_left = 8 -theme_override_constants/margin_top = 8 -theme_override_constants/margin_right = 8 -theme_override_constants/margin_bottom = 8 - -[node name="GridContainer" type="GridContainer" parent="SpawnBox/MarginContainer"] -layout_mode = 2 -theme_override_constants/h_separation = 0 -theme_override_constants/v_separation = 0 -columns = 4 - -[node name="SpawnButton" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -theme = ExtResource("5_121ry") -texture_normal = ExtResource("4_w7sef") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") -texture = ExtResource("7_ba5tw") - -[node name="SpawnButton2" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -shortcut = SubResource("Shortcut_i6rmj") -texture_normal = ExtResource("8_wmbg8") -texture_hover = ExtResource("6_4go2d") -texture = ExtResource("9_nmd8t") - -[node name="SpawnButton3" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("10_daowa") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") -texture = ExtResource("11_yxcwt") - -[node name="SpawnButton4" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("12_20egp") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") -texture = ExtResource("13_iq5a7") - -[node name="SpawnButton5" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("14_t3qlu") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") - -[node name="SpawnButton6" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("14_t3qlu") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") - -[node name="SpawnButton7" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("14_t3qlu") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") - -[node name="SpawnButton8" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("14_t3qlu") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") - -[node name="SpawnButton9" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("14_t3qlu") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") - -[node name="SpawnButton10" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("14_t3qlu") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") - -[node name="SpawnButton11" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("14_t3qlu") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") - -[node name="SpawnButton12" parent="SpawnBox/MarginContainer/GridContainer" instance=ExtResource("3_7eaea")] -layout_mode = 2 -texture_normal = ExtResource("14_t3qlu") -texture_pressed = ExtResource("5_xcxr8") -texture_hover = ExtResource("6_4go2d") - -[node name="PlayersList" parent="." instance=ExtResource("16_mq4um")] -unique_name_in_owner = true -anchors_preset = 1 -anchor_left = 1.0 -anchor_right = 1.0 -offset_left = -204.0 -offset_top = 41.0 -offset_right = -4.0 -offset_bottom = 84.0 -grow_horizontal = 0 - -[node name="CenterContainer" type="CenterContainer" parent="."] -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -23.0 -grow_horizontal = 2 -grow_vertical = 0 - -[node name="Tower" type="Label" parent="CenterContainer"] -unique_name_in_owner = true -layout_mode = 2 - -[node name="TowerConfigurationsContainer" type="MarginContainer" parent="."] -visible = false -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -120.0 -offset_right = -152.0 -grow_horizontal = 2 -grow_vertical = 0 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 - -[node name="PanelContainer" type="PanelContainer" parent="TowerConfigurationsContainer"] -layout_mode = 2 - -[node name="MarginContainer" type="MarginContainer" parent="TowerConfigurationsContainer/PanelContainer"] -layout_mode = 2 -theme_override_constants/margin_left = 8 -theme_override_constants/margin_top = 8 -theme_override_constants/margin_right = 8 -theme_override_constants/margin_bottom = 8 - -[node name="ScrollContainer" type="ScrollContainer" parent="TowerConfigurationsContainer/PanelContainer/MarginContainer"] -layout_mode = 2 -vertical_scroll_mode = 0 - -[node name="TowerConfigurations" type="HBoxContainer" parent="TowerConfigurationsContainer/PanelContainer/MarginContainer/ScrollContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="TextureRect" parent="TowerConfigurationsContainer/PanelContainer/MarginContainer/ScrollContainer/TowerConfigurations" instance=ExtResource("17_1c5dq")] -layout_mode = 2 - -[connection signal="gui_input" from="Panel/VBoxContainer/Container/GridContainer/MarginContainer/HBoxContainer/BuildModeButton" to="." method="_on_build_mode_button_gui_input"] -[connection signal="gui_input" from="Panel/VBoxContainer/Container/GridContainer/MarginContainer2/HBoxContainer2/SpawnerBoxButton" to="." method="_on_spawner_box_button_gui_input"] -[connection signal="gui_input" from="Panel/VBoxContainer/Container/GridContainer/MarginContainer3/HBoxContainer2/PlayerListButton" to="." method="_on_player_list_button_gui_input"] diff --git a/UI/PlayersList.tscn b/UI/PlayersList.tscn index f3bde9b..2575b73 100644 --- a/UI/PlayersList.tscn +++ b/UI/PlayersList.tscn @@ -26,7 +26,7 @@ layout_mode = 2 text = "ID" [node name="Score" parent="MarginContainer/List/Header/HBoxContainer" index="2"] -text = "Score" +text = "Income" [node name="Indicator" parent="MarginContainer/List/Header" index="1"] visible = false diff --git a/UI/collision_visibility_area.gd b/UI/collision_visibility_area.gd index a049432..fbbf97f 100644 --- a/UI/collision_visibility_area.gd +++ b/UI/collision_visibility_area.gd @@ -14,7 +14,7 @@ func _draw(): draw_rect( Rect2( Vector2.ZERO, - shape.size.snapped(Client.stage.map.tile_set.tile_size) + shape.size.snapped(Client.current_stage.map.tile_set.tile_size) ), colliding_color if colliding_nodes else not_colliding_color ) diff --git a/UI/lobby.gd b/UI/lobby.gd index 86bfa4c..f849d81 100644 --- a/UI/lobby.gd +++ b/UI/lobby.gd @@ -10,8 +10,8 @@ var current_map_idx := 0 func _ready() -> void: if not multiplayer.is_server(): - %StartButton.visible = false - %StartButton.queue_free() + %StartButton.disabled = true + #%StartButton.queue_free() %PlayersList.remove_child(%PlayersList.get_child(0)) %PlayersList.remove_child(%PlayersList.get_child(0)) @@ -74,7 +74,7 @@ func _on_cancel_button_pressed() -> void: @rpc("authority", "call_local") func start(): - get_tree().change_scene_to_file("res://Stages/Wintermaul.tscn") + get_tree().change_scene_to_file("res://Stages/Wintermaul/Wintermaul.tscn") @rpc("authority", "call_local") diff --git a/UI/players_list.gd b/UI/players_list.gd index 598d7ad..6bb7e14 100644 --- a/UI/players_list.gd +++ b/UI/players_list.gd @@ -1,35 +1,37 @@ extends PanelContainer +@export var players: Array[Player]: + set(value): + players = value + update_players() + @onready var list: Control = %List func _ready() -> void: #players_list_container.visible = false - Client.player.score_changed.connect(update_players) Network.players_changed.connect(update_players) - update_players() multiplayer.peer_disconnected.connect(remove_player) func update_players(): - for id in Network.get_ordered_player_ids(): - var player: Player = Network.get_player(id) - - var control: Control = list.get_node_or_null(str(id)) + for player in players: + var control: Control = list.get_node_or_null(str(player.id)) if not control: control = preload("res://UI/PlayersListItem.tscn").instantiate() - control.name = str(id) + control.name = str(player.id) control.modulate = player.get_color() - control.get_node("%Indicator").visible = id == multiplayer.get_unique_id() + control.get_node("%Indicator").visible = player.id == multiplayer.get_unique_id() list.add_child(control) control.get_node("%ID").text = str(player.username) - control.get_node("%ID").tooltip_text = str(id) - control.get_node("%Score").text = str(player.score) - list.move_child(control, Network.get_ordered_player_ids().find(id) + 1) + control.get_node("%ID").tooltip_text = str(player.id) + control.get_node("%Score").text = str(player.income) + list.move_child(control, Network.get_ordered_player_ids().find(player.id) + 1) func remove_player(id): list.remove_child(list.get_node(str(id))) + #players.remove_at(players.filter(func(item): return item.id == id)[0]) TODO diff --git a/UI/spawn_button.gd b/UI/spawn_button.gd index e623874..ba67e37 100644 --- a/UI/spawn_button.gd +++ b/UI/spawn_button.gd @@ -11,4 +11,4 @@ func _on_pressed() -> void: unit.get_node("Sprite2D").texture = texture unit.get_node("Sprite2D").scale = Vector2(32,32) / texture.get_size() - Client.spawn_unit(unit, Client.stage.spawn) + Client.spawn_unit(unit, Client.current_stage.get_spawn(), Client.current_stage.get_overwrite_target()) |