diff --git a/buildings/BuildingDefinitions.gd b/buildings/BuildingDefinitions.gd index 727c905..4ebdb9a 100644 --- a/buildings/BuildingDefinitions.gd +++ b/buildings/BuildingDefinitions.gd @@ -1,13 +1,14 @@ class_name BuildingDefinitions extends RefCounted -const ORDER: PackedStringArray = ["mothership", "ship_crafter", "command_center", "outpost", "planning_center", "extractor", "transport_hub", "ship_lab", "gas_burner"] +const ORDER: PackedStringArray = ["mothership", "ship_crafter", "command_center", "outpost", "planning_center", "spacial_workshop", "extractor", "transport_hub", "ship_lab", "gas_burner"] const DEFINITIONS: Dictionary = { "mothership": preload("res://buildings/MothershipBuildingDefinition.tres"), "ship_crafter": preload("res://buildings/CrafterBuildingDefinition.tres"), "command_center": preload("res://buildings/CommandBuildingDefinition.tres"), "outpost": preload("res://buildings/OutpostBuildingDefinition.tres"), "planning_center": preload("res://buildings/PlanningBuildingDefinition.tres"), + "spacial_workshop": preload("res://buildings/WorkshopBuildingDefinition.tres"), "extractor": preload("res://buildings/ExtractorBuildingDefinition.tres"), "transport_hub": preload("res://buildings/TransportHubBuildingDefinition.tres"), "ship_lab": preload("res://buildings/ShipLabBuildingDefinition.tres"), diff --git a/buildings/WorkshopBuildingDefinition.tres b/buildings/WorkshopBuildingDefinition.tres new file mode 100644 index 0000000..2f781d1 --- /dev/null +++ b/buildings/WorkshopBuildingDefinition.tres @@ -0,0 +1,20 @@ +[gd_resource type="Resource" script_class="BuildingDefinition" load_steps=3 format=3] +[ext_resource type="Script" path="res://buildings/BuildingDefinition.gd" id="1"] +[ext_resource type="PackedScene" path="res://buildings/WorkshopBuildingVisual.tscn" id="2"] +[resource] +script = ExtResource("1") +definition_id = "spacial_workshop" +display_name = "Spacial Workshop" +description = "Sends repair drones out to damaged structures. Repairs cost ore in proportion to the damage, delivered here by hub transporters." +cost = 55 +action_icon = 42 +menu_icon = 42 +visual_scene = ExtResource("2") +capabilities = PackedStringArray("repair") +map_color = Color(0.5, 0.95, 0.8, 1) +map_sides = 5 +map_radius = 7.0 +menu_button_name = "WorkshopButton" +menu_label_name = "WorkshopLabel" +menu_cost_name = "WorkshopCost" +max_hp = 70 diff --git a/buildings/WorkshopBuildingVisual.gd b/buildings/WorkshopBuildingVisual.gd new file mode 100644 index 0000000..86697ce --- /dev/null +++ b/buildings/WorkshopBuildingVisual.gd @@ -0,0 +1,13 @@ +extends "res://buildings/BuildingVisualBase.gd" + +# Drawn once, like the command centre and the outpost. #117 makes the +# animated buildings stop when idle; this one has nothing that moves, so +# there is nothing to gate. + +func _ready() -> void: + set_process(false) + queue_redraw() + +func _draw() -> void: + register_draw() + _draw_workshop() diff --git a/buildings/WorkshopBuildingVisual.tscn b/buildings/WorkshopBuildingVisual.tscn new file mode 100644 index 0000000..07b91bb --- /dev/null +++ b/buildings/WorkshopBuildingVisual.tscn @@ -0,0 +1,11 @@ +[gd_scene load_steps=3 format=3] + +[ext_resource type="Script" path="res://buildings/WorkshopBuildingVisual.gd" id="1"] +[ext_resource type="Script" path="res://buildings/BuildingActionProvider.gd" id="2"] + +[node name="Visual" type="Node2D"] +script = ExtResource("1") + +[node name="ActionProvider" type="Node" parent="."] +script = ExtResource("2") +actions = PackedStringArray("transfer") diff --git a/logistics/RepairDrone.gd b/logistics/RepairDrone.gd new file mode 100644 index 0000000..81c0e7d --- /dev/null +++ b/logistics/RepairDrone.gd @@ -0,0 +1,40 @@ +extends Node2D + +# #116: purely visual - a repair drone on its way out to a damaged structure +# or back to its workshop. Carries no state of its own; GameState owns the +# simulation and RepairDroneField creates, positions and frees this to match. + +const HULL_COLOR: Color = Color(0.5, 0.95, 0.8) + +var laden: bool = false + + +func _ready() -> void: + add_to_group("repair_drones") + # #91: behind the fleet, like every other piece of ground furniture. + z_index = -1 + queue_redraw() + + +func set_laden(value: bool) -> void: + if laden == value: + return + laden = value + queue_redraw() + + +func _draw() -> void: + # Small and blunt, with a tool arm out front, in the workshop's own + # green-teal: it should read as a tender belonging to a building rather + # than as a fleet vessel or a hub's magenta hauler. + var hull: PackedVector2Array = PackedVector2Array([ + Vector2(0, -11), Vector2(8, -3), Vector2(6, 10), Vector2(-6, 10), Vector2(-8, -3), + ]) + NeonDraw.draw_glowing_polygon(self, hull, HULL_COLOR, 1.0) + NeonDraw.draw_glowing_line(self, Vector2(0, -11), Vector2(0, -18), HULL_COLOR, 0.9, 0.35) + NeonDraw.draw_glowing_line(self, Vector2(-5, -18), Vector2(5, -18), HULL_COLOR, 0.9, 0.35) + if laden: + # The load it is carrying out, in ore's own colour so it reads as + # material rather than as a light on the hull. + NeonDraw.draw_glowing_circle(self, Vector2(0, 3), 5.0, + GameState.resource_color(GameState.RESOURCE_ORE), 1.0) diff --git a/logistics/RepairDrone.tscn b/logistics/RepairDrone.tscn new file mode 100644 index 0000000..d40602f --- /dev/null +++ b/logistics/RepairDrone.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3] + +[ext_resource type="Script" path="res://logistics/RepairDrone.gd" id="1"] + +[node name="RepairDrone" type="Node2D"] +script = ExtResource("1") diff --git a/logistics/RepairDroneField.gd b/logistics/RepairDroneField.gd new file mode 100644 index 0000000..1d6b040 --- /dev/null +++ b/logistics/RepairDroneField.gd @@ -0,0 +1,59 @@ +extends Node2D + +# #116: draws the repair drones GameState is simulating, and only while they +# are somewhere the player could see them. +# +# Same arrangement as TransporterField, and for the same reason: the +# simulation is authoritative and the visuals are optional, so a repair run +# happening far away costs nothing but still puts the building back together. +# Position comes from the very same `progress` that decides when the repair +# actually lands. + +@export var visible_radius: float = 2600.0 + +@onready var fleet: Node2D = get_node("../Fleet") + +var drone_scene: PackedScene = preload("res://logistics/RepairDrone.tscn") +# index into GameState.repair_drones -> live node +var active: Dictionary = {} + + +func _process(_delta: float) -> void: + var centre: Vector2 = fleet.get_centroid() + + for i in range(GameState.repair_drones.size()): + var drone: Dictionary = GameState.repair_drones[i] + # An idle drone is parked inside its workshop's own art; drawing it + # there adds a dot sitting on a building rather than a vessel doing + # something. + if String(drone.state) == GameState.DRONE_IDLE: + _despawn(i) + continue + var pos: Vector2 = GameState.repair_drone_position(drone) + if pos.distance_to(centre) > visible_radius: + _despawn(i) + continue + + var node: Node2D = active.get(i) + if node == null or not is_instance_valid(node): + node = drone_scene.instantiate() + get_parent().add_child(node) + active[i] = node + + var previous: Vector2 = node.position + node.position = pos + node.set_laden(int(drone.carrying) > 0) + var travel: Vector2 = pos - previous + if travel.length() > 0.5: + node.rotation = travel.angle() + PI / 2.0 + + for key in active.keys(): + if key >= GameState.repair_drones.size(): + _despawn(key) + + +func _despawn(index: int) -> void: + var node: Node2D = active.get(index) + if node != null and is_instance_valid(node): + node.queue_free() + active.erase(index) diff --git a/vessels/RepairDroneVesselDefinition.tres b/vessels/RepairDroneVesselDefinition.tres new file mode 100644 index 0000000..30b0212 --- /dev/null +++ b/vessels/RepairDroneVesselDefinition.tres @@ -0,0 +1,16 @@ +[gd_resource type="Resource" script_class="VesselDefinition" load_steps=4 format=3] +[ext_resource type="Script" path="res://vessels/VesselDefinition.gd" id="1"] +[ext_resource type="Resource" path="res://vessels/RepairYieldUpgrade.tres" id="2"] +[ext_resource type="Resource" path="res://vessels/RepairSpeedUpgrade.tres" id="3"] +[resource] +script = ExtResource("1") +definition_id = "repair_drone" +display_name = "Repair Drone" +description = "Workshop-owned tender. Flies out to damaged structures and puts them back together, spending ore delivered to its workshop. Cannot be crafted - a workshop brings its own." +build_cost = 0 +build_time = 0.0 +icon = 43 +glow_color = Color(0.5, 0.95, 0.8, 1) +hull_points = PackedVector2Array(0, -14, 9, -4, 7, 10, -7, 10, -9, -4) +base_stats = {"max_speed": 620.0, "acceleration": 1800.0, "transport_speed": 190.0, "repair_amount": 25.0, "delivery_speed": 180.0} +upgrades = Array[Resource]([ExtResource("2"), ExtResource("3")]) diff --git a/vessels/RepairSpeedUpgrade.tres b/vessels/RepairSpeedUpgrade.tres new file mode 100644 index 0000000..ab28a76 --- /dev/null +++ b/vessels/RepairSpeedUpgrade.tres @@ -0,0 +1,12 @@ +[gd_resource type="Resource" script_class="VesselUpgradeDefinition" load_steps=2 format=3] +[ext_resource type="Script" path="res://vessels/VesselUpgradeDefinition.gd" id="1"] +[resource] +script = ExtResource("1") +upgrade_id = "rep_speed" +display_name = "Yard Thrusters" +description = "+80 speed on repair runs." +base_cost = 35 +max_level = 3 +research_point_cost = 1 +icon = 22 +additive_modifiers = {"transport_speed": 80.0} diff --git a/vessels/RepairYieldUpgrade.tres b/vessels/RepairYieldUpgrade.tres new file mode 100644 index 0000000..05bea8b --- /dev/null +++ b/vessels/RepairYieldUpgrade.tres @@ -0,0 +1,12 @@ +[gd_resource type="Resource" script_class="VesselUpgradeDefinition" load_steps=2 format=3] +[ext_resource type="Script" path="res://vessels/VesselUpgradeDefinition.gd" id="1"] +[resource] +script = ExtResource("1") +upgrade_id = "rep_yield" +display_name = "Heavy Plating" +description = "+12 structure put back on every repair run." +base_cost = 40 +max_level = 3 +research_point_cost = 1 +icon = 17 +additive_modifiers = {"repair_amount": 12.0} diff --git a/vessels/VesselDefinitions.gd b/vessels/VesselDefinitions.gd index dbc00a8..58370ed 100644 --- a/vessels/VesselDefinitions.gd +++ b/vessels/VesselDefinitions.gd @@ -1,7 +1,7 @@ class_name VesselDefinitions extends RefCounted -const ORDER: PackedStringArray = ["interceptor", "shield", "gas_bomber", "transporter", "carrier", "laser", "distorder"] +const ORDER: PackedStringArray = ["interceptor", "shield", "gas_bomber", "transporter", "carrier", "laser", "distorder", "repair_drone"] const DEFINITIONS: Dictionary = { "interceptor": preload("res://vessels/InterceptorVesselDefinition.tres"), "shield": preload("res://vessels/ShieldVesselDefinition.tres"), @@ -10,6 +10,7 @@ const DEFINITIONS: Dictionary = { "carrier": preload("res://vessels/CarrierVesselDefinition.tres"), "laser": preload("res://vessels/LaserVesselDefinition.tres"), "distorder": preload("res://vessels/DistorderVesselDefinition.tres"), + "repair_drone": preload("res://vessels/RepairDroneVesselDefinition.tres"), } static func get_definition(definition_id: String) -> Resource: