summaryrefslogtreecommitdiff
path: root/Towers
diff options
context:
space:
mode:
Diffstat (limited to 'Towers')
-rw-r--r--Towers/Tower.gd164
-rw-r--r--Towers/Tower.tscn46
-rw-r--r--Towers/replicated_tower.gd7
3 files changed, 217 insertions, 0 deletions
diff --git a/Towers/Tower.gd b/Towers/Tower.gd
new file mode 100644
index 0000000..f3b6667
--- /dev/null
+++ b/Towers/Tower.gd
@@ -0,0 +1,164 @@
+class_name Tower
+extends StaticBody2D
+
+
+signal selected
+signal deselected
+
+static var selected_towers: Array[Tower]
+
+var is_selected = false :
+ set(value):
+ if value:
+ if not Tower.selected_towers.has(self):
+ Tower.selected_towers.append(self)
+ selected.emit()
+ else:
+ Tower.selected_towers.erase(self)
+ deselected.emit()
+ Client.stage.hud.tower.text = ""
+ is_selected = value
+ queue_redraw()
+
+var is_hovered = false :
+ set(value):
+ is_hovered = value
+ queue_redraw()
+
+var mobs_in_range: Array = []
+
+var selection_area: Area2D
+
+# rpc owner id
+var owner_id = 1
+
+# unique shared id on the network on all clients
+var network_id
+
+@export var attack_range: int = 32
+@export var attack_power: int = 1
+@export var attack_speed: int = 1
+
+
+func _ready():
+ $Range/CollisionShape2D.shape.radius = attack_range
+ $ShootCooldown.wait_time = attack_speed
+
+
+func _draw():
+ if is_selected:
+ draw_circle(
+ Client.stage.map.tile_set.tile_size,
+ 8 + attack_range,
+ Color(1, 1, 1, 0.75),
+ false,
+ 1.0
+ )
+ modulate = Color(1.5, 1.5, 1.5)
+ elif is_hovered:
+ if Client.state is StateDefault:
+ draw_circle(
+ Client.stage.map.tile_set.tile_size,
+ 8 + attack_range,
+ Color(1, 1, 1, 0.5),
+ false,
+ 1.0
+ )
+ modulate = Color(1.25, 1.25, 1.25)
+ else:
+ modulate = Color(1, 1, 1)
+
+
+func _process(_delta: float) -> void:
+ if $ShootCooldown.is_stopped() and not mobs_in_range.is_empty():
+ shoot()
+ $ShootCooldown.start()
+
+ if selection_area and is_instance_valid(selection_area):
+ var bodies = selection_area.get_overlapping_bodies()
+ if bodies.size() > 0:
+ selection_area.queue_free()
+ for body in bodies:
+ Client.select_tower(body)
+
+
+func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int):
+ # disable remote select for now
+ if owner_id != multiplayer.get_unique_id():
+ return
+
+ if Client.state is StateDefault:
+ if event.is_action_pressed("builder_tower_select"):
+ Client.select_tower(self)
+
+ if event is InputEventMouseButton:
+ if event.is_double_click():
+ selection_area = Area2D.new()
+ selection_area.position = (
+ Client.stage.get_node("Camera").get_rect().position +
+ Client.stage.get_node("Camera").get_rect().size / 2
+ )
+ selection_area.set_collision_mask_value(3, true)
+ var collision_shape = CollisionShape2D.new()
+ var shape = RectangleShape2D.new()
+ shape.size = Client.stage.get_node("Camera").get_rect().size
+ collision_shape.shape = shape
+ selection_area.add_child(collision_shape)
+ get_tree().current_scene.add_child(selection_area)
+
+ if event.is_action_pressed("builder_cancel"):
+ Client.remove_tower(self)
+
+
+func _on_range_body_entered(body: Node2D) -> void:
+ mobs_in_range.append(body)
+
+func _on_range_body_exited(body: Node2D) -> void:
+ mobs_in_range.remove_at(mobs_in_range.find(body))
+
+
+func _on_mouse_entered() -> void:
+ is_hovered = true
+
+func _on_mouse_exited() -> void:
+ is_hovered = false
+
+
+func is_melee_range():
+ return attack_range <= (Client.stage.map.tile_set.tile_size.x * 2)
+
+
+func shoot():
+ var target = mobs_in_range.pick_random() as Unit
+
+ if is_melee_range():
+ target.set_hp(target.hp - 1)
+ else: # TODO
+ target.set_hp(target.hp - 1)
+
+
+func show_ui():
+ # todo: show ui
+ pass
+
+
+func get_region():
+ var collision_shape := $CollisionShape2D
+ var shape = $CollisionShape2D.shape as RectangleShape2D
+
+ return Rect2(
+ collision_shape.position,
+ shape.size
+ )
+
+
+func _on_tree_exiting() -> void:
+ is_selected = false
+
+
+func get_rpc_properties() -> Dictionary:
+ return {
+ "global_position": null,
+ "owner_id": null,
+ "network_id": null,
+ }
diff --git a/Towers/Tower.tscn b/Towers/Tower.tscn
new file mode 100644
index 0000000..dfb2364
--- /dev/null
+++ b/Towers/Tower.tscn
@@ -0,0 +1,46 @@
+[gd_scene load_steps=5 format=3 uid="uid://by1x56w21o165"]
+
+[ext_resource type="Script" path="res://Towers/Tower.gd" id="1_axo1d"]
+[ext_resource type="Texture2D" uid="uid://b1b18rd0tqbar" path="res://core_outdoor.png" id="1_mrep8"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_atm5x"]
+size = Vector2(31, 31)
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_qa8kt"]
+
+[node name="Tower" type="StaticBody2D"]
+y_sort_enabled = true
+collision_layer = 4
+collision_mask = 5
+input_pickable = true
+script = ExtResource("1_axo1d")
+
+[node name="Sprite2D" type="Sprite2D" parent="."]
+texture_filter = 1
+position = Vector2(0, -19)
+scale = Vector2(1.0625, 1.0625)
+texture = ExtResource("1_mrep8")
+centered = false
+region_enabled = true
+region_rect = Rect2(400, 432, 32, 48)
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(16, 16)
+shape = SubResource("RectangleShape2D_atm5x")
+
+[node name="Range" type="Area2D" parent="."]
+collision_layer = 0
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Range"]
+position = Vector2(16, 16)
+shape = SubResource("CircleShape2D_qa8kt")
+
+[node name="ShootCooldown" type="Timer" parent="."]
+one_shot = true
+
+[connection signal="input_event" from="." to="." method="_on_input_event"]
+[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]
+[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"]
+[connection signal="tree_exiting" from="." to="." method="_on_tree_exiting"]
+[connection signal="body_entered" from="Range" to="." method="_on_range_body_entered"]
+[connection signal="body_exited" from="Range" to="." method="_on_range_body_exited"]
diff --git a/Towers/replicated_tower.gd b/Towers/replicated_tower.gd
new file mode 100644
index 0000000..de69ae1
--- /dev/null
+++ b/Towers/replicated_tower.gd
@@ -0,0 +1,7 @@
+extends Tower
+# supposed to be attached to a tower that should just have client-synced behavior
+
+
+# overwrite functions, that behave differently or not at all if called by another peer
+func show_ui():
+ pass