Complete lab, quest, garrison, and energy tickets
This commit is contained in:
parent
d413d1da9f
commit
0f7edff15a
20 changed files with 238 additions and 45 deletions
|
|
@ -1,5 +1,7 @@
|
|||
extends Area2D
|
||||
|
||||
const COMBAT_TARGET = preload("res://core/CombatTarget.gd")
|
||||
|
||||
# #86: faster. The bolt used to crawl far enough behind a moving target that
|
||||
# leading a shot was guesswork rather than skill.
|
||||
# #155: was 850, which took 1.1s to cross the gun's own range - long enough
|
||||
|
|
@ -54,9 +56,9 @@ func _physics_process(delta: float) -> void:
|
|||
|
||||
|
||||
func _on_area_entered(area: Area2D) -> void:
|
||||
# Asteroids answer take_damage() exactly as enemies do, so both are hit by
|
||||
# the same branch rather than by a second special case.
|
||||
if area.is_in_group("enemies") or area.is_in_group("asteroids"):
|
||||
# Anything that opted into the weapon-target contract answers take_damage(),
|
||||
# so adding a new target composition needs no projectile type check.
|
||||
if area.is_in_group(COMBAT_TARGET.GROUP):
|
||||
area.take_damage(damage)
|
||||
queue_free()
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ extends Area2D
|
|||
signal destroyed
|
||||
|
||||
const VESSEL_DEFINITIONS = preload("res://vessels/VesselDefinitions.gd")
|
||||
const COMBAT_TARGET = preload("res://core/CombatTarget.gd")
|
||||
|
||||
@export var max_speed: float = 460.0
|
||||
@export var acceleration: float = 450.0
|
||||
|
|
@ -200,17 +201,14 @@ func _breakaway_direction() -> Vector2:
|
|||
|
||||
|
||||
func _on_area_entered(area: Area2D) -> void:
|
||||
if not (area.is_in_group("enemies") or area.is_in_group("asteroids")):
|
||||
if not area.is_in_group(COMBAT_TARGET.GROUP):
|
||||
return
|
||||
# The enemy is told about the impact BEFORE this ship resolves its own
|
||||
# damage, because resolving it can free this node - and a ship that dies
|
||||
# to a ramming chaser must still take the chaser with it. Whether the
|
||||
# impact actually destroys the enemy is the enemy's decision (#82).
|
||||
if area.is_in_group("enemies") and area.has_method("collide_with_player_vessel"):
|
||||
# A target is told about the impact BEFORE this ship resolves its own
|
||||
# damage, because resolving it can free this node. Whether the impact does
|
||||
# anything to the target is part of that target's composition (#82).
|
||||
if area.has_method("collide_with_player_vessel"):
|
||||
area.collide_with_player_vessel()
|
||||
var absorbed: bool = take_damage(1)
|
||||
if absorbed and area.is_in_group("asteroids") and is_instance_valid(area):
|
||||
area.queue_free()
|
||||
take_damage(1)
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
class_name VesselGarrisonComponent
|
||||
extends Node
|
||||
|
||||
const COMBAT_TARGET = preload("res://core/CombatTarget.gd")
|
||||
|
||||
# #105 (#97g): "When a vessel is assigned to an outpost, it navigates around
|
||||
# the outpost by itself, attacking nearby ennemies if any are detected."
|
||||
#
|
||||
|
|
@ -66,7 +68,7 @@ func is_engaging() -> bool:
|
|||
|
||||
func tick(delta: float) -> void:
|
||||
var ship: Node2D = get_parent()
|
||||
var target: Node2D = _nearest_enemy(ship)
|
||||
var target: Node2D = _nearest_target(ship)
|
||||
_engaging = target != null
|
||||
if target == null:
|
||||
_patrol(ship, delta)
|
||||
|
|
@ -176,20 +178,27 @@ func _hold_fire(ship: Node2D) -> void:
|
|||
weapon.set_fire_direction(Vector2.ZERO)
|
||||
|
||||
|
||||
func _nearest_enemy(ship: Node2D) -> Node2D:
|
||||
func _nearest_target(ship: Node2D) -> Node2D:
|
||||
var nearest: Node2D = null
|
||||
var best: float = detection_range
|
||||
for enemy in get_tree().get_nodes_in_group("enemies"):
|
||||
if not is_instance_valid(enemy) or enemy.is_queued_for_deletion():
|
||||
var best_distance: float = INF
|
||||
var best_priority: int = -1
|
||||
for target_node in get_tree().get_nodes_in_group(COMBAT_TARGET.GROUP):
|
||||
if not is_instance_valid(target_node) or not (target_node is Node2D) \
|
||||
or target_node.is_queued_for_deletion():
|
||||
continue
|
||||
var at: Vector2 = (enemy as Node2D).global_position
|
||||
var target: Node2D = target_node as Node2D
|
||||
var at: Vector2 = target.global_position
|
||||
# Judged from the POST, not from the vessel: otherwise a garrison
|
||||
# that had drifted out to its leash would see further still, and
|
||||
# could be walked away from its outpost one enemy at a time.
|
||||
if station.distance_to(at) > leash_range + engage_distance:
|
||||
continue
|
||||
var d: float = ship.global_position.distance_to(at)
|
||||
if d < best:
|
||||
best = d
|
||||
nearest = enemy
|
||||
if d > detection_range:
|
||||
continue
|
||||
var priority: int = COMBAT_TARGET.priority(target)
|
||||
if priority > best_priority or (priority == best_priority and d < best_distance):
|
||||
best_priority = priority
|
||||
best_distance = d
|
||||
nearest = target
|
||||
return nearest
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ var fire_timer: float = 0.0
|
|||
var fire_target: Vector2 = Vector2.ZERO
|
||||
var has_fire_target: bool = false
|
||||
var projectile_scene: PackedScene = preload("res://vessels/Projectile.tscn")
|
||||
const COMBAT_TARGET = preload("res://core/CombatTarget.gd")
|
||||
# By path, not by class name - see the note at the top of MuzzleSparkVFX.
|
||||
const MUZZLE_SPARK = preload("res://vfx/MuzzleSparkVFX.gd")
|
||||
|
||||
|
|
@ -58,7 +59,6 @@ const ASSIST_CONE_DEGREES: float = 28.0
|
|||
# smaller than the directional cone at ordinary weapon range: it catches a
|
||||
# pointer placed beside something without making the whole screen magnetic.
|
||||
const ASSIST_CURSOR_RADIUS: float = 180.0
|
||||
const ASSIST_TARGET_GROUP: StringName = &"player_aim_targets"
|
||||
|
||||
|
||||
# The concrete point an aim should stick to. A target can qualify in two ways:
|
||||
|
|
@ -81,7 +81,7 @@ static func assisted_point(tree: SceneTree, origin: Vector2, point: Vector2,
|
|||
var cursor_distance: float = INF
|
||||
var direction_pick: Node2D = null
|
||||
var direction_distance: float = INF
|
||||
for target_node in tree.get_nodes_in_group(ASSIST_TARGET_GROUP):
|
||||
for target_node in tree.get_nodes_in_group(COMBAT_TARGET.GROUP):
|
||||
if not is_instance_valid(target_node) or not (target_node is Node2D) \
|
||||
or target_node.is_queued_for_deletion():
|
||||
continue
|
||||
|
|
|
|||
Loading…
Reference in a new issue