diff --git a/source/match/MatchSignals.gd b/source/match/MatchSignals.gd index aa49a20..0f04f14 100644 --- a/source/match/MatchSignals.gd +++ b/source/match/MatchSignals.gd @@ -17,3 +17,4 @@ signal unit_deselected(unit) signal unit_died(unit) signal unit_production_started(unit_prototype, producer_unit) signal not_enough_resources_for_production(player) +signal resource_depleted(resource) diff --git a/source/match/players/human/UnitActionsController.gd b/source/match/players/human/UnitActionsController.gd index dfa8aab..22ed789 100644 --- a/source/match/players/human/UnitActionsController.gd +++ b/source/match/players/human/UnitActionsController.gd @@ -49,15 +49,19 @@ func _try_navigating_selected_units_towards_position(target_point): unit.action = Actions.Moving.new(new_target) -func _try_setting_rally_points(target_point: Vector3): +func _try_setting_rally_points(target): + # can a day exists an unit who can spawn units? var controlled_structures = get_tree().get_nodes_in_group("selected_units").filter( func(unit): return unit.is_in_group("controlled_units") and unit.find_child("RallyPoint") != null ) for structure in controlled_structures: var rally_point = structure.find_child("RallyPoint") - if rally_point != null: - rally_point.global_position = target_point + if ( + rally_point != null + && (target is Vector3 || not (target.is_in_group("adversary_units"))) + ): + rally_point.set_target(target) func _try_ordering_selected_workers_to_construct_structure(potential_structure): @@ -80,30 +84,37 @@ func _navigate_selected_units_towards_unit(target_unit): for unit in get_tree().get_nodes_in_group("selected_units"): if not unit.is_in_group("controlled_units"): continue - if Actions.CollectingResourcesSequentially.is_applicable(unit, target_unit): - unit.action = Actions.CollectingResourcesSequentially.new(target_unit) - units_navigated += 1 - elif Actions.AutoAttacking.is_applicable(unit, target_unit): - unit.action = Actions.AutoAttacking.new(target_unit) - units_navigated += 1 - elif Actions.Constructing.is_applicable(unit, target_unit): - unit.action = Actions.Constructing.new(target_unit) - units_navigated += 1 - elif ( - ( - target_unit.is_in_group("adversary_units") - or target_unit.is_in_group("controlled_units") - ) - and Actions.Following.is_applicable(unit) - ): - unit.action = Actions.Following.new(target_unit) - units_navigated += 1 - elif Actions.MovingToUnit.is_applicable(unit): - unit.action = Actions.MovingToUnit.new(target_unit) + + if navigate_unit_towards_unit(unit, target_unit): units_navigated += 1 + return units_navigated > 0 +# im not sure if an static function is a good solution here in godot, but liked to "move" a new spawned unit. +static func navigate_unit_towards_unit(unit, target_unit): + var action_generated = false + if Actions.CollectingResourcesSequentially.is_applicable(unit, target_unit): + unit.action = Actions.CollectingResourcesSequentially.new(target_unit) + action_generated = true + elif Actions.AutoAttacking.is_applicable(unit, target_unit): + unit.action = Actions.AutoAttacking.new(target_unit) + action_generated = true + elif Actions.Constructing.is_applicable(unit, target_unit): + unit.action = Actions.Constructing.new(target_unit) + action_generated = true + elif ( + (target_unit.is_in_group("adversary_units") or target_unit.is_in_group("controlled_units")) + and Actions.Following.is_applicable(unit) + ): + unit.action = Actions.Following.new(target_unit) + action_generated = true + elif Actions.MovingToUnit.is_applicable(unit): + unit.action = Actions.MovingToUnit.new(target_unit) + action_generated = true + return action_generated + + func _on_terrain_targeted(position): _try_navigating_selected_units_towards_position(position) _try_setting_rally_points(position) @@ -114,6 +125,7 @@ func _on_unit_targeted(unit): var targetability = unit.find_child("Targetability") if targetability != null: targetability.animate() + _try_setting_rally_points(unit) func _on_unit_spawned(unit): diff --git a/source/match/units/non-player/ResourceA.gd b/source/match/units/non-player/ResourceA.gd index 95643e7..99a80b0 100644 --- a/source/match/units/non-player/ResourceA.gd +++ b/source/match/units/non-player/ResourceA.gd @@ -7,7 +7,7 @@ const MATERIAL_ALBEDO_TO_REPLACE_EPSILON = 0.05 set(value): resource_a = max(0, value) if resource_a == 0: - queue_free() + _free_me() var color = Constants.Match.Resources.A.COLOR: set(_value): diff --git a/source/match/units/non-player/ResourceB.gd b/source/match/units/non-player/ResourceB.gd index 53a1c45..29d0d2e 100644 --- a/source/match/units/non-player/ResourceB.gd +++ b/source/match/units/non-player/ResourceB.gd @@ -7,7 +7,7 @@ const MATERIAL_ALBEDO_TO_REPLACE_EPSILON = 0.05 set(value): resource_b = max(0, value) if resource_b == 0: - queue_free() + _free_me() var color = Constants.Match.Resources.B.COLOR: set(_value): diff --git a/source/match/units/non-player/ResourceUnit.gd b/source/match/units/non-player/ResourceUnit.gd index 62daa6c..535ed25 100644 --- a/source/match/units/non-player/ResourceUnit.gd +++ b/source/match/units/non-player/ResourceUnit.gd @@ -18,3 +18,8 @@ func _animate_decay(): var decay_animation = ResourceDecayAnimation.instantiate() decay_animation.global_transform = global_transform get_parent().add_child.call_deferred(decay_animation) + + +func _free_me(): + MatchSignals.resource_depleted.emit(self) + queue_free() diff --git a/source/match/units/traits/ProductionQueue.gd b/source/match/units/traits/ProductionQueue.gd index 6ef2acd..ede3931 100644 --- a/source/match/units/traits/ProductionQueue.gd +++ b/source/match/units/traits/ProductionQueue.gd @@ -4,6 +4,9 @@ signal element_enqueued(element) signal element_removed(element) const Moving = preload("res://source/match/units/actions/Moving.gd") +const Unit = preload("res://source/match/units/Unit.gd") +const ResourceUnit = preload("res://source/match/units/non-player/ResourceUnit.gd") +const UnitActionsController = preload("res://source/match/players/human/UnitActionsController.gd") class ProductionQueueElement: @@ -109,7 +112,10 @@ func _finalize_production(former_queue_element): # Handle rally point if _unit.has_node("RallyPoint") and Moving.is_applicable(produced_unit): - var rally_point = _unit.get_node("RallyPoint").global_position + var rally_point = _unit.get_node("RallyPoint").get_target() - if rally_point != _unit.global_position: - produced_unit.action = Moving.new(rally_point) + if rally_point: + if rally_point is Vector3 && rally_point != _unit.global_position: + produced_unit.action = Moving.new(rally_point) + elif rally_point is Unit || rally_point is ResourceUnit: + UnitActionsController.navigate_unit_towards_unit(produced_unit, rally_point) diff --git a/source/match/units/traits/RallyPoint.gd b/source/match/units/traits/RallyPoint.gd index 51a84b0..4a527e5 100644 --- a/source/match/units/traits/RallyPoint.gd +++ b/source/match/units/traits/RallyPoint.gd @@ -1,11 +1,44 @@ extends Node3D +const Unit = preload("res://source/match/units/Unit.gd") + @onready var _unit = get_parent() @onready var _animation_player = find_child("AnimationPlayer") +var _target = null + func _ready(): _animation_player.play("idle") visible = _unit.is_in_group("selected_units") _unit.selected.connect(show) _unit.deselected.connect(hide) + MatchSignals.unit_died.connect(_restore_rally_point_position) # to unfollow when unit die + MatchSignals.resource_depleted.connect(_restore_rally_point_position) # to unfollow when resource depleted + + +func _restore_rally_point_position(target): + if not (_target is Vector3) && target == _target: + _target = null + global_position = _unit.global_position + + +func set_target(target): + # unselect prev rally point + if _target != null && not (_target is Vector3): + var rp_selection = _target.find_child("Selection") + if rp_selection != null: + rp_selection.hide_selection_circle() + + _target = target + if _target is Vector3: + global_position = target + else: + global_position = _unit.global_position + var rp_selection = _target.find_child("Selection") + if rp_selection != null: + rp_selection.show_selection_circle() + + +func get_target(): + return _target diff --git a/source/match/units/traits/Selection.gd b/source/match/units/traits/Selection.gd index 131b36c..48f59a5 100644 --- a/source/match/units/traits/Selection.gd +++ b/source/match/units/traits/Selection.gd @@ -21,14 +21,32 @@ func _ready(): _circle.hide() +func show_selection_circle(): + _update_circle_color() + _circle.show() + + +func hide_selection_circle(): + _circle.hide() + + func select(): if _selected: return _selected = true if not _unit.is_in_group("selected_units"): _unit.add_to_group("selected_units") - _update_circle_color() - _circle.show() + show_selection_circle() + + # also show as selected rally point, but not add to selection group + if _unit.has_node("RallyPoint"): + var rally_point = _unit.get_node("RallyPoint").get_target() + + if rally_point != null && not (rally_point is Vector3): + var rp_selection = rally_point.find_child("Selection") + if rp_selection != null: + rp_selection.show_selection_circle() + if "selected" in _unit: _unit.selected.emit() MatchSignals.unit_selected.emit(_unit) @@ -40,7 +58,16 @@ func deselect(): _selected = false if _unit.is_in_group("selected_units"): _unit.remove_from_group("selected_units") - _circle.hide() + hide_selection_circle() + + if _unit.has_node("RallyPoint"): + var rally_point = _unit.get_node("RallyPoint").get_target() + + if rally_point != null && not (rally_point is Vector3): + var rp_selection = rally_point.find_child("Selection") + if rp_selection != null: + rp_selection.hide_selection_circle() + if "deselected" in _unit: _unit.deselected.emit() MatchSignals.unit_deselected.emit(_unit)