From f21f27ce7f6f9e87a555e7e9505beea8f82f32c0 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 19:25:30 +0100 Subject: [PATCH 01/17] `HeatSink` resource and ship property --- mechanics/heat/heat_sink.gd | 27 +++++++++++++++++++++++++++ ships/ship.gd | 5 +++++ 2 files changed, 32 insertions(+) create mode 100644 mechanics/heat/heat_sink.gd diff --git a/mechanics/heat/heat_sink.gd b/mechanics/heat/heat_sink.gd new file mode 100644 index 00000000..3ed48040 --- /dev/null +++ b/mechanics/heat/heat_sink.gd @@ -0,0 +1,27 @@ +extends SaveableResource +class_name HeatSink + +## Accumulates heat that is generated by ship functions and inflicted in combat. +## +## When heat exceeds the maximum capacity of the heat sink, the ship becomes disabled. + +## The maximum heat capacity for this sink. +@export var max_heat: float: + set(value): + assert(value >= 0.0, "Heat capacity must be non-negative") + if is_equal_approx(max_heat, value): + return + + max_heat = value + self.emit_changed() + +## The current heat level. +## +## Unlike other, similar mechanics, this value can exceed [member max_heat], at which point the ship is disabled. +@export var heat: float: + set(value): + if is_equal_approx(heat, value): + return + + heat = maxf(value, 0.0) + self.emit_changed() diff --git a/ships/ship.gd b/ships/ship.gd index f9cc4ca9..e4d095d9 100644 --- a/ships/ship.gd +++ b/ships/ship.gd @@ -51,6 +51,9 @@ class_name Ship ## The [Battery] powering the ship. @export var battery: Battery +## The [HeatSink] which accumulates ship heat. +@export var heat_sink: HeatSink + ## An optional cargo hold for this ship. @export var cargo_hold: CargoHold @@ -128,6 +131,7 @@ func save_to_dict() -> Dictionary: SaveGame.save_resource_property_into_dict(self, result, "hull") SaveGame.save_resource_property_into_dict(self, result, "battery") + SaveGame.save_resource_property_into_dict(self, result, "heat_sink") SaveGame.save_resource_property_into_dict(self, result, "shield") SaveGame.save_resource_property_into_dict(self, result, "hyperdrive") SaveGame.save_resource_property_into_dict(self, result, "cargo_hold") @@ -146,6 +150,7 @@ func load_from_dict(dict: Dictionary) -> void: SaveGame.load_resource_property_from_dict(self, dict, "hull") SaveGame.load_resource_property_from_dict(self, dict, "battery") + SaveGame.load_resource_property_from_dict(self, dict, "heat_sink") SaveGame.load_resource_property_from_dict(self, dict, "shield") SaveGame.load_resource_property_from_dict(self, dict, "hyperdrive") SaveGame.load_resource_property_from_dict(self, dict, "cargo_hold") From da1c00be96764c535f3dc0b82b7f28ede23b9916 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 19:27:58 +0100 Subject: [PATCH 02/17] Add `heat` to `Damage` --- mechanics/combat/damage.gd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mechanics/combat/damage.gd b/mechanics/combat/damage.gd index 5c596b8a..8ed714bf 100644 --- a/mechanics/combat/damage.gd +++ b/mechanics/combat/damage.gd @@ -12,3 +12,8 @@ class_name Damage ## ## If a damageable object has shields, damage is applied to the shields first, then the hull, in proportion. @export var hull_damage: float + +## How much heat will be inflicted on the target. +## +## Heat is not directly damaging, but can result in a ship becoming disabled. +@export var heat: float From 4594bbfd813493fbd7e2a9e822d0aba597c010c2 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 19:33:16 +0100 Subject: [PATCH 03/17] `Radiator` node --- mechanics/heat/radiator.gd | 12 ++++++++++++ ships/ship.gd | 4 ++++ 2 files changed, 16 insertions(+) create mode 100644 mechanics/heat/radiator.gd diff --git a/mechanics/heat/radiator.gd b/mechanics/heat/radiator.gd new file mode 100644 index 00000000..08f542c7 --- /dev/null +++ b/mechanics/heat/radiator.gd @@ -0,0 +1,12 @@ +extends Node3D +class_name Radiator + +## Radiates heat away from a [HeatSink] into vacuum. + +## How much heat is radiated away per second. +@export var rate: float + +var heat_sink: HeatSink + +func _physics_process(delta: float) -> void: + self.heat_sink.heat -= self.rate * delta diff --git a/ships/ship.gd b/ships/ship.gd index e4d095d9..2fa16f50 100644 --- a/ships/ship.gd +++ b/ships/ship.gd @@ -21,6 +21,9 @@ class_name Ship ## This ship's power management unit. @export var power_management_unit: PowerManagementUnit +## The ship's radiator to dissipate heat. +@export var radiator: Radiator + ## An object for representing this ship on radar. @export var radar_object: RadarObject @@ -94,6 +97,7 @@ func _ready() -> void: self.rigid_body_thruster.battery = self.battery self.rigid_body_direction.battery = self.battery self.power_management_unit.battery = self.battery + self.radiator.heat_sink = self.heat_sink if self.shield_recharger: self.shield_recharger.shield = self.shield From 1f22919950e43d1e45d7aa7bcbaa029ff2ca1336 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 19:37:13 +0100 Subject: [PATCH 04/17] Add heat sinks and radiators to all ship types --- ships/corvette01/corvette01.tscn | 18 ++++++++++++++++-- ships/freighter/freighter.tscn | 18 ++++++++++++++++-- ships/frigate03/frigate03.tscn | 18 ++++++++++++++++-- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/ships/corvette01/corvette01.tscn b/ships/corvette01/corvette01.tscn index 4ac6e13c..65708761 100644 --- a/ships/corvette01/corvette01.tscn +++ b/ships/corvette01/corvette01.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=32 format=3 uid="uid://dsuln1s4j366a"] +[gd_scene load_steps=35 format=3 uid="uid://dsuln1s4j366a"] [ext_resource type="PackedScene" uid="uid://c0eitctnmmfyq" path="res://ships/ship.tscn" id="1_cmgif"] [ext_resource type="ArrayMesh" uid="uid://40a23nnu1j37" path="res://ships/corvette01/corvette01_mesh.tres" id="1_yacfo"] @@ -8,6 +8,7 @@ [ext_resource type="AudioStream" uid="uid://5iqc5o8p02l5" path="res://ships/audio/THRUSTER LOW.wav" id="4_xrdjv"] [ext_resource type="Script" path="res://mechanics/economy/cargo_hold.gd" id="5_kmsu1"] [ext_resource type="Script" path="res://mechanics/combat/hull.gd" id="5_uewxf"] +[ext_resource type="Script" path="res://mechanics/heat/heat_sink.gd" id="5_vh7sc"] [ext_resource type="Script" path="res://mechanics/economy/passenger_quarters.gd" id="6_a0tra"] [ext_resource type="Script" path="res://mechanics/hyperspace/hyperdrive.gd" id="6_wd6xk"] [ext_resource type="Script" path="res://mechanics/physics/spin_thruster.gd" id="8_4hne6"] @@ -20,6 +21,7 @@ [ext_resource type="Script" path="res://mechanics/combat/weapons/weapon_mount.gd" id="15_douxu"] [ext_resource type="Resource" uid="uid://cw1tu3qdxdgfi" path="res://mechanics/combat/weapons/blaster/blaster.tres" id="16_17v50"] [ext_resource type="Script" path="res://mechanics/physics/rigid_body_cargo.gd" id="19_f3xy8"] +[ext_resource type="Script" path="res://mechanics/heat/radiator.gd" id="22_o7v2x"] [sub_resource type="Resource" id="Resource_5twpq"] resource_local_to_scene = true @@ -42,6 +44,12 @@ script = ExtResource("9_8bmn0") max_power = 100.0 power = 100.0 +[sub_resource type="Resource" id="Resource_8nr6w"] +resource_local_to_scene = true +script = ExtResource("5_vh7sc") +max_heat = 100.0 +heat = 0.0 + [sub_resource type="Resource" id="Resource_qh2kh"] resource_local_to_scene = true script = ExtResource("5_kmsu1") @@ -81,14 +89,16 @@ power_consumption_rate = 8.0 script = ExtResource("13_n5lfa") rate_of_power = 5.0 -[node name="Corvette" node_paths=PackedStringArray("shield_recharger", "weapon_mounts", "rigid_body_cargo") instance=ExtResource("1_cmgif")] +[node name="Corvette" node_paths=PackedStringArray("radiator", "shield_recharger", "weapon_mounts", "rigid_body_cargo") instance=ExtResource("1_cmgif")] mass = 10.0 +radiator = NodePath("Radiator") shield_recharger = NodePath("ShieldRecharger") weapon_mounts = [NodePath("Blaster"), NodePath("LeftWeaponMount"), NodePath("RightWeaponMount")] rigid_body_cargo = NodePath("RigidBodyCargo") hull = SubResource("Resource_5twpq") shield = SubResource("Resource_alskh") battery = SubResource("Resource_ftwkb") +heat_sink = SubResource("Resource_8nr6w") cargo_hold = SubResource("Resource_qh2kh") passenger_quarters = SubResource("Resource_7u7qk") hyperdrive = SubResource("Resource_br02e") @@ -160,4 +170,8 @@ transform = Transform3D(1, -1.21652e-31, 0, -1.21652e-31, 1, 0, 0, 0, 1, 0.199, script = ExtResource("15_douxu") fire_offset = 0.5 +[node name="Radiator" type="Node3D" parent="." index="13"] +script = ExtResource("22_o7v2x") +rate = 3.0 + [editable path="CombatObject/TargetOverlay"] diff --git a/ships/freighter/freighter.tscn b/ships/freighter/freighter.tscn index 2c84f808..f8968804 100644 --- a/ships/freighter/freighter.tscn +++ b/ships/freighter/freighter.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=30 format=3 uid="uid://dqrul5pyjbxjc"] +[gd_scene load_steps=33 format=3 uid="uid://dqrul5pyjbxjc"] [ext_resource type="PackedScene" uid="uid://c0eitctnmmfyq" path="res://ships/ship.tscn" id="1_r6j4w"] [ext_resource type="PackedScene" uid="uid://co3rcmgurh2gb" path="res://ships/freighter/freighter.glb" id="2_qliud"] @@ -7,6 +7,7 @@ [ext_resource type="Script" path="res://mechanics/combat/shield.gd" id="3_ti3ck"] [ext_resource type="Script" path="res://mechanics/combat/hull.gd" id="4_n1hc8"] [ext_resource type="Shader" path="res://fx/shield/shield.gdshader" id="4_unqrx"] +[ext_resource type="Script" path="res://mechanics/heat/heat_sink.gd" id="5_0dh7p"] [ext_resource type="PackedScene" uid="uid://cdyo800b83x5i" path="res://fx/explosions/explosion002.tscn" id="5_bgpiu"] [ext_resource type="Script" path="res://mechanics/combat/shield_recharger.gd" id="5_s17ip"] [ext_resource type="Script" path="res://mechanics/physics/spin_thruster.gd" id="8_ngx4b"] @@ -16,6 +17,7 @@ [ext_resource type="AudioStream" uid="uid://5iqc5o8p02l5" path="res://ships/audio/THRUSTER LOW.wav" id="11_5uksh"] [ext_resource type="PackedScene" uid="uid://dbc2usdmy5wf3" path="res://fx/engine_glow/engine_glow.tscn" id="12_8a1b6"] [ext_resource type="Shader" path="res://fx/engine_glow/engine_glow.gdshader" id="13_0qykh"] +[ext_resource type="Script" path="res://mechanics/heat/radiator.gd" id="18_jmrpj"] [sub_resource type="Resource" id="Resource_t05wf"] resource_local_to_scene = true @@ -38,6 +40,12 @@ script = ExtResource("8_w8qvs") max_power = 300.0 power = 300.0 +[sub_resource type="Resource" id="Resource_10qq0"] +resource_local_to_scene = true +script = ExtResource("5_0dh7p") +max_heat = 400.0 +heat = 0.0 + [sub_resource type="CylinderShape3D" id="CylinderShape3D_23xxj"] height = 3.88505 radius = 0.973661 @@ -90,12 +98,14 @@ orientation = 1 script = ExtResource("9_277l5") rate_of_power = 3.0 -[node name="Freighter" node_paths=PackedStringArray("shield_recharger") instance=ExtResource("1_r6j4w")] +[node name="Freighter" node_paths=PackedStringArray("radiator", "shield_recharger") instance=ExtResource("1_r6j4w")] mass = 150.0 +radiator = NodePath("Radiator") shield_recharger = NodePath("ShieldRecharger") hull = SubResource("Resource_t05wf") shield = SubResource("Resource_ln8ln") battery = SubResource("Resource_lo26u") +heat_sink = SubResource("Resource_10qq0") [node name="Model" parent="." index="0" instance=ExtResource("2_qliud")] transform = Transform3D(-1, 3.48787e-16, -8.74228e-08, 3.48787e-16, 1, -3.48787e-16, 8.74228e-08, -3.48787e-16, -1, 0, 0, 0) @@ -153,4 +163,8 @@ power_generator = SubResource("Resource_ku887") [node name="ShieldRecharger" type="Node3D" parent="." index="7"] script = ExtResource("5_s17ip") +[node name="Radiator" type="Node3D" parent="." index="8"] +script = ExtResource("18_jmrpj") +rate = 6.0 + [editable path="CombatObject/TargetOverlay"] diff --git a/ships/frigate03/frigate03.tscn b/ships/frigate03/frigate03.tscn index 270e2e8d..ae91666c 100644 --- a/ships/frigate03/frigate03.tscn +++ b/ships/frigate03/frigate03.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=32 format=3 uid="uid://cdvbol3xj7jr5"] +[gd_scene load_steps=35 format=3 uid="uid://cdvbol3xj7jr5"] [ext_resource type="PackedScene" uid="uid://c0eitctnmmfyq" path="res://ships/ship.tscn" id="1_w0piq"] [ext_resource type="PackedScene" uid="uid://cdyo800b83x5i" path="res://fx/explosions/explosion002.tscn" id="2_xcc1t"] @@ -6,6 +6,7 @@ [ext_resource type="PackedScene" uid="uid://gcf8fo4e36c4" path="res://ships/frigate03/target_view.tscn" id="3_bcien"] [ext_resource type="Script" path="res://mechanics/combat/hull.gd" id="4_6j23n"] [ext_resource type="AudioStream" uid="uid://5iqc5o8p02l5" path="res://ships/audio/THRUSTER LOW.wav" id="4_xrdjv"] +[ext_resource type="Script" path="res://mechanics/heat/heat_sink.gd" id="5_e20uk"] [ext_resource type="ArrayMesh" uid="uid://c2y60nf8m25ka" path="res://ships/frigate03/frigate03_mesh.tres" id="6_g7bx0"] [ext_resource type="Script" path="res://mechanics/physics/spin_thruster.gd" id="8_74gsh"] [ext_resource type="PackedScene" uid="uid://dbc2usdmy5wf3" path="res://fx/engine_glow/engine_glow.tscn" id="8_ibdmx"] @@ -18,6 +19,7 @@ [ext_resource type="Script" path="res://mechanics/combat/shield_recharger.gd" id="15_ik8m4"] [ext_resource type="Script" path="res://mechanics/combat/weapons/weapon_mount.gd" id="16_xra8r"] [ext_resource type="Resource" uid="uid://cw1tu3qdxdgfi" path="res://mechanics/combat/weapons/blaster/blaster.tres" id="17_h1u5w"] +[ext_resource type="Script" path="res://mechanics/heat/radiator.gd" id="20_0bm6k"] [sub_resource type="Resource" id="Resource_am8dk"] resource_local_to_scene = true @@ -40,6 +42,12 @@ script = ExtResource("9_7c238") max_power = 300.0 power = 300.0 +[sub_resource type="Resource" id="Resource_kynkv"] +resource_local_to_scene = true +script = ExtResource("5_e20uk") +max_heat = 200.0 +heat = 0.0 + [sub_resource type="BoxShape3D" id="BoxShape3D_ou7uu"] size = Vector3(1.98299, 0.832642, 1.04932) @@ -91,13 +99,15 @@ orientation = 1 script = ExtResource("14_ccaul") rate_of_power = 2.0 -[node name="Frigate" node_paths=PackedStringArray("shield_recharger", "weapon_mounts") instance=ExtResource("1_w0piq")] +[node name="Frigate" node_paths=PackedStringArray("radiator", "shield_recharger", "weapon_mounts") instance=ExtResource("1_w0piq")] mass = 100.0 +radiator = NodePath("Radiator") shield_recharger = NodePath("ShieldRecharger") weapon_mounts = [NodePath("Blaster")] hull = SubResource("Resource_am8dk") shield = SubResource("Resource_rw3nb") battery = SubResource("Resource_p601o") +heat_sink = SubResource("Resource_kynkv") [node name="MeshInstance3D" type="MeshInstance3D" parent="." index="0"] transform = Transform3D(-0.4, 1.39515e-16, 3.49691e-08, 1.39515e-16, 0.4, -1.39515e-16, -3.49691e-08, -1.39515e-16, -0.4, 1.40849e-16, -1.40849e-16, -0.199324) @@ -153,4 +163,8 @@ transform = Transform3D(1, -1.21652e-31, 0, -1.21652e-31, 1, 0, 0, 0, 1, 3.78906 script = ExtResource("16_xra8r") weapon = ExtResource("17_h1u5w") +[node name="Radiator" type="Node3D" parent="." index="9"] +script = ExtResource("20_0bm6k") +rate = 5.0 + [editable path="CombatObject/TargetOverlay"] From 3f5f398da8b089e9e69c462f6e18ddcabed7ffe4 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 19:38:45 +0100 Subject: [PATCH 05/17] Add `Player.heat_changed` signal --- actors/player.gd | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/actors/player.gd b/actors/player.gd index 9e06ec5d..0cae86e0 100644 --- a/actors/player.gd +++ b/actors/player.gd @@ -26,6 +26,9 @@ signal shield_changed(player: Player, shield: Shield) ## Fires when the ship's power level changes. signal power_changed(player: Player, battery: Battery) +## Fires when the ship's heat level changes. +signal heat_changed(player: Player, heat_sink: HeatSink) + ## Fires when the player's ship is destroyed. signal ship_destroyed(player: Player) @@ -107,6 +110,7 @@ func _ready() -> void: self.ship.hull.changed.connect(_on_hull_changed) self.ship.hull.hull_destroyed.connect(_on_hull_destroyed) self.ship.battery.changed.connect(_on_power_changed) + self.ship.heat_sink.changed.connect(_on_heat_changed) self.ship.targeting_system.target_changed.connect(_on_target_changed) InputEventBroadcaster.input_event.connect(_on_broadcasted_input_event) @@ -114,6 +118,7 @@ func _ready() -> void: # Initial notifications so the UI can update. self._on_hull_changed() self._on_power_changed() + self._on_heat_changed() if self.ship.shield: self.ship.shield.changed.connect(_on_shield_changed) @@ -145,6 +150,9 @@ func _on_shield_changed() -> void: func _on_power_changed() -> void: self.power_changed.emit(self, self.ship.battery) +func _on_heat_changed() -> void: + self.heat_changed.emit(self, self.ship.heat_sink) + func _on_hull_destroyed(hull: Hull) -> void: assert(hull == self.ship.hull, "Received hull_destroyed signal from incorrect hull") self.ship_destroyed.emit(self) From 9f28fccc54864afdf37fb1f45efb6bf9d2374f97 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 19:50:21 +0100 Subject: [PATCH 06/17] Disable any ship's controls when overheated --- actors/ai/ai_navigation.gd | 32 +++++++++++++++++--------------- actors/ai/archetypes/pirate.gd | 3 +++ actors/player.gd | 4 ++-- mechanics/heat/heat_sink.gd | 4 ++-- ships/ship.gd | 10 ++++++++++ 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/actors/ai/ai_navigation.gd b/actors/ai/ai_navigation.gd index f360eaed..fb485965 100644 --- a/actors/ai/ai_navigation.gd +++ b/actors/ai/ai_navigation.gd @@ -1,7 +1,9 @@ extends Node3D class_name AINavigation -## Automatically navigates a [RigidBody3D] to a particular position using a [RigidBodyThruster] and a [RigidBodyDirection]. +## Automatically navigates a [Ship] to a particular position using a [RigidBodyThruster] and a [RigidBodyDirection]. +## +## [b]This script expects the parent node to be a [Ship].[/b] @export var rigid_body_thruster: RigidBodyThruster @export var rigid_body_direction: RigidBodyDirection @@ -43,7 +45,7 @@ var navigating: bool: else: self._state = State.IDLE -@onready var _rigid_body := rigid_body_thruster.get_parent() as RigidBody3D +@onready var _ship := get_parent() as Ship var _state: State = State.IDLE var _target_direction: Vector3 @@ -56,7 +58,7 @@ func _ready() -> void: self.navigating = true func _physics_process(_delta: float) -> void: - if not self.navigating: + if not self.navigating or self._ship.controls_disabled(): return match self._state: @@ -76,7 +78,7 @@ func _idle() -> void: self.rigid_body_thruster.throttle = 0.0 func _rotate_to_accelerate() -> void: - self._target_direction = (self.destination - self._rigid_body.global_position).normalized() + self._target_direction = (self.destination - self._ship.global_position).normalized() self.rigid_body_direction.direction = self._target_direction self.rigid_body_thruster.throttle = 0.0 @@ -86,19 +88,19 @@ func _rotate_to_accelerate() -> void: func _accelerate_toward_destination() -> void: self.rigid_body_thruster.throttle = 1.0 - var distance_to_destination := self._rigid_body.global_position.distance_to(self.destination) - var stopping_distance := self._calculate_stopping_distance(self._rigid_body.linear_velocity.length()) + var distance_to_destination := self._ship.global_position.distance_to(self.destination) + var stopping_distance := self._calculate_stopping_distance(self._ship.linear_velocity.length()) # Account for rotation time in stopping distance - var rotation_time := self._estimate_rotation_time(-self._rigid_body.linear_velocity.normalized()) - var rotation_distance := self._rigid_body.linear_velocity.length() * rotation_time + var rotation_time := self._estimate_rotation_time(-self._ship.linear_velocity.normalized()) + var rotation_distance := self._ship.linear_velocity.length() * rotation_time stopping_distance += rotation_distance if stopping_distance >= distance_to_destination: self._state = State.ROTATING_TO_DECELERATE func _rotate_to_decelerate() -> void: - self._target_direction = -self._rigid_body.linear_velocity.normalized() + self._target_direction = -self._ship.linear_velocity.normalized() self.rigid_body_direction.direction = self._target_direction self.rigid_body_thruster.throttle = 0.0 @@ -106,7 +108,7 @@ func _rotate_to_decelerate() -> void: self._state = State.DECELERATING_TO_STOP func _decelerate_to_stop() -> void: - self._target_direction = -self._rigid_body.linear_velocity.normalized() + self._target_direction = -self._ship.linear_velocity.normalized() self.rigid_body_direction.direction = self._target_direction if self._pointing_in_direction(self._target_direction): @@ -114,8 +116,8 @@ func _decelerate_to_stop() -> void: else: self.rigid_body_thruster.throttle = 0.0 - var distance_to_destination := self._rigid_body.global_position.distance_to(self.destination) - if distance_to_destination <= self.arrival_distance_tolerance and self._rigid_body.linear_velocity.length() <= self.stopping_velocity_tolerance: + var distance_to_destination := self._ship.global_position.distance_to(self.destination) + if distance_to_destination <= self.arrival_distance_tolerance and self._ship.linear_velocity.length() <= self.stopping_velocity_tolerance: self.navigating = false self.rigid_body_thruster.throttle = 0.0 @@ -123,15 +125,15 @@ func _decelerate_to_stop() -> void: self.destination_reached.emit(self) func _pointing_in_direction(direction: Vector3) -> bool: - var current_direction := -self._rigid_body.global_transform.basis.z + var current_direction := -self._ship.global_transform.basis.z return current_direction.angle_to(direction) <= self.direction_tolerance func _calculate_stopping_distance(current_velocity: float) -> float: - var acceleration := self.rigid_body_thruster.thruster.thrust_force / self._rigid_body.mass + var acceleration := self.rigid_body_thruster.thruster.thrust_force / self._ship.mass return (current_velocity * current_velocity) / (2 * acceleration) func _estimate_rotation_time(target_direction: Vector3) -> float: - var current_direction := -self._rigid_body.global_transform.basis.z + var current_direction := -self._ship.global_transform.basis.z var angle_to_rotate := current_direction.angle_to(target_direction) return angle_to_rotate / self.rigid_body_direction.spin_thruster.turning_rate diff --git a/actors/ai/archetypes/pirate.gd b/actors/ai/archetypes/pirate.gd index 063a77d3..e13dd294 100644 --- a/actors/ai/archetypes/pirate.gd +++ b/actors/ai/archetypes/pirate.gd @@ -59,6 +59,9 @@ func _select_new_patrol_target() -> void: self._patrol_target = MathUtils.random_unit_vector() * self.patrol_radius func _physics_process(delta: float) -> void: + if self._ship.controls_disabled(): + return + if not self._ship.targeting_system.target: self._current_state = State.PATROL diff --git a/actors/player.gd b/actors/player.gd index 0cae86e0..3a9269e0 100644 --- a/actors/player.gd +++ b/actors/player.gd @@ -214,7 +214,7 @@ func _closest_landing_target() -> Celestial: return nearest_celestial func _unhandled_input(event: InputEvent) -> void: - if self.ship.hyperdrive_system.jumping: + if self.ship.controls_disabled(): return var motion_event := event as InputEventMouseMotion @@ -366,7 +366,7 @@ func _mouse_joystick_input() -> Vector2: return offset.normalized() * normalized_distance func _physics_process(_delta: float) -> void: - if not self.ship.hyperdrive_system or self.ship.hyperdrive_system.jumping: + if self.ship.controls_disabled(): return if Input.is_action_pressed("jump"): diff --git a/mechanics/heat/heat_sink.gd b/mechanics/heat/heat_sink.gd index 3ed48040..3e72f45b 100644 --- a/mechanics/heat/heat_sink.gd +++ b/mechanics/heat/heat_sink.gd @@ -3,7 +3,7 @@ class_name HeatSink ## Accumulates heat that is generated by ship functions and inflicted in combat. ## -## When heat exceeds the maximum capacity of the heat sink, the ship becomes disabled. +## When heat exceeds the maximum capacity of the heat sink, the ship's controls become inoperable. ## The maximum heat capacity for this sink. @export var max_heat: float: @@ -17,7 +17,7 @@ class_name HeatSink ## The current heat level. ## -## Unlike other, similar mechanics, this value can exceed [member max_heat], at which point the ship is disabled. +## Unlike other, similar mechanics, this value can exceed [member max_heat], at which point the ship controls are disabled. @export var heat: float: set(value): if is_equal_approx(heat, value): diff --git a/ships/ship.gd b/ships/ship.gd index 2fa16f50..219eae14 100644 --- a/ships/ship.gd +++ b/ships/ship.gd @@ -116,6 +116,16 @@ func _ready() -> void: func _to_string() -> String: return "Ship:%s (%s)" % [self.name, self.combat_object] +## Whether this ship's controls should be disabled. +func controls_disabled() -> bool: + if self.heat_sink.heat >= self.heat_sink.max_heat: + return true + + if self.hyperdrive_system and self.hyperdrive_system.jumping: + return true + + return false + ## Add an outfit to the ship and apply its effects. func add_outfit(outfit: Outfit) -> void: outfit.apply_to_ship(self) From 2e4445db60866481322212ed5b359141ee6506e7 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 19:56:48 +0100 Subject: [PATCH 07/17] Heat bar in UI --- screens/game/game.tscn | 45 ++++++++++++++++++++++++++++--- screens/game/hud/player_vitals.gd | 5 ++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/screens/game/game.tscn b/screens/game/game.tscn index 8d65bd9c..f2f4679e 100644 --- a/screens/game/game.tscn +++ b/screens/game/game.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=77 format=3 uid="uid://sunhu71swcs2"] +[gd_scene load_steps=80 format=3 uid="uid://sunhu71swcs2"] [ext_resource type="Environment" uid="uid://b7t3opwr35xen" path="res://fx/environment.tres" id="1_pqled"] [ext_resource type="Script" path="res://mechanics/hyperspace/hyperspace_scene_switcher.gd" id="4_yyrkm"] +[ext_resource type="Script" path="res://mechanics/heat/heat_sink.gd" id="6_hv4l5"] [ext_resource type="Material" uid="uid://tpd4rufhhe4h" path="res://fx/starfield/starfield.tres" id="7_gr6ce"] [ext_resource type="Script" path="res://mechanics/economy/passenger_quarters.gd" id="8_bkgwh"] [ext_resource type="Script" path="res://fx/starfield/starfield_parallax.gd" id="8_ueist"] @@ -78,6 +79,12 @@ script = ExtResource("15_sjw8q") max_power = 300.0 power = 300.0 +[sub_resource type="Resource" id="Resource_dr1mv"] +resource_local_to_scene = true +script = ExtResource("6_hv4l5") +max_heat = 400.0 +heat = 0.0 + [sub_resource type="Resource" id="Resource_rcbfw"] resource_local_to_scene = true script = ExtResource("14_bcf1o") @@ -99,6 +106,12 @@ script = ExtResource("15_sjw8q") max_power = 100.0 power = 100.0 +[sub_resource type="Resource" id="Resource_s186x"] +resource_local_to_scene = true +script = ExtResource("6_hv4l5") +max_heat = 100.0 +heat = 0.0 + [sub_resource type="Resource" id="Resource_on6n3"] script = ExtResource("11_ag0i7") max_volume = 10.0 @@ -182,6 +195,13 @@ message_log = NodePath("../InGameGUI/MarginContainer/HBoxContainer/MessageLog") hull = SubResource("Resource_p7sh0") shield = SubResource("Resource_dhynb") battery = SubResource("Resource_ubt7x") +heat_sink = SubResource("Resource_dr1mv") + +[node name="AINavigation" parent="HyperspaceSceneSwitcher/Sol/Freighter" index="8"] +direction_tolerance = null +arrival_distance_tolerance = null +stopping_velocity_tolerance = null +auto_start = null [node name="PlayerCorvette" parent="HyperspaceSceneSwitcher/Sol" node_paths=PackedStringArray("hyperdrive_system") instance=ExtResource("12_bj83b")] physics_material_override = null @@ -189,6 +209,7 @@ hyperdrive_system = NodePath("HyperdriveSystem") hull = SubResource("Resource_rcbfw") shield = SubResource("Resource_7husa") battery = SubResource("Resource_i5r8g") +heat_sink = SubResource("Resource_s186x") cargo_hold = SubResource("Resource_on6n3") passenger_quarters = SubResource("Resource_ksma2") hyperdrive = SubResource("Resource_un4md") @@ -230,6 +251,9 @@ message_log = NodePath("../../../../../InGameGUI/MarginContainer/HBoxContainer/M script = ExtResource("15_cfr6f") rigid_body_thruster = NodePath("../RigidBodyThruster") rigid_body_direction = NodePath("../RigidBodyDirection") +direction_tolerance = null +destination = null +arrival_distance_tolerance = null stopping_velocity_tolerance = 0.5 auto_start = false @@ -362,6 +386,8 @@ mouse_filter = 2 [node name="MinimapContainer" type="PanelContainer" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar"] custom_minimum_size = Vector2(100, 100) layout_mode = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 mouse_filter = 2 theme_override_styles/panel = SubResource("StyleBoxTexture_7gqif") @@ -465,15 +491,16 @@ theme_override_font_sizes/font_size = 10 text = "Ship systems" uppercase = true -[node name="PlayerVitals" type="GridContainer" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer" node_paths=PackedStringArray("hull_bar", "shield_bar", "power_bar")] +[node name="PlayerVitals" type="GridContainer" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer" node_paths=PackedStringArray("hull_bar", "shield_bar", "power_bar", "heat_bar")] layout_mode = 2 size_flags_horizontal = 4 -theme_override_constants/h_separation = 16 -columns = 3 +theme_override_constants/h_separation = 8 +columns = 4 script = ExtResource("27_mar8l") hull_bar = NodePath("HullBar") shield_bar = NodePath("ShieldBar") power_bar = NodePath("PowerBar") +heat_bar = NodePath("HeatBar") [node name="HullLabel" type="Label" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer/PlayerVitals"] layout_mode = 2 @@ -493,6 +520,12 @@ theme_type_variation = &"HUDLabel" text = "PWR" horizontal_alignment = 1 +[node name="HeatLabel" type="Label" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer/PlayerVitals"] +layout_mode = 2 +theme_type_variation = &"HUDLabel" +text = "HEAT" +horizontal_alignment = 1 + [node name="HullBar" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer/PlayerVitals" instance=ExtResource("28_7l7fi")] layout_mode = 2 @@ -502,6 +535,9 @@ layout_mode = 2 [node name="PowerBar" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer/PlayerVitals" instance=ExtResource("28_7l7fi")] layout_mode = 2 +[node name="HeatBar" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer/PlayerVitals" instance=ExtResource("28_7l7fi")] +layout_mode = 2 + [node name="TargetInfoContainer" type="PanelContainer" parent="InGameGUI/MarginContainer/HBoxContainer/Sidebar" node_paths=PackedStringArray("target_label", "target_viewport", "hull_bar", "shield_bar", "pick_sound")] custom_minimum_size = Vector2(200, 194) layout_mode = 2 @@ -670,6 +706,7 @@ script = ExtResource("37_e11x7") [connection signal="jump_destination_loaded" from="HyperspaceSceneSwitcher" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/SystemName" method="_on_jump_destination_loaded"] [connection signal="jump_path_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/HyperdriveSystem" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PanelContainer/VBoxContainer/JumpDestinationName" method="_on_jump_path_changed"] [connection signal="jumping_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/HyperdriveSystem" to="MainCameraTransform/MainCamera/HyperspaceEffect" method="_on_jumping_changed"] +[connection signal="heat_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/Player" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer/PlayerVitals" method="_on_player_heat_changed"] [connection signal="hull_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/Player" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer/PlayerVitals" method="_on_player_hull_changed"] [connection signal="hyperdrive_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/Player" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PanelContainer/VBoxContainer/FuelBar" method="_on_player_hyperdrive_changed"] [connection signal="landing_target_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/Player" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/LandingTargetName" method="_on_landing_target_changed"] diff --git a/screens/game/hud/player_vitals.gd b/screens/game/hud/player_vitals.gd index 60f3bc76..dc2a55e8 100644 --- a/screens/game/hud/player_vitals.gd +++ b/screens/game/hud/player_vitals.gd @@ -3,6 +3,7 @@ extends GridContainer @export var hull_bar: VitalsFillBar @export var shield_bar: VitalsFillBar @export var power_bar: VitalsFillBar +@export var heat_bar: VitalsFillBar func _on_player_hull_changed(_player: Player, hull: Hull) -> void: self.hull_bar.max_value = hull.max_integrity @@ -15,3 +16,7 @@ func _on_player_shield_changed(_player: Player, shield: Shield) -> void: func _on_player_power_changed(_player: Player, battery: Battery) -> void: self.power_bar.max_value = maxf(1.0, battery.max_power) self.power_bar.value = battery.power + +func _on_player_heat_changed(_player: Player, heat_sink: HeatSink) -> void: + self.heat_bar.max_value = heat_sink.max_heat + self.heat_bar.value = heat_sink.heat From cbe79f00be2f610b93fdc585464c9ab9cb1b79aa Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:02:54 +0100 Subject: [PATCH 08/17] Fix player firing continuing after overheating --- actors/ai/archetypes/pirate.gd | 15 ++++++--------- actors/player.gd | 5 ++--- ships/ship.gd | 6 ++++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/actors/ai/archetypes/pirate.gd b/actors/ai/archetypes/pirate.gd index e13dd294..767806fe 100644 --- a/actors/ai/archetypes/pirate.gd +++ b/actors/ai/archetypes/pirate.gd @@ -60,6 +60,7 @@ func _select_new_patrol_target() -> void: func _physics_process(delta: float) -> void: if self._ship.controls_disabled(): + self._ship.set_firing(false) return if not self._ship.targeting_system.target: @@ -88,7 +89,7 @@ func _pointing_in_direction(direction: Vector3) -> bool: return current_direction.angle_to(direction) <= self.direction_tolerance func _patrol_behavior(_delta: float) -> void: - self._set_firing(false) + self._ship.set_firing(false) var target := self._find_closest_target() self._ship.targeting_system.target = target @@ -108,12 +109,12 @@ func _patrol_behavior(_delta: float) -> void: func _engage_behavior(_delta: float) -> void: var target := self._ship.targeting_system.target if not target: - self._set_firing(false) + self._ship.set_firing(false) self._current_state = State.PATROL return if not self._pointing_in_direction(self._desired_direction()): - self._set_firing(false) + self._ship.set_firing(false) self._ship.rigid_body_thruster.throttle = 0.0 return @@ -130,10 +131,10 @@ func _engage_behavior(_delta: float) -> void: else: self._ship.rigid_body_thruster.throttle = 0.0 - self._set_firing(distance <= self.fire_range) + self._ship.set_firing(distance <= self.fire_range) func _retreat_behavior(_delta: float) -> void: - self._set_firing(false) + self._ship.set_firing(false) var target := self._ship.targeting_system.target if not target: @@ -149,10 +150,6 @@ func _retreat_behavior(_delta: float) -> void: if distance >= self.preferred_distance: self._current_state = State.ENGAGE -func _set_firing(firing: bool) -> void: - for weapon_mount in self._ship.weapon_mounts: - weapon_mount.firing = firing - func _find_closest_target() -> CombatObject: var available_targets := self._ship.targeting_system.get_available_targets() available_targets.erase(self._ship.combat_object) diff --git a/actors/player.gd b/actors/player.gd index 3a9269e0..fa922d96 100644 --- a/actors/player.gd +++ b/actors/player.gd @@ -367,15 +367,14 @@ func _mouse_joystick_input() -> Vector2: func _physics_process(_delta: float) -> void: if self.ship.controls_disabled(): + self.ship.set_firing(false) return if Input.is_action_pressed("jump"): self._jump_to_hyperspace() return - var firing := Input.is_action_pressed("fire") - for weapon_mount in self.ship.weapon_mounts: - weapon_mount.firing = firing + self.ship.set_firing(Input.is_action_pressed("fire")) match UserPreferences.control_scheme: UserPreferences.ControlScheme.RELATIVE: diff --git a/ships/ship.gd b/ships/ship.gd index 219eae14..e3ed7f85 100644 --- a/ships/ship.gd +++ b/ships/ship.gd @@ -97,6 +97,7 @@ func _ready() -> void: self.rigid_body_thruster.battery = self.battery self.rigid_body_direction.battery = self.battery self.power_management_unit.battery = self.battery + self.power_management_unit.heat_sink = self.heat_sink self.radiator.heat_sink = self.heat_sink if self.shield_recharger: @@ -126,6 +127,11 @@ func controls_disabled() -> bool: return false +## Starts or stops firing on all weapon mounts. +func set_firing(firing: bool) -> void: + for weapon_mount in self.weapon_mounts: + weapon_mount.firing = firing + ## Add an outfit to the ship and apply its effects. func add_outfit(outfit: Outfit) -> void: outfit.apply_to_ship(self) From 9d0851ac4f08cde788af6864bd6fedf82cde758c Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:03:10 +0100 Subject: [PATCH 09/17] Generate heat from power generators --- mechanics/power/power_generator.gd | 10 ++++++++++ mechanics/power/power_management_unit.gd | 11 ++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/mechanics/power/power_generator.gd b/mechanics/power/power_generator.gd index b60ba346..aa883c86 100644 --- a/mechanics/power/power_generator.gd +++ b/mechanics/power/power_generator.gd @@ -12,3 +12,13 @@ class_name PowerGenerator rate_of_power = value self.emit_changed() + +## How much heat this generator produces per second. +@export var rate_of_heat: float: + set(value): + assert(value >= 0.0, "Heat generation rate must be non-negative") + if is_equal_approx(rate_of_heat, value): + return + + rate_of_heat = value + self.emit_changed() diff --git a/mechanics/power/power_management_unit.gd b/mechanics/power/power_management_unit.gd index 0b33d937..8ae6789f 100644 --- a/mechanics/power/power_management_unit.gd +++ b/mechanics/power/power_management_unit.gd @@ -7,13 +7,14 @@ class_name PowerManagementUnit @export var power_generator: PowerGenerator: set(value): power_generator = value - self.set_physics_process(self.battery != null and power_generator != null) + self.set_physics_process(power_generator != null) ## A battery storing power. -var battery: Battery: - set(value): - battery = value - self.set_physics_process(battery != null and self.power_generator != null) +var battery: Battery + +## A sink for absorbing heat. +var heat_sink: HeatSink func _physics_process(delta: float) -> void: self.battery.recharge(self.power_generator.rate_of_power * delta) + self.heat_sink.heat += self.power_generator.rate_of_heat * delta From 860f0d490ba34a974795dd13ff27bf372c81fbf6 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:04:15 +0100 Subject: [PATCH 10/17] Generate heat when firing weapons --- mechanics/combat/weapons/weapon.gd | 3 +++ mechanics/combat/weapons/weapon_mount.gd | 4 ++++ ships/ship.gd | 1 + 3 files changed, 8 insertions(+) diff --git a/mechanics/combat/weapons/weapon.gd b/mechanics/combat/weapons/weapon.gd index 9de13add..8475de1e 100644 --- a/mechanics/combat/weapons/weapon.gd +++ b/mechanics/combat/weapons/weapon.gd @@ -14,5 +14,8 @@ class_name Weapon ## If the containing ship's available power is less than this amount, the weapon won't be able to fire. @export var power_consumption: float +## The amount of heat generated when firing the weapon. +@export var heat: float + ## The projectile that this weapon fires. The root node [b]must[/b] be a [RigidBody3D]. @export var projectile: PackedScene diff --git a/mechanics/combat/weapons/weapon_mount.gd b/mechanics/combat/weapons/weapon_mount.gd index eda6e6bd..42791a0f 100644 --- a/mechanics/combat/weapons/weapon_mount.gd +++ b/mechanics/combat/weapons/weapon_mount.gd @@ -22,6 +22,9 @@ class_name WeaponMount ## The [Battery] to power the weapon from. var battery: Battery +## The [HeatSink] to dump heat into. +var heat_sink: HeatSink + ## Set to true when this weapon should automatically fire; set to false to stop firing. var firing: bool = false: set(value): @@ -67,3 +70,4 @@ func _physics_process(_delta: float) -> void: projectile_instance.apply_central_impulse(projectile_instance.transform.basis * self.weapon.fire_force * Vector3.FORWARD) self._last_fired_usec = now + self.heat_sink.heat += self.weapon.heat diff --git a/ships/ship.gd b/ships/ship.gd index e3ed7f85..1d8f7882 100644 --- a/ships/ship.gd +++ b/ships/ship.gd @@ -109,6 +109,7 @@ func _ready() -> void: for weapon_mount in self.weapon_mounts: weapon_mount.battery = self.battery + weapon_mount.heat_sink = self.heat_sink if self.rigid_body_cargo: self.rigid_body_cargo.cargo_hold = self.cargo_hold From 01f33e907c77e4236d889c7177a7dd7dbfa16393 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:06:38 +0100 Subject: [PATCH 11/17] Generate heat when thrusting --- mechanics/physics/rigid_body_thruster.gd | 5 +++++ mechanics/physics/thruster.gd | 3 +++ ships/ship.gd | 1 + 3 files changed, 9 insertions(+) diff --git a/mechanics/physics/rigid_body_thruster.gd b/mechanics/physics/rigid_body_thruster.gd index 1ec9e6d7..1a945af6 100644 --- a/mechanics/physics/rigid_body_thruster.gd +++ b/mechanics/physics/rigid_body_thruster.gd @@ -23,6 +23,9 @@ class_name RigidBodyThruster ## The [Battery] to power the thruster from. var battery: Battery +## The [HeatSink] to dump heat to. +var heat_sink: HeatSink + ## The current level of throttle (where 1.0 is full throttle), which corresponds to the magnitude of the thrust to apply, as well as the amount of power to be consumed. var throttle: float: set(value): @@ -75,6 +78,8 @@ func _physics_process(delta: float) -> void: var desired_power := self.thruster.power_consumption_rate * self.throttle * delta var power_consumed := self.battery.consume_up_to(desired_power) var magnitude := self.throttle * (power_consumed / desired_power) + + self.heat_sink.heat += self.thruster.heat_generation_rate * magnitude * delta self._animate_transparency(1.0 - magnitude) self._rigid_body.apply_central_force(self._rigid_body.transform.basis * Vector3.FORWARD * self.thruster.thrust_force * magnitude) diff --git a/mechanics/physics/thruster.gd b/mechanics/physics/thruster.gd index 08361124..8887e1c9 100644 --- a/mechanics/physics/thruster.gd +++ b/mechanics/physics/thruster.gd @@ -8,3 +8,6 @@ class_name Thruster ## How much power the thruster consumes per second when thrusting at full power. @export var power_consumption_rate: float + +## How much heat the thruster generates per second when thrusting at full power. +@export var heat_generation_rate: float diff --git a/ships/ship.gd b/ships/ship.gd index 1d8f7882..f364ce5c 100644 --- a/ships/ship.gd +++ b/ships/ship.gd @@ -95,6 +95,7 @@ func _ready() -> void: self.hero.killed.emit(self.hero)) self.rigid_body_thruster.battery = self.battery + self.rigid_body_thruster.heat_sink = self.heat_sink self.rigid_body_direction.battery = self.battery self.power_management_unit.battery = self.battery self.power_management_unit.heat_sink = self.heat_sink From 44666dd354048b5d212439518de5f8024c92056c Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:13:50 +0100 Subject: [PATCH 12/17] Add some heat values to various components --- mechanics/combat/weapons/blaster/blaster.tres | 1 + mechanics/outfitting/outfits/blaster.tres | 2 ++ ships/corvette01/corvette01.tscn | 4 +++- ships/freighter/freighter.tscn | 2 ++ ships/frigate03/frigate03.tscn | 4 +++- 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mechanics/combat/weapons/blaster/blaster.tres b/mechanics/combat/weapons/blaster/blaster.tres index 0e9225b8..8a696c2e 100644 --- a/mechanics/combat/weapons/blaster/blaster.tres +++ b/mechanics/combat/weapons/blaster/blaster.tres @@ -8,4 +8,5 @@ script = ExtResource("1_h0068") fire_interval = 0.2 fire_force = 2.0 power_consumption = 5.0 +heat = 10.0 projectile = ExtResource("1_upvwn") diff --git a/mechanics/outfitting/outfits/blaster.tres b/mechanics/outfitting/outfits/blaster.tres index 26876a67..997dd055 100644 --- a/mechanics/outfitting/outfits/blaster.tres +++ b/mechanics/outfitting/outfits/blaster.tres @@ -10,7 +10,9 @@ description = "Commonly installed by traders heading into more dangerous reaches mass = 2.0 price_in_credits = 12000.0 modified_cargo_capacity = 0.0 +modified_passenger_capacity = 0 modified_fuel_capacity = 0.0 +modified_hull_capacity = 0.0 modified_shield_capacity = 0.0 shield_recharge_multiplier = 1.0 modified_power_generation = -1.0 diff --git a/ships/corvette01/corvette01.tscn b/ships/corvette01/corvette01.tscn index 65708761..3beca2e5 100644 --- a/ships/corvette01/corvette01.tscn +++ b/ships/corvette01/corvette01.tscn @@ -84,10 +84,12 @@ power_consumption_rate = 5.0 script = ExtResource("10_ffov7") thrust_force = 200.0 power_consumption_rate = 8.0 +heat_generation_rate = 2.0 [sub_resource type="Resource" id="Resource_csuav"] script = ExtResource("13_n5lfa") rate_of_power = 5.0 +rate_of_heat = 1.0 [node name="Corvette" node_paths=PackedStringArray("radiator", "shield_recharger", "weapon_mounts", "rigid_body_cargo") instance=ExtResource("1_cmgif")] mass = 10.0 @@ -172,6 +174,6 @@ fire_offset = 0.5 [node name="Radiator" type="Node3D" parent="." index="13"] script = ExtResource("22_o7v2x") -rate = 3.0 +rate = 4.0 [editable path="CombatObject/TargetOverlay"] diff --git a/ships/freighter/freighter.tscn b/ships/freighter/freighter.tscn index f8968804..eaf8f40c 100644 --- a/ships/freighter/freighter.tscn +++ b/ships/freighter/freighter.tscn @@ -82,6 +82,7 @@ power_consumption_rate = 5.0 script = ExtResource("10_8eiax") thrust_force = 60.0 power_consumption_rate = 5.0 +heat_generation_rate = 5.0 [sub_resource type="ShaderMaterial" id="ShaderMaterial_jl6dq"] render_priority = 0 @@ -97,6 +98,7 @@ orientation = 1 [sub_resource type="Resource" id="Resource_ku887"] script = ExtResource("9_277l5") rate_of_power = 3.0 +rate_of_heat = 1.0 [node name="Freighter" node_paths=PackedStringArray("radiator", "shield_recharger") instance=ExtResource("1_r6j4w")] mass = 150.0 diff --git a/ships/frigate03/frigate03.tscn b/ships/frigate03/frigate03.tscn index ae91666c..1582d091 100644 --- a/ships/frigate03/frigate03.tscn +++ b/ships/frigate03/frigate03.tscn @@ -83,6 +83,7 @@ power_consumption_rate = 5.0 script = ExtResource("10_6f48k") thrust_force = 100.0 power_consumption_rate = 5.0 +heat_generation_rate = 3.0 [sub_resource type="ShaderMaterial" id="ShaderMaterial_rurkt"] render_priority = 0 @@ -98,6 +99,7 @@ orientation = 1 [sub_resource type="Resource" id="Resource_0m3cu"] script = ExtResource("14_ccaul") rate_of_power = 2.0 +rate_of_heat = 1.0 [node name="Frigate" node_paths=PackedStringArray("radiator", "shield_recharger", "weapon_mounts") instance=ExtResource("1_w0piq")] mass = 100.0 @@ -165,6 +167,6 @@ weapon = ExtResource("17_h1u5w") [node name="Radiator" type="Node3D" parent="." index="9"] script = ExtResource("20_0bm6k") -rate = 5.0 +rate = 8.0 [editable path="CombatObject/TargetOverlay"] From b57e684d7cb4e55a3caf952c9788639fe7974f39 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:16:32 +0100 Subject: [PATCH 13/17] Zero out manuevering when controls are disabled --- actors/player.gd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/actors/player.gd b/actors/player.gd index fa922d96..b287b03b 100644 --- a/actors/player.gd +++ b/actors/player.gd @@ -368,6 +368,9 @@ func _mouse_joystick_input() -> Vector2: func _physics_process(_delta: float) -> void: if self.ship.controls_disabled(): self.ship.set_firing(false) + self.ship.rigid_body_thruster.throttle = 0.0 + self.ship.rigid_body_direction.direction = Vector3.ZERO + self._rigid_body_turner.turning = 0.0 return if Input.is_action_pressed("jump"): From 91536e1a285d893e4bf0ca25cd74cf509d3e5251 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:20:24 +0100 Subject: [PATCH 14/17] Support heat-modifying outfits --- mechanics/outfitting/outfit.gd | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mechanics/outfitting/outfit.gd b/mechanics/outfitting/outfit.gd index 261f5dbe..1d56f713 100644 --- a/mechanics/outfitting/outfit.gd +++ b/mechanics/outfitting/outfit.gd @@ -56,6 +56,11 @@ class_name Outfit ## If negative, the output of the ship's [PowerGenerator] will be reduced by this amount. The outfit cannot be installed if the [PowerGenerator] is insufficient. @export var modified_power_generation: float = 0 +## A modification this outfit makes to heat sink capacity. +## +## If negative, the capacity of the ship's [HeatSink] will be reduced. The outfit cannot be installed if the available heat capacity is insufficient. +@export var modified_heat_capacity: float = 0 + ## A weapon provided by this outfit. @export var weapon: Weapon @@ -110,6 +115,11 @@ func can_install_onto_ship(ship: Ship) -> bool: if generator.rate_of_power < self.modified_power_generation: return false + + if not is_zero_approx(self.modified_heat_capacity): + # Include some epsilon so the ship doesn't end up overheated and inoperable + if ship.heat_sink.max_heat + self.modified_heat_capacity < 0.01: + return false if self.weapon: var mount_available := false @@ -143,6 +153,7 @@ func apply_to_ship(ship: Ship) -> void: ship.shield.recharge_rate *= self.shield_recharge_multiplier ship.hull.max_integrity += self.modified_hull_capacity + ship.heat_sink.max_heat += self.modified_heat_capacity if ship.power_management_unit.power_generator: ship.power_management_unit.power_generator.rate_of_power += self.modified_power_generation @@ -175,6 +186,7 @@ func remove_from_ship(ship: Ship) -> void: ship.shield.recharge_rate /= self.shield_recharge_multiplier ship.hull.max_integrity -= self.modified_hull_capacity + ship.heat_sink.max_heat -= self.modified_heat_capacity if ship.power_management_unit.power_generator: ship.power_management_unit.power_generator.rate_of_power -= self.modified_power_generation @@ -220,6 +232,9 @@ func get_effects() -> PackedStringArray: effects.push_back("[b]Fire interval:[/b] %ss" % [self.weapon.fire_interval]) effects.push_back("[b]Power consumption per shot:[/b] %s" % [self.weapon.power_consumption]) + if not is_zero_approx(self.modified_heat_capacity): + effects.push_back("[b]Heat:[/b] %s" % self._signed_string(-self.modified_heat_capacity)) + return effects func _signed_string(value: float) -> String: From da9b8b66b2a52e4b548c151ab7cc4c4124892755 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:23:38 +0100 Subject: [PATCH 15/17] Add heat effects to some outfits --- mechanics/outfitting/outfits/cargo_pod.tres | 3 +++ mechanics/outfitting/outfits/fuel_tank.tres | 3 +++ mechanics/outfitting/outfits/hull_plating.tres | 1 + mechanics/outfitting/outfits/shield_booster.tres | 1 + 4 files changed, 8 insertions(+) diff --git a/mechanics/outfitting/outfits/cargo_pod.tres b/mechanics/outfitting/outfits/cargo_pod.tres index 8e69248c..5e42f323 100644 --- a/mechanics/outfitting/outfits/cargo_pod.tres +++ b/mechanics/outfitting/outfits/cargo_pod.tres @@ -9,7 +9,10 @@ description = "Traders frequently like to expand their available cargo space, to mass = 10.0 price_in_credits = 7000.0 modified_cargo_capacity = 10.0 +modified_passenger_capacity = 0 modified_fuel_capacity = -1.0 +modified_hull_capacity = 0.0 modified_shield_capacity = 0.0 shield_recharge_multiplier = 1.0 modified_power_generation = 0.0 +modified_heat_capacity = -5.0 diff --git a/mechanics/outfitting/outfits/fuel_tank.tres b/mechanics/outfitting/outfits/fuel_tank.tres index b9c5b78f..64d2c4ce 100644 --- a/mechanics/outfitting/outfits/fuel_tank.tres +++ b/mechanics/outfitting/outfits/fuel_tank.tres @@ -9,7 +9,10 @@ description = "For the spacefaring captain making long haul journeys, extra fuel mass = 1.0 price_in_credits = 5000.0 modified_cargo_capacity = 0.0 +modified_passenger_capacity = 0 modified_fuel_capacity = 1.0 +modified_hull_capacity = 0.0 modified_shield_capacity = 0.0 shield_recharge_multiplier = 1.0 modified_power_generation = -1.0 +modified_heat_capacity = -5.0 diff --git a/mechanics/outfitting/outfits/hull_plating.tres b/mechanics/outfitting/outfits/hull_plating.tres index e47769fd..54952af4 100644 --- a/mechanics/outfitting/outfits/hull_plating.tres +++ b/mechanics/outfitting/outfits/hull_plating.tres @@ -15,3 +15,4 @@ modified_hull_capacity = 20.0 modified_shield_capacity = 0.0 shield_recharge_multiplier = 1.0 modified_power_generation = 0.0 +modified_heat_capacity = -10.0 diff --git a/mechanics/outfitting/outfits/shield_booster.tres b/mechanics/outfitting/outfits/shield_booster.tres index 90cf848d..09b00449 100644 --- a/mechanics/outfitting/outfits/shield_booster.tres +++ b/mechanics/outfitting/outfits/shield_booster.tres @@ -15,3 +15,4 @@ modified_hull_capacity = 0.0 modified_shield_capacity = 50.0 shield_recharge_multiplier = 1.1 modified_power_generation = -3.0 +modified_heat_capacity = -10.0 From 2d455f191816f8e93876fd10b578c3d109742659 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:24:17 +0100 Subject: [PATCH 16/17] Reset ship heat upon departure --- actors/player.gd | 1 + 1 file changed, 1 insertion(+) diff --git a/actors/player.gd b/actors/player.gd index b287b03b..a174691f 100644 --- a/actors/player.gd +++ b/actors/player.gd @@ -329,6 +329,7 @@ func _depart_from_port(port: Port) -> void: if self.ship.shield: self.ship.shield.integrity = self.ship.shield.max_integrity self.ship.hull.integrity = self.ship.hull.max_integrity + self.ship.heat_sink.heat = 0 self._reset_controls() self._reset_velocity() From d952e394f2c8fdbe77022806e9544d6caf3fb2fe Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 2 Sep 2024 20:25:02 +0100 Subject: [PATCH 17/17] Add heat damage to blaster bolts --- mechanics/combat/combat_object.gd | 5 +++++ mechanics/combat/weapons/blaster/blaster_bolt.tscn | 1 + mechanics/outfitting/outfits/blaster.tres | 1 + screens/game/game.tscn | 2 ++ ships/ship.gd | 1 + 5 files changed, 10 insertions(+) diff --git a/mechanics/combat/combat_object.gd b/mechanics/combat/combat_object.gd index e6567700..37a31ecf 100644 --- a/mechanics/combat/combat_object.gd +++ b/mechanics/combat/combat_object.gd @@ -49,6 +49,9 @@ var hull: Hull: ## An optional shield protecting the object. var shield: Shield +## A heat sink to dump heat to. +var heat_sink: HeatSink + ## Fires when this object is targeted, or stops being targeted, by a new [TargetingSystem]. ## ## See [method get_targeted_by] @@ -106,6 +109,8 @@ func damage(dmg: Damage) -> void: if apply_hull_dmg_pct > 0.0: self.hull.integrity -= dmg.hull_damage * apply_hull_dmg_pct + + self.heat_sink.heat += dmg.heat ## Checks whether [param node] contains a [CombatObject], and damages it if so. static func damage_combat_object_inside(node: Node, dmg: Damage) -> bool: diff --git a/mechanics/combat/weapons/blaster/blaster_bolt.tscn b/mechanics/combat/weapons/blaster/blaster_bolt.tscn index ae4468ae..3f211571 100644 --- a/mechanics/combat/weapons/blaster/blaster_bolt.tscn +++ b/mechanics/combat/weapons/blaster/blaster_bolt.tscn @@ -10,6 +10,7 @@ script = ExtResource("2_eoln0") shield_damage = 80.0 hull_damage = 40.0 +heat = 20.0 [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_5b1vh"] diff --git a/mechanics/outfitting/outfits/blaster.tres b/mechanics/outfitting/outfits/blaster.tres index 997dd055..8f4f99a6 100644 --- a/mechanics/outfitting/outfits/blaster.tres +++ b/mechanics/outfitting/outfits/blaster.tres @@ -16,4 +16,5 @@ modified_hull_capacity = 0.0 modified_shield_capacity = 0.0 shield_recharge_multiplier = 1.0 modified_power_generation = -1.0 +modified_heat_capacity = 0.0 weapon = ExtResource("2_womhg") diff --git a/screens/game/game.tscn b/screens/game/game.tscn index f2f4679e..67a8a965 100644 --- a/screens/game/game.tscn +++ b/screens/game/game.tscn @@ -196,6 +196,7 @@ hull = SubResource("Resource_p7sh0") shield = SubResource("Resource_dhynb") battery = SubResource("Resource_ubt7x") heat_sink = SubResource("Resource_dr1mv") +outfits = null [node name="AINavigation" parent="HyperspaceSceneSwitcher/Sol/Freighter" index="8"] direction_tolerance = null @@ -213,6 +214,7 @@ heat_sink = SubResource("Resource_s186x") cargo_hold = SubResource("Resource_on6n3") passenger_quarters = SubResource("Resource_ksma2") hyperdrive = SubResource("Resource_un4md") +outfits = null [node name="CombatObject" parent="HyperspaceSceneSwitcher/Sol/PlayerCorvette" index="3" node_paths=PackedStringArray("targeted_sound")] targeted_sound = NodePath("../Player/TargetedSound") diff --git a/ships/ship.gd b/ships/ship.gd index f364ce5c..cf5392fc 100644 --- a/ships/ship.gd +++ b/ships/ship.gd @@ -89,6 +89,7 @@ var save_node_path_override: NodePath func _ready() -> void: self.combat_object.hull = self.hull self.combat_object.shield = self.shield + self.combat_object.heat_sink = self.heat_sink if self.hero: self.combat_object.combat_name = self.hero.name self.hull.hull_destroyed.connect(func(_hull: Hull) -> void: