summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Game/States/Build/StateBuild.gd10
-rw-r--r--Readme.md17
-rw-r--r--Stages/Stage.gd2
-rw-r--r--Stages/Wintermaul/HUD.gd13
-rw-r--r--Stages/Wintermaul/hud_tower.gd380
-rw-r--r--Stages/Wintermaul/hud_tower.tscn60
-rw-r--r--Stages/Wintermaul/wintermaul.gd2
-rw-r--r--Towers/Components/AttackComponent.gd77
-rw-r--r--Towers/Components/BurnComponent.gd2
-rw-r--r--Towers/Components/FrostComponent.gd2
-rw-r--r--Towers/Components/RangeComponent.gd52
-rw-r--r--Towers/Components/TowerComponent.gd48
-rw-r--r--Towers/Tower.gd154
-rw-r--r--Towers/Tower.tscn15
-rw-r--r--UI/ContainContainer.tscn6
-rw-r--r--UI/contain_container.gd10
-rw-r--r--project.godot1
17 files changed, 622 insertions, 229 deletions
diff --git a/Game/States/Build/StateBuild.gd b/Game/States/Build/StateBuild.gd
index e7f122d..ea06671 100644
--- a/Game/States/Build/StateBuild.gd
+++ b/Game/States/Build/StateBuild.gd
@@ -19,8 +19,9 @@ func _state_exit():
func _state_input(event: InputEvent):
if event.is_action_pressed("builder_tower_select"):
-
if current_builder_element and current_builder_element.can_build():
+ get_viewport().set_input_as_handled()
+
var placed_tower = current_builder_element.element.instantiate() as Tower
placed_tower.global_position = current_builder_element.global_position
@@ -41,9 +42,12 @@ func _state_input(event: InputEvent):
set_state("StateDefault")
if event.is_action_pressed("builder_cancel") and current_builder_element:
+ get_viewport().set_input_as_handled()
+
current_builder_element.queue_free()
current_builder_element = null
-func _state_unhandled_input(_event: InputEvent) -> void:
- pass
+func _state_unhandled_input(event: InputEvent) -> void:
+ if event.is_action_pressed("select"):
+ set_state("StateDefault")
diff --git a/Readme.md b/Readme.md
index 71fd295..3338402 100644
--- a/Readme.md
+++ b/Readme.md
@@ -4,9 +4,24 @@ Give them abilities/skills
Splash yes/no + splash range - could only be available at tower upgrade level 2+
exp system for towers?? - transfer xp to other selected tower that is over max_xp usable
-Add Components to Towers
Pre-Build Tower Configurations
+Poison Effect:
+Stackable.
+Tick abhängig von unit current speed bei tick reset.
+Damage at tick abhängig von current speed at tick.
+Amplified speed reduction effects? wäre interessant, ja
+
+Burn und Frost = nicht stackable
+dadurch hat Poison effect merit
+
+Range Component, Speed Component, Attack Component,
+Burn Component, Frost Component, Poison Component,
+Splash Damage Component = trifft mehrere auf einmal in der Trefferregion.
+ trifft damit nicht mehr das ziel direkt evtl sondern nur den boden wo das anvisierte ziel war/ist.
+ on impact area get\_overlapping und damage und effekte applyen
+ !abhängig von positionsdistanz zum impact! effekte normal applyen
+
Credits:
diff --git a/Stages/Stage.gd b/Stages/Stage.gd
index 7cdd2f8..9484305 100644
--- a/Stages/Stage.gd
+++ b/Stages/Stage.gd
@@ -42,7 +42,7 @@ func place_tower(_remote_data: Dictionary) -> void:
func _place_tower(parent: Node2D, tower: Tower):
var player: Player = Network.get_player(tower.owner_id)
tower.get_node("AnimatedSprite2D").modulate = player.get_color()
- tower.get_node("ComponentsAnchor").modulate = player.get_color()
+ tower.get_node("%ComponentsAnchor").modulate = player.get_color()
fill_tower_region(tower, true)
diff --git a/Stages/Wintermaul/HUD.gd b/Stages/Wintermaul/HUD.gd
index 5567f77..be2dacb 100644
--- a/Stages/Wintermaul/HUD.gd
+++ b/Stages/Wintermaul/HUD.gd
@@ -180,12 +180,15 @@ func get_ordered_group_keys() -> Array:
var group_b = selection_groups[b]
var node_a = group_a[0]
var node_b = group_b[0]
+ var level_a = 0
+ var level_b = 0
- return (
- (node_a.attack_range / 8) + node_a.attack_power + node_a.attack_speed
- >
- (node_b.attack_range / 8) + node_b.attack_power + node_b.attack_speed
- )
+ for component in node_a.components.values():
+ level_a += component.level
+ for component in node_b.components.values():
+ level_b += component.level
+
+ return level_a > level_b
)
keys.sort_custom(func(a, b):
var group_a = selection_groups[a]
diff --git a/Stages/Wintermaul/hud_tower.gd b/Stages/Wintermaul/hud_tower.gd
index ab23441..24a7a8d 100644
--- a/Stages/Wintermaul/hud_tower.gd
+++ b/Stages/Wintermaul/hud_tower.gd
@@ -17,9 +17,9 @@ func set_current_tower(tower: Tower):
redraw_components()
current_tower.components_changed.connect(redraw_components)
- %Data.text = "Range: %s - Power: %s - Speed: %s" % [
- current_tower.attack_range, current_tower.attack_power, current_tower.attack_speed
- ]
+ #%Data.text = "Range: %s - Power: %s - Speed: %s" % [
+ #current_tower.attack_range, current_tower.attack_power, current_tower.attack_speed
+ #]
func redraw_components():
@@ -27,10 +27,9 @@ func redraw_components():
node.modulate = Color(1.0, 1.0, 1.0, 0.5)
node.get_node("Level").text = str(0)
- for idx in range(current_tower.components.size()):
- var component = current_tower.components[idx]
- %Components.get_node(component.name).modulate = Color(1.0, 1.0, 1.0, 1.0)
- %Components.get_node(component.name).get_node("Level").text = ": %s" % [component.level]
+ for component: TowerComponent in current_tower.components.values():
+ %Components.get_node(component.id).modulate = Color(1.0, 1.0, 1.0, 1.0)
+ %Components.get_node(component.id).get_node("Level").text = ": %s" % [component.level]
func get_selected_towers() -> Array:
@@ -40,87 +39,137 @@ func get_selected_towers() -> Array:
return hud.selection_groups[hud.selected_group].duplicate()
-func get_component(tower: Tower, component_name: String):
- var component: TowerComponent
- for idx in range(tower.components.size()):
- if tower.components[idx].name == component_name:
- component = tower.components[idx]
- break
-
- return component
-
-
-func _on_range_plus_pressed() -> void:
- var towers = get_selected_towers()
-
- var cost = Client.current_stage.price_map.tower.attack_range.call(current_tower.attack_range, towers.size())
- if Client.player.money < cost:
- Client.current_stage.add_status_message("Not enough money to upgrade")
- return
-
- for tower: Tower in towers:
- tower.attack_range += 8
- tower.selection_group_id = tower.get_group_id()
- Client.update_tower(tower.get_path(), tower.to_network_data())
-
- Network.update_player.rpc(Client.player.id, {
- "money": -cost,
- })
-
- %Data.text = "Range: %s - Power: %s - Speed: %s" % [
- current_tower.attack_range, current_tower.attack_power, current_tower.attack_speed
- ]
-
-
-func _on_power_plus_pressed() -> void:
- var towers = get_selected_towers()
-
- var cost = Client.current_stage.price_map.tower.attack_power.call(current_tower.attack_power, towers.size())
- if Client.player.money < cost:
- Client.current_stage.add_status_message("Not enough money to upgrade")
- return
-
- for tower: Tower in towers:
- tower.attack_power += 1
- tower.selection_group_id = tower.get_group_id()
- Client.update_tower(tower.get_path(), tower.to_network_data())
-
- Network.update_player.rpc(Client.player.id, {
- "money": -cost,
- })
-
- %Data.text = "Range: %s - Power: %s - Speed: %s" % [
- current_tower.attack_range, current_tower.attack_power, current_tower.attack_speed
- ]
+#func get_component(tower: Tower, component_name: String):
+ #var component: TowerComponent
+ #for idx in range(tower.components.size()):
+ #if tower.components[idx].name == component_name:
+ #component = tower.components[idx]
+ #break
+ #
+ #return component
+
+
+#func _on_range_plus_pressed() -> void:
+ #var towers = get_selected_towers()
+ #
+ #var cost = Client.current_stage.price_map.tower.attack_range.call(current_tower.attack_range, towers.size())
+ #if Client.player.money < cost:
+ #Client.current_stage.add_status_message("Not enough money to upgrade")
+ #return
+ #
+ #for tower: Tower in towers:
+ #tower.attack_range += 8
+ #tower.selection_group_id = tower.get_group_id()
+ #Client.update_tower(tower.get_path(), tower.to_network_data())
+ #
+ #Network.update_player.rpc(Client.player.id, {
+ #"money": -cost,
+ #})
+ #
+ ##%Data.text = "Range: %s - Power: %s - Speed: %s" % [
+ ##current_tower.attack_range, current_tower.attack_power, current_tower.attack_speed
+ ##]
+#
+#
+#func _on_power_plus_pressed() -> void:
+ #var towers = get_selected_towers()
+ #
+ #var cost = Client.current_stage.price_map.tower.attack_power.call(current_tower.attack_power, towers.size())
+ #if Client.player.money < cost:
+ #Client.current_stage.add_status_message("Not enough money to upgrade")
+ #return
+ #
+ #for tower: Tower in towers:
+ #tower.attack_power += 1
+ #tower.selection_group_id = tower.get_group_id()
+ #Client.update_tower(tower.get_path(), tower.to_network_data())
+ #
+ #Network.update_player.rpc(Client.player.id, {
+ #"money": -cost,
+ #})
+ #
+ ##%Data.text = "Range: %s - Power: %s - Speed: %s" % [
+ ##current_tower.attack_range, current_tower.attack_power, current_tower.attack_speed
+ ##]
+#
+#
+#func _on_speed_plus_pressed() -> void:
+ #var towers = get_selected_towers()
+ #
+ #var cost = Client.current_stage.price_map.tower.attack_speed.call(current_tower.attack_speed, towers.size())
+ #if Client.player.money < cost:
+ #Client.current_stage.add_status_message("Not enough money to upgrade")
+ #return
+ #
+ #for tower: Tower in towers:
+ #tower.attack_speed += 1
+ #tower.selection_group_id = tower.get_group_id()
+ #Client.update_tower(tower.get_path(), tower.to_network_data())
+ #
+ #Network.update_player.rpc(Client.player.id, {
+ #"money": -cost,
+ #})
+ #
+ ##%Data.text = "Range: %s - Power: %s - Speed: %s" % [
+ ##current_tower.attack_range, current_tower.attack_power, current_tower.attack_speed
+ ##]
+
+
+func _on_range_gui_input(event: InputEvent) -> void:
+ if event.is_action_pressed("select"):
+ get_viewport().set_input_as_handled()
+
+ if current_tower.components.has(TowerComponent.ComponentType.Range):
+ Client.current_stage.add_status_message("Component already added")
+ return
+
+ var towers = get_selected_towers()
+
+ var cost = 100 * towers.size()
+ if Client.player.money < cost:
+ Client.current_stage.add_status_message("Not enough money to add component")
+ return
+
+ for tower: Tower in towers:
+ tower.add_component(preload("res://Towers/Components/RangeComponent.gd").new())
+
+ Client.update_tower(tower.get_path(), tower.to_network_data())
+
+ Network.update_player.rpc(Client.player.id, {
+ "money": -cost,
+ })
-func _on_speed_plus_pressed() -> void:
- var towers = get_selected_towers()
-
- var cost = Client.current_stage.price_map.tower.attack_speed.call(current_tower.attack_speed, towers.size())
- if Client.player.money < cost:
- Client.current_stage.add_status_message("Not enough money to upgrade")
- return
-
- for tower: Tower in towers:
- tower.attack_speed += 1
- tower.selection_group_id = tower.get_group_id()
- Client.update_tower(tower.get_path(), tower.to_network_data())
-
- Network.update_player.rpc(Client.player.id, {
- "money": -cost,
- })
-
- %Data.text = "Range: %s - Power: %s - Speed: %s" % [
- current_tower.attack_range, current_tower.attack_power, current_tower.attack_speed
- ]
+func _on_attack_gui_input(event: InputEvent) -> void:
+ if event.is_action_pressed("select"):
+ get_viewport().set_input_as_handled()
+
+ if current_tower.components.has(TowerComponent.ComponentType.Attack):
+ Client.current_stage.add_status_message("Component already added")
+ return
+
+ var towers = get_selected_towers()
+
+ var cost = 100 * towers.size()
+ if Client.player.money < cost:
+ Client.current_stage.add_status_message("Not enough money to add component")
+ return
+
+ for tower: Tower in towers:
+ tower.add_component(preload("res://Towers/Components/AttackComponent.gd").new())
+
+ Client.update_tower(tower.get_path(), tower.to_network_data())
+
+ Network.update_player.rpc(Client.player.id, {
+ "money": -cost,
+ })
func _on_frost_gui_input(event: InputEvent) -> void:
if event.is_action_pressed("select"):
get_viewport().set_input_as_handled()
- if get_component(current_tower, "Frost"):
+ if current_tower.components.has(TowerComponent.ComponentType.Frost):
Client.current_stage.add_status_message("Component already added")
return
@@ -132,16 +181,7 @@ func _on_frost_gui_input(event: InputEvent) -> void:
return
for tower: Tower in towers:
- var found = false
- for idx in range(tower.components.size()):
- var component = tower.components[idx]
- if component.name == "Frost":
- found = true
- tower.remove_component(component.name)
- break
-
- if not found:
- tower.add_component(preload("res://Towers/Components/FrostComponent.gd").new())
+ tower.add_component(preload("res://Towers/Components/FrostComponent.gd").new())
Client.update_tower(tower.get_path(), tower.to_network_data())
@@ -154,7 +194,7 @@ func _on_burn_gui_input(event: InputEvent) -> void:
if event.is_action_pressed("select"):
get_viewport().set_input_as_handled()
- if get_component(current_tower, "Burn"):
+ if current_tower.components.has(TowerComponent.ComponentType.Burn):
Client.current_stage.add_status_message("Component already added")
return
@@ -166,16 +206,7 @@ func _on_burn_gui_input(event: InputEvent) -> void:
return
for tower: Tower in towers:
- var found = false
- for idx in range(tower.components.size()):
- var component = tower.components[idx]
- if component.name == "Burn":
- found = true
- tower.remove_component(component.name)
- break
-
- if not found:
- tower.add_component(preload("res://Towers/Components/BurnComponent.gd").new())
+ tower.add_component(preload("res://Towers/Components/BurnComponent.gd").new())
Client.update_tower(tower.get_path(), tower.to_network_data())
@@ -184,14 +215,62 @@ func _on_burn_gui_input(event: InputEvent) -> void:
})
+func _on_range_level_up_pressed() -> void:
+ var towers = get_selected_towers()
+
+ var component: TowerComponent = current_tower.components.get(TowerComponent.ComponentType.Range)
+
+ if not component:
+ return
+
+ var cost = 25 * component.level * towers.size()
+ if Client.player.money < cost:
+ Client.current_stage.add_status_message("Not enough money to level up")
+ return
+
+ for tower: Tower in towers:
+ var tower_component: TowerComponent = tower.components.get(TowerComponent.ComponentType.Range)
+
+ tower_component.level += 1
+ tower.components_changed.emit()
+
+ Client.update_tower(tower.get_path(), tower.to_network_data())
+
+ Network.update_player.rpc(Client.player.id, {
+ "money": -cost,
+ })
+
+
+func _on_attack_level_up_pressed() -> void:
+ var towers = get_selected_towers()
+
+ var component: TowerComponent = current_tower.components.get(TowerComponent.ComponentType.Attack)
+
+ if not component:
+ return
+
+ var cost = 10 * component.level * towers.size()
+ if Client.player.money < cost:
+ Client.current_stage.add_status_message("Not enough money to level up")
+ return
+
+ for tower: Tower in towers:
+ var tower_component: TowerComponent = tower.components.get(TowerComponent.ComponentType.Attack)
+
+ tower_component.level += 1
+ tower.components_changed.emit()
+
+ Client.update_tower(tower.get_path(), tower.to_network_data())
+
+ Network.update_player.rpc(Client.player.id, {
+ "money": -cost,
+ })
+
+
func _on_frost_level_up_pressed() -> void:
var towers = get_selected_towers()
- var component: TowerComponent
- for idx in range(current_tower.components.size()):
- component = current_tower.components[idx]
- if component.name == "Frost":
- break
+ var component: TowerComponent = current_tower.components.get(TowerComponent.ComponentType.Frost)
if not component:
return
@@ -202,14 +281,11 @@ func _on_frost_level_up_pressed() -> void:
return
for tower: Tower in towers:
- var tower_component: TowerComponent
- for idx in range(tower.components.size()):
- tower_component = tower.components[idx]
- if tower_component.name == "Frost":
- break
+ var tower_component: TowerComponent = tower.components.get(TowerComponent.ComponentType.Frost)
tower_component.level += 1
tower.components_changed.emit()
+
Client.update_tower(tower.get_path(), tower.to_network_data())
Network.update_player.rpc(Client.player.id, {
@@ -220,12 +296,7 @@ func _on_frost_level_up_pressed() -> void:
func _on_burn_level_up_pressed() -> void:
var towers = get_selected_towers()
- var component: TowerComponent
- for idx in range(current_tower.components.size()):
- component = current_tower.components[idx]
- if component.name == "Burn":
- break
-
+ var component: TowerComponent = current_tower.components.get(TowerComponent.ComponentType.Burn)
if not component:
return
@@ -235,14 +306,11 @@ func _on_burn_level_up_pressed() -> void:
return
for tower: Tower in towers:
- var tower_component: TowerComponent
- for idx in range(tower.components.size()):
- tower_component = tower.components[idx]
- if tower_component.name == "Burn":
- break
+ var tower_component: TowerComponent = tower.components.get(TowerComponent.ComponentType.Burn)
tower_component.level += 1
tower.components_changed.emit()
+
Client.update_tower(tower.get_path(), tower.to_network_data())
Network.update_player.rpc(Client.player.id, {
@@ -250,28 +318,70 @@ func _on_burn_level_up_pressed() -> void:
})
-func _on_range_plus_mouse_entered() -> void:
+#func _on_range_plus_mouse_entered() -> void:
+ #var towers = get_selected_towers()
+ #var cost = Client.current_stage.price_map.tower.attack_range.call(current_tower.attack_range, towers.size())
+ #%RangePlus.tooltip_text = "Cost: " + str(cost)
+#
+#func _on_power_plus_mouse_entered() -> void:
+ #var towers = get_selected_towers()
+ #var cost = Client.current_stage.price_map.tower.attack_power.call(current_tower.attack_power, towers.size())
+ #%PowerPlus.tooltip_text = "Cost: " + str(cost)
+#
+#func _on_speed_plus_mouse_entered() -> void:
+ #var towers = get_selected_towers()
+ #var cost = Client.current_stage.price_map.tower.attack_speed.call(current_tower.attack_speed, towers.size())
+ #%SpeedPlus.tooltip_text = "Cost: " + str(cost)
+
+func _on_range_mouse_entered() -> void:
+ if current_tower.components.has(TowerComponent.ComponentType.Range):
+ $Components/Range.tooltip_text = ""
+ return
+
var towers = get_selected_towers()
- var cost = Client.current_stage.price_map.tower.attack_range.call(current_tower.attack_range, towers.size())
- %RangePlus.tooltip_text = "Cost: " + str(cost)
+ var cost = 100 * towers.size()
+ $Components/Range.tooltip_text = "Cost: " + str(cost)
-func _on_power_plus_mouse_entered() -> void:
+func _on_range_level_up_mouse_entered() -> void:
+ var component = current_tower.components.get(TowerComponent.ComponentType.Range)
+ if not component:
+ $Components/Range/RangeLevelUp.tooltip_text = ""
+ return
+
+ var towers = get_selected_towers()
+ var cost = 25 * component.level * towers.size()
+ $Components/Range/RangeLevelUp.tooltip_text = "Cost: " + str(cost)
+
+func _on_attack_mouse_entered() -> void:
+ if current_tower.components.has(TowerComponent.ComponentType.Attack):
+ $Components/Range.tooltip_text = ""
+ return
+
var towers = get_selected_towers()
- var cost = Client.current_stage.price_map.tower.attack_power.call(current_tower.attack_power, towers.size())
- %PowerPlus.tooltip_text = "Cost: " + str(cost)
+ var cost = 100 * towers.size()
+ $Components/Attack.tooltip_text = "Cost: " + str(cost)
-func _on_speed_plus_mouse_entered() -> void:
+func _on_attack_level_up_mouse_entered() -> void:
+ var component = current_tower.components.get(TowerComponent.ComponentType.Attack)
+ if not component:
+ $Components/Attack/AttackLevelUp.tooltip_text = ""
+ return
+
var towers = get_selected_towers()
- var cost = Client.current_stage.price_map.tower.attack_speed.call(current_tower.attack_speed, towers.size())
- %SpeedPlus.tooltip_text = "Cost: " + str(cost)
+ var cost = 10 * component.level * towers.size()
+ $Components/Attack/AttackLevelUp.tooltip_text = "Cost: " + str(cost)
func _on_frost_mouse_entered() -> void:
+ if current_tower.components.has(TowerComponent.ComponentType.Frost):
+ $Components/Range.tooltip_text = ""
+ return
+
var towers = get_selected_towers()
var cost = 100 * towers.size()
$Components/Frost.tooltip_text = "Cost: " + str(cost)
func _on_frost_level_up_mouse_entered() -> void:
- var component = get_component(current_tower, "Frost")
+ var component = current_tower.components.get(TowerComponent.ComponentType.Frost)
if not component:
$Components/Frost/FrostLevelUp.tooltip_text = ""
return
@@ -281,12 +391,16 @@ func _on_frost_level_up_mouse_entered() -> void:
$Components/Frost/FrostLevelUp.tooltip_text = "Cost: " + str(cost)
func _on_burn_mouse_entered() -> void:
+ if current_tower.components.has(TowerComponent.ComponentType.Burn):
+ $Components/Range.tooltip_text = ""
+ return
+
var towers = get_selected_towers()
var cost = 100 * towers.size()
$Components/Burn.tooltip_text = "Cost: " + str(cost)
func _on_burn_level_up_mouse_entered() -> void:
- var component = get_component(current_tower, "Burn")
+ var component = current_tower.components.get(TowerComponent.ComponentType.Burn)
if not component:
$Components/Burn/BurnLevelUp.tooltip_text = ""
return
diff --git a/Stages/Wintermaul/hud_tower.tscn b/Stages/Wintermaul/hud_tower.tscn
index 533c6b9..4a23f10 100644
--- a/Stages/Wintermaul/hud_tower.tscn
+++ b/Stages/Wintermaul/hud_tower.tscn
@@ -1,8 +1,10 @@
-[gd_scene load_steps=4 format=3 uid="uid://ei0ai7om3mkw"]
+[gd_scene load_steps=6 format=3 uid="uid://ei0ai7om3mkw"]
[ext_resource type="Texture2D" uid="uid://ba3dmlce1wv2p" path="res://Towers/Components/Assets/frost-component.png" id="1_1rlop"]
[ext_resource type="Script" path="res://Stages/Wintermaul/hud_tower.gd" id="1_aog4m"]
+[ext_resource type="Texture2D" uid="uid://dx07y4scyi5a1" path="res://Towers/Components/Assets/range-component.png" id="2_epopi"]
[ext_resource type="Texture2D" uid="uid://2djpswd6sgng" path="res://Towers/Components/Assets/burn-component.png" id="2_gcd2r"]
+[ext_resource type="Texture2D" uid="uid://gbknvb38euuq" path="res://Towers/Components/Assets/attack-component.png" id="3_xygpi"]
[node name="HUDTower" type="VBoxContainer"]
offset_left = 64.0
@@ -12,10 +14,12 @@ script = ExtResource("1_aog4m")
[node name="Data" type="Label" parent="."]
unique_name_in_owner = true
+visible = false
layout_mode = 2
text = "Data"
[node name="HBoxContainer" type="HBoxContainer" parent="."]
+visible = false
layout_mode = 2
[node name="RangePlus" type="Button" parent="HBoxContainer"]
@@ -40,6 +44,52 @@ text = "+Speed"
unique_name_in_owner = true
layout_mode = 2
+[node name="Range" type="HBoxContainer" parent="Components"]
+layout_mode = 2
+mouse_default_cursor_shape = 2
+
+[node name="TextureRect" type="TextureRect" parent="Components/Range"]
+custom_minimum_size = Vector2(32, 0)
+layout_mode = 2
+texture = ExtResource("2_epopi")
+stretch_mode = 5
+
+[node name="Label" type="Label" parent="Components/Range"]
+layout_mode = 2
+text = "Range"
+
+[node name="Level" type="Label" parent="Components/Range"]
+layout_mode = 2
+text = ": 1"
+
+[node name="RangeLevelUp" type="Button" parent="Components/Range"]
+layout_mode = 2
+mouse_default_cursor_shape = 2
+text = "+Level"
+
+[node name="Attack" type="HBoxContainer" parent="Components"]
+layout_mode = 2
+mouse_default_cursor_shape = 2
+
+[node name="TextureRect" type="TextureRect" parent="Components/Attack"]
+custom_minimum_size = Vector2(32, 0)
+layout_mode = 2
+texture = ExtResource("3_xygpi")
+stretch_mode = 5
+
+[node name="Label" type="Label" parent="Components/Attack"]
+layout_mode = 2
+text = "Attack"
+
+[node name="Level" type="Label" parent="Components/Attack"]
+layout_mode = 2
+text = ": 1"
+
+[node name="AttackLevelUp" type="Button" parent="Components/Attack"]
+layout_mode = 2
+mouse_default_cursor_shape = 2
+text = "+Level"
+
[node name="Frost" type="HBoxContainer" parent="Components"]
layout_mode = 2
mouse_default_cursor_shape = 2
@@ -92,6 +142,14 @@ text = "+Level"
[connection signal="pressed" from="HBoxContainer/PowerPlus" to="." method="_on_power_plus_pressed"]
[connection signal="mouse_entered" from="HBoxContainer/SpeedPlus" to="." method="_on_speed_plus_mouse_entered"]
[connection signal="pressed" from="HBoxContainer/SpeedPlus" to="." method="_on_speed_plus_pressed"]
+[connection signal="gui_input" from="Components/Range" to="." method="_on_range_gui_input"]
+[connection signal="mouse_entered" from="Components/Range" to="." method="_on_range_mouse_entered"]
+[connection signal="mouse_entered" from="Components/Range/RangeLevelUp" to="." method="_on_range_level_up_mouse_entered"]
+[connection signal="pressed" from="Components/Range/RangeLevelUp" to="." method="_on_range_level_up_pressed"]
+[connection signal="gui_input" from="Components/Attack" to="." method="_on_attack_gui_input"]
+[connection signal="mouse_entered" from="Components/Attack" to="." method="_on_attack_mouse_entered"]
+[connection signal="mouse_entered" from="Components/Attack/AttackLevelUp" to="." method="_on_attack_level_up_mouse_entered"]
+[connection signal="pressed" from="Components/Attack/AttackLevelUp" to="." method="_on_attack_level_up_pressed"]
[connection signal="gui_input" from="Components/Frost" to="." method="_on_frost_gui_input"]
[connection signal="mouse_entered" from="Components/Frost" to="." method="_on_frost_mouse_entered"]
[connection signal="mouse_entered" from="Components/Frost/FrostLevelUp" to="." method="_on_frost_level_up_mouse_entered"]
diff --git a/Stages/Wintermaul/wintermaul.gd b/Stages/Wintermaul/wintermaul.gd
index 95d914a..90abf6b 100644
--- a/Stages/Wintermaul/wintermaul.gd
+++ b/Stages/Wintermaul/wintermaul.gd
@@ -59,7 +59,7 @@ func _ready():
if multiplayer.is_server():
for player in Network.get_players():
Network.update_player.rpc(player.id, {
- "money": 50,
+ "money": 50 * 10000,
"income": 5,
})
diff --git a/Towers/Components/AttackComponent.gd b/Towers/Components/AttackComponent.gd
new file mode 100644
index 0000000..c7660cf
--- /dev/null
+++ b/Towers/Components/AttackComponent.gd
@@ -0,0 +1,77 @@
+class_name AttackTowerComponent
+extends TowerComponent
+
+
+var power := 1
+
+var speed_base := 1.0
+var speed := 1
+
+var shoot_cooldown := Timer.new()
+var shoot_sound := AudioStreamPlayer2D.new()
+
+@export var range_component: RangeTowerComponent:
+ get():
+ return current_tower.components[ComponentType.Range]
+
+
+func _init() -> void:
+ type = ComponentType.Attack
+ set_sprite(preload("res://Towers/Components/Assets/attack-component.png"))
+
+ update_power()
+ update_speed()
+ level_changed.connect(update_power)
+ level_changed.connect(update_speed)
+
+
+func update_power():
+ power = ceil(level / 2.0)
+
+func update_speed():
+ speed = level - ceil(level / 2.0)
+ shoot_cooldown.wait_time = speed_base / speed
+
+func update_range():
+ shoot_sound.max_distance = range_component.range * Client.current_stage.map.tile_set.tile_size.x
+
+
+func on_add(tower: Tower):
+ super.on_add(tower)
+
+ shoot_cooldown.one_shot = true
+ tower.add_child(shoot_cooldown)
+
+ shoot_sound.stream = preload("res://Towers/Assets/shoot.ogg")
+ tower.add_child(shoot_sound)
+
+ update_range()
+ range_component.range_changed.connect(update_range)
+
+
+func process(_delta: float):
+ if shoot_cooldown.is_stopped() and not range_component.units_in_range.is_empty():
+ shoot()
+ shoot_cooldown.start()
+
+
+func shoot():
+ var target = range_component.units_in_range[0]
+
+ for component in current_tower.components.values():
+ if component.has_method("on_shoot"):
+ component.on_shoot(target)
+
+ shoot_fx.rpc()
+
+ if is_melee_range():
+ target.set_hp(target.hp - 1)
+ else: # TODO
+ target.set_hp(target.hp - 1)
+
+@rpc("authority", "call_local")
+func shoot_fx():
+ shoot_sound.play()
+
+func is_melee_range():
+ return range_component.range <= (Client.current_stage.map.tile_set.tile_size.x * 2)
diff --git a/Towers/Components/BurnComponent.gd b/Towers/Components/BurnComponent.gd
index 96c24f7..d708d4f 100644
--- a/Towers/Components/BurnComponent.gd
+++ b/Towers/Components/BurnComponent.gd
@@ -2,7 +2,7 @@ extends TowerComponent
func _init() -> void:
- name = "Burn"
+ type = ComponentType.Burn
set_sprite(preload("res://Towers/Components/Assets/burn-component.png"))
diff --git a/Towers/Components/FrostComponent.gd b/Towers/Components/FrostComponent.gd
index 473baf6..2443b70 100644
--- a/Towers/Components/FrostComponent.gd
+++ b/Towers/Components/FrostComponent.gd
@@ -2,7 +2,7 @@ extends TowerComponent
func _init() -> void:
- name = "Frost"
+ type = ComponentType.Frost
set_sprite(preload("res://Towers/Components/Assets/frost-component.png"))
diff --git a/Towers/Components/RangeComponent.gd b/Towers/Components/RangeComponent.gd
new file mode 100644
index 0000000..a2f7ae7
--- /dev/null
+++ b/Towers/Components/RangeComponent.gd
@@ -0,0 +1,52 @@
+class_name RangeTowerComponent
+extends TowerComponent
+
+
+signal range_changed
+@warning_ignore("shadowed_global_identifier")
+var range := 0:
+ set(value):
+ range = value
+ range_changed.emit()
+
+var area := Area2D.new()
+var collision_shape := CollisionShape2D.new()
+var shape := CircleShape2D.new()
+
+var units_in_range: Array[Unit]
+
+
+func _init() -> void:
+ type = ComponentType.Range
+ set_sprite(preload("res://Towers/Components/Assets/range-component.png"))
+
+ update_range()
+ level_changed.connect(update_range)
+
+
+func update_range():
+ var tile_size = Client.current_stage.map.tile_set.tile_size.x
+ @warning_ignore("integer_division")
+ range = (tile_size * 2) + ((tile_size / 2) * level)
+ shape.radius = range
+
+
+func on_add(tower: Tower):
+ super.on_add(tower)
+
+ area.set_collision_layer_value(1, false)
+ area.set_collision_mask_value(1, true)
+
+ area.body_entered.connect(func(body: Node2D):
+ units_in_range.append(body)
+ )
+ area.body_exited.connect(func(body: Node2D):
+ units_in_range.erase(body)
+ )
+
+ area.position = tower.get_node("CenterAnchor").position
+
+ collision_shape.shape = shape
+ area.add_child(collision_shape)
+
+ tower.add_child(area)
diff --git a/Towers/Components/TowerComponent.gd b/Towers/Components/TowerComponent.gd
index 609f88c..7ca766a 100644
--- a/Towers/Components/TowerComponent.gd
+++ b/Towers/Components/TowerComponent.gd
@@ -1,30 +1,58 @@
class_name TowerComponent
-extends Resource
+extends Node
-var name: String
-var sprite: Sprite2D = Sprite2D.new()
-var level: int = 1
+var current_tower: Tower
+
+enum ComponentType {
+ Range,
+ Attack,
+ Speed,
+ Frost,
+ Burn,
+ Poison,
+}
+
+var type: ComponentType
+var sprite: TextureRect = TextureRect.new()
+
+var id: String:
+ get():
+ return get_type_name()
+
+signal level_changed
+var level: int = 1:
+ set(value):
+ level = value
+ level_changed.emit()
func set_sprite(texture: Texture2D):
sprite.texture = texture
sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
- sprite.centered = false
- sprite.scale = Vector2(2, 2)
- sprite.name = name
+ #sprite.centered = false
+ sprite.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
+ #sprite.scale = Vector2(2, 2)
+ sprite.name = get_type_name()
+
+
+func get_type_name(component_type: ComponentType = type):
+ return ComponentType.keys()[component_type]
+
+func on_add(tower: Tower):
+ current_tower = tower
class NetworkData extends Resource:
- var name: String
+ var type: ComponentType
var level: int
func to_network_data() -> NetworkData:
var data = NetworkData.new()
- data.name = name
+ data.type = type
data.level = level
return data
@@ -35,7 +63,7 @@ func update_with_network_data(_data: NetworkData):
static func from_network_data(data: NetworkData) -> TowerComponent:
var component = preload("res://Towers/Components/TowerComponent.gd").new()
- component.name = data.name
+ component.type = data.type
component.level = data.level
return component
diff --git a/Towers/Tower.gd b/Towers/Tower.gd
index 187cd93..1d856f3 100644
--- a/Towers/Tower.gd
+++ b/Towers/Tower.gd
@@ -40,7 +40,7 @@ var is_highlighted := false:
is_highlighted = value
queue_redraw()
-var mobs_in_range: Array = []
+#var mobs_in_range: Array = []
#var selection_area: Area2D
@@ -54,22 +54,22 @@ signal selection_group_id_changed(previous_id: String)
# rpc owner id
@export var owner_id = 1
-@export var attack_range: int = 32:
- set(value):
- attack_range = value
- $Range/CollisionShape2D.shape.radius = attack_range
- $SoundShoot.max_distance = attack_range * Client.current_stage.map.tile_set.tile_size.x
+#@export var attack_range: int = 32:
+ #set(value):
+ #attack_range = value
+ #$Range/CollisionShape2D.shape.radius = attack_range
+ #$SoundShoot.max_distance = attack_range * Client.current_stage.map.tile_set.tile_size.x
-@export var attack_power: int = 1
+#@export var attack_power: int = 1
-var attack_speed_base: float = 2.0
-@export var attack_speed: int = 1:
- set(value):
- attack_speed = value
- %ShootCooldown.wait_time = attack_speed_base / attack_speed
+#var attack_speed_base: float = 2.0
+#@export var attack_speed: int = 1:
+ #set(value):
+ #attack_speed = value
+ #%ShootCooldown.wait_time = attack_speed_base / attack_speed
signal components_changed
-@export var components: Array[TowerComponent] = []
+@export var components: Dictionary
func _init():
@@ -79,6 +79,9 @@ func _init():
func _ready():
$AnimatedSprite2D.play()
+ for component in [RangeTowerComponent.new(), AttackTowerComponent.new()]:
+ add_component(component)
+
redraw_components()
components_changed.connect(func():
selection_group_id = get_group_id()
@@ -92,7 +95,7 @@ func _draw():
if Client.state is StateDefault:
draw_circle(
Vector2(Client.current_stage.map.tile_set.tile_size) / scale,
- 8 + attack_range,
+ 8 + components.get(TowerComponent.ComponentType.Range).range,
Color(1, 1, 1, 0.5),
false,
1.0
@@ -112,11 +115,15 @@ func _draw():
)
-func _process(_delta: float) -> void:
+func _process(delta: float) -> void:
if multiplayer.is_server():
- if $ShootCooldown.is_stopped() and not mobs_in_range.is_empty():
- shoot()
- $ShootCooldown.start()
+ for component in components.values():
+ if component.has_method("process"):
+ component.process(delta)
+
+ #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()
@@ -139,11 +146,11 @@ func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int):
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.erase(body)
+#func _on_range_body_entered(body: Node2D) -> void:
+ #mobs_in_range.append(body)
+#
+#func _on_range_body_exited(body: Node2D) -> void:
+ #mobs_in_range.erase(body)
func _on_selectable_area_hover_enter() -> void:
@@ -168,49 +175,56 @@ func _on_selectable_area_select_primary(event: InputEvent) -> void:
func add_component(component: TowerComponent):
- components.append(component)
+ components[component.type] = component
+ component.on_add(self)
+
var sprite = component.sprite
- $ComponentsAnchor.add_child(sprite)
+ %ComponentsAnchor.add_child(sprite)
redraw_components()
+
components_changed.emit()
-func remove_component(component_name: String):
- for component in components:
- if component.name == component_name:
- components.erase(component)
- $ComponentsAnchor.remove_child($ComponentsAnchor.get_node(NodePath(component.name)))
- break
+func remove_component(component: TowerComponent):
+ components.erase(component.type)
+ %ComponentsAnchor.remove_child(%ComponentsAnchor.get_node(NodePath(component.id)))
+ #for component in components:
+ #if component.name == component_name:
+ #components.erase(component)
+ #$ComponentsAnchor.remove_child($ComponentsAnchor.get_node(NodePath(component.name)))
+ #break
redraw_components()
components_changed.emit()
func redraw_components():
- for idx in range(components.size()):
- var component = components[idx]
- var sprite = $ComponentsAnchor.get_node(NodePath(component.name))
+ var keys = components.keys()
+ for idx in range(keys.size()):
+ var key = keys[idx]
+ var component: TowerComponent = components[key]
+ var sprite = %ComponentsAnchor.get_node(NodePath(component.id))
sprite.position.y = (idx + 1) * -16
-func is_melee_range():
- return attack_range <= (Client.current_stage.map.tile_set.tile_size.x * 2)
-
-
-func shoot():
- var target = mobs_in_range[0] as Unit
-
- for component in components:
- if component.has_method("on_shoot"):
- component.on_shoot(target)
-
- shoot_fx.rpc()
-
- if is_melee_range():
- target.set_hp(target.hp - 1)
- else: # TODO
- target.set_hp(target.hp - 1)
-
-@rpc("authority", "call_local")
-func shoot_fx():
- $SoundShoot.play()
+#func is_melee_range():
+ #return attack_range <= (Client.current_stage.map.tile_set.tile_size.x * 2)
+
+
+#func shoot():
+ #var target = mobs_in_range[0] as Unit
+ #
+ #for component in components:
+ #if component.has_method("on_shoot"):
+ #component.on_shoot(target)
+ #
+ #shoot_fx.rpc()
+ #
+ #if is_melee_range():
+ #target.set_hp(target.hp - 1)
+ #else: # TODO
+ #target.set_hp(target.hp - 1)
+#
+#@rpc("authority", "call_local")
+#func shoot_fx():
+ #$SoundShoot.play()
@@ -227,12 +241,12 @@ func get_region():
func get_group_id() -> String:
var string := ""
- string += str(attack_range)
- string += str(attack_power)
- string += str(attack_speed)
+ #string += str(attack_range)
+ #string += str(attack_power)
+ #string += str(attack_speed)
- for component in components:
- string += component.name
+ for component: TowerComponent in components.values():
+ string += component.id
string += str(component.level)
return string.md5_text()
@@ -263,15 +277,15 @@ func to_network_data() -> NetworkData:
data.owner_id = owner_id
data.position = global_position
- data.attack_range = attack_range
- data.attack_power = attack_power
- data.attack_speed = attack_speed
- data.components = components.map(func(item: TowerComponent):
+ #data.attack_range = attack_range
+ #data.attack_power = attack_power
+ #data.attack_speed = attack_speed
+ data.components = components.values().map(func(item: TowerComponent):
return inst_to_dict(item.to_network_data())
)
data.sprite_modulate = $AnimatedSprite2D.modulate
- data.components_anchor_modulate = $ComponentsAnchor.modulate
+ data.components_anchor_modulate = %ComponentsAnchor.modulate
# IMPROVEMENT: check against last update and only set changed values
@@ -279,7 +293,7 @@ func to_network_data() -> NetworkData:
func update_with_network_data(data: NetworkData):
for component in components.duplicate():
- remove_component(component.name)
+ remove_component(component.id)
for component_data in data.components:
var component_network_data: TowerComponent.NetworkData = dict_to_inst(component_data)
@@ -294,11 +308,11 @@ static func from_network_data(data: NetworkData) -> Tower:
tower.owner_id = data.owner_id
tower.global_position = data.position
- tower.attack_range = data.attack_range
- tower.attack_power = data.attack_power
- tower.attack_speed = data.attack_speed
+ #tower.attack_range = data.attack_range
+ #tower.attack_power = data.attack_power
+ #tower.attack_speed = data.attack_speed
tower.get_node("AnimatedSprite2D").modulate = data.sprite_modulate
- tower.get_node("ComponentsAnchor").modulate = data.components_anchor_modulate
+ tower.get_node("%ComponentsAnchor").modulate = data.components_anchor_modulate
return tower
diff --git a/Towers/Tower.tscn b/Towers/Tower.tscn
index 25388f6..0bd4579 100644
--- a/Towers/Tower.tscn
+++ b/Towers/Tower.tscn
@@ -93,6 +93,7 @@ shape = SubResource("RectangleShape2D_atm5x")
[node name="Range" type="Area2D" parent="."]
unique_name_in_owner = true
+visible = false
collision_layer = 0
[node name="CollisionShape2D" type="CollisionShape2D" parent="Range"]
@@ -109,13 +110,23 @@ one_shot = true
position = Vector2(16, 16)
shape = SubResource("RectangleShape2D_312i7")
-[node name="ComponentsAnchor" type="Marker2D" parent="."]
-position = Vector2(0, 32)
+[node name="ComponentsAnchor" type="HFlowContainer" parent="."]
+unique_name_in_owner = true
+offset_right = 32.0
+offset_bottom = 32.0
+size_flags_vertical = 3
+theme_override_constants/h_separation = 0
+theme_override_constants/v_separation = 0
+reverse_fill = true
[node name="GroundAnchor" type="Marker2D" parent="."]
position = Vector2(16, 29)
+[node name="CenterAnchor" type="Marker2D" parent="."]
+position = Vector2(16, 16)
+
[node name="SoundShoot" type="AudioStreamPlayer2D" parent="."]
+visible = false
stream = ExtResource("5_i05ow")
[connection signal="input_event" from="." to="." method="_on_input_event"]
diff --git a/UI/ContainContainer.tscn b/UI/ContainContainer.tscn
new file mode 100644
index 0000000..d9120ed
--- /dev/null
+++ b/UI/ContainContainer.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=3 uid="uid://pchnqnutfth7"]
+
+[ext_resource type="Script" path="res://UI/contain_container.gd" id="1_oswre"]
+
+[node name="ContainContainer" type="Container"]
+script = ExtResource("1_oswre")
diff --git a/UI/contain_container.gd b/UI/contain_container.gd
new file mode 100644
index 0000000..df6e3a8
--- /dev/null
+++ b/UI/contain_container.gd
@@ -0,0 +1,10 @@
+@tool
+class_name ContainContainer
+extends Container
+
+
+func _notification(what: int) -> void:
+ if what == NOTIFICATION_SORT_CHILDREN:
+ for child in get_children():
+ if child is Control:
+ fit_child_in_rect(child, Rect2(Vector2.ZERO, size))
diff --git a/project.godot b/project.godot
index 785dd86..193ce14 100644
--- a/project.godot
+++ b/project.godot
@@ -63,6 +63,7 @@ builder_tower_select={
builder_cancel={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":2,"position":Vector2(152, 20),"global_position":Vector2(156, 61),"factor":1.0,"button_index":2,"canceled":false,"pressed":true,"double_click":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
builder_tower_place_keep={