Files
Brachistochrone/addons/Assets/enviroment assets/grok-alec/fleet/soyuz.gd
T
scorpion21211-cmd 8efae1a0d0 changelog
arcology updated
ship models in
particle fx is broken on kestrel
2026-10-04 19:37:48 -04:00

155 lines
6.0 KiB
GDScript

extends Node3D
## Soyuz-MS. Godot 4.7. Units: 1 m.
## Axes: dock / forward +Z, dorsal +Y, starboard +X. The service engine exhausts -Z.
## rcs_direction uses those axes. Nose thrust is +Z, not +Y.
## Drive is a chemical torch (short, warm). Abort motors are the same ribbons as Kestrel.
## See PARTICLE_FX.md.
const Fx = preload("res://naf_fx.gd")
@export_range(0.0, 1.0) var hatch_crew_open := 0.0 : set = set_hatch_crew_open
@export_range(0.0, 1.0) var hatch_transfer_open := 0.0 : set = set_hatch_transfer_open
@export_range(0.0, 1.0) var hatch_dock_open := 0.0 : set = set_hatch_dock_open
@export_range(0.0, 1.0) var throttle := 0.0
@export var drive_on := false
@export_enum("Off", "Nose", "Tail", "Starboard", "Port", "Dorsal", "Ventral") var rcs_direction := 0
@export var abort_burn := false
var _time := 0.0
var _spool := 0.0
var _abort_hold := 0.0
var _drive_socket: Node3D
var _drive_core: Node3D
var _drive_sheath: Node3D
var _drive_light: SpotLight3D
var _rcs: Array[Node3D] = []
var _aborts: Array[Dictionary] = []
const _RCS_THRUST := [
Vector3.ZERO,
Vector3(0, 0, 1),
Vector3(0, 0, -1),
Vector3(1, 0, 0),
Vector3(-1, 0, 0),
Vector3(0, 1, 0),
Vector3(0, -1, 0),
]
func _ready() -> void:
_arm_fx()
set_physics_process(true)
func _physics_process(delta: float) -> void:
_time += delta
var power := throttle if drive_on else 0.0
var spool_target := 1.0 if power > 0.04 else 0.0
_spool = Fx.smooth(_spool, spool_target, delta, 0.2 if spool_target > 0.0 else 0.12)
var plume := power * _spool
if _drive_core:
Fx.set_spear(_drive_core, plume, 1.0, _time)
Fx.set_spear(_drive_sheath, plume * 0.82, 1.0, _time)
if _drive_light:
_drive_light.light_energy = plume * 6.0
var thrust: Vector3 = _RCS_THRUST[clampi(rcs_direction, 0, _RCS_THRUST.size() - 1)]
var ship := global_transform.basis
for ribbon in _rcs:
var want := 0.0
if thrust != Vector3.ZERO:
var exhaust: Vector3 = ship.inverse() * ribbon.global_transform.basis.y
if exhaust.dot(-thrust) > 0.7:
want = 1.0
var burn := float(ribbon.get_meta("burn"))
burn = Fx.smooth(burn, want, delta, 0.08 if want > burn else 0.14)
ribbon.set_meta("burn", burn)
Fx.set_spear(ribbon, burn, 1.0, _time)
if abort_burn:
_abort_hold = minf(1.0, _abort_hold + delta / 0.22)
elif _abort_hold > 0.0:
_abort_hold = maxf(0.0, _abort_hold - delta / 0.28)
var on := _abort_hold > 0.03
var flick := 0.86 + 0.14 * sin(_time * 41.0)
var sheath_scale := 0.9 + 0.1 * sin(_time * 19.0)
for a in _aborts:
var core := a.core as Node3D
var sheath := a.sheath as Node3D
Fx.set_opacity(core, _abort_hold * 0.95 * flick if on else 0.0)
Fx.set_opacity(sheath, _abort_hold * 0.82 * flick if on else 0.0)
sheath.scale = Vector3(1, sheath_scale, 1)
var sparks := a.sparks as GPUParticles3D
var sheath_sparks := a.sheath_sparks as GPUParticles3D
sparks.emitting = on
sheath_sparks.emitting = on
var flash := a.flash as MeshInstance3D
flash.visible = on
var fmat := flash.material_override as StandardMaterial3D
if fmat:
var tint := fmat.albedo_color
tint.a = _abort_hold * 0.45
fmat.albedo_color = tint
flash.scale = Vector3.ONE * (0.06 + _abort_hold * 0.04)
var light := a.light as SpotLight3D
light.light_energy = _abort_hold * 8.0 if on else 0.0
func set_hatch_crew_open(v: float) -> void:
hatch_crew_open = v
_seek("hatch_crew_open", v)
func set_hatch_transfer_open(v: float) -> void:
hatch_transfer_open = v
_seek("hatch_transfer_open", v)
func set_hatch_dock_open(v: float) -> void:
hatch_dock_open = v
_seek("hatch_dock_open", v)
func _seek(clip: StringName, t: float) -> void:
var ap := get_node_or_null("AnimationPlayer") as AnimationPlayer
if ap == null:
ap = find_child("AnimationPlayer", true, false) as AnimationPlayer
if ap == null or not ap.has_animation(clip):
return
ap.play(clip)
ap.seek(clampf(t, 0.0, 1.0) * ap.get_animation(clip).length, true)
ap.pause()
func _arm_fx() -> void:
var drive := find_child("Vfx_DrivePlume", true, false) as Node3D
if drive:
_drive_socket = drive
_drive_core = Fx.spear(drive, 7.0, 0.5, Color(1.0, 0.953, 0.831, 0.95), Color(1.0, 0.72, 0.4, 0.4), Color(1.0, 0.45, 0.1, 0.0), 0.92, 4, 1.0, "DriveCore")
_drive_sheath = Fx.spear(drive, 5.0, 1.25, Color(0.91, 0.353, 0.07, 0.9), Color(0.7, 0.2, 0.02, 0.35), Color(0.3, 0.05, 0.0, 0.0), 0.6, 3, 2.0, "DriveSheath")
_drive_light = Fx.spot(drive, 0.2, Color(1.0, 0.627, 0.29), 0.5, 6.0, 2.0)
for n in find_children("*", "Node3D", true, false):
var nm := String(n.name)
if nm.begins_with("Vfx_RCS_"):
_rcs.append(Fx.spear(n, 1.2, 0.09, Color(0.863, 0.937, 1.0, 0.95), Color(0.41, 0.67, 1.0, 0.35), Color(0.25, 0.45, 0.8, 0.0), 0.82, 2, 1.0, "Spear"))
elif nm.begins_with("Vfx_Abort_"):
_aborts.append(_make_abort(n))
func _make_abort(socket: Node3D) -> Dictionary:
var core := Fx.taper_ribbon(socket, 2.1, 0.06, 0.20, Color(1.0, 0.97, 0.92, 1.0), Color(1.0, 0.45, 0.12, 0.72), Color(0.40, 0.08, 0.02, 0.0), 0.95, 3, "AbortCore")
var sheath := Fx.taper_ribbon(socket, 5.2, 0.10, 0.78, Color(1.0, 0.55, 0.18, 1.0), Color(1.0, 0.28, 0.06, 0.55), Color(0.35, 0.06, 0.01, 0.0), 0.82, 3, "AbortSheath")
var sparks := Fx.sparks(socket, "AbortCoreSparks", 10, 0.15, 18.0, 28.0, 1.6, 0.05, 6.0)
var sheath_sparks := Fx.sparks(socket, "AbortSheathSparks", 18, 0.26, 14.0, 22.0, 4.5, 0.09, 8.0)
for p in [sparks, sheath_sparks]:
var proc := p.process_material as ParticleProcessMaterial
if proc:
proc.color_ramp = _abort_ramp()
var flash := Fx.abort_flash(socket)
var light := Fx.spot(socket, 0.08, Color(1.0, 0.416, 0.157), 0.5, 6.5, 1.8)
light.light_energy = 0.0
return {"core": core, "sheath": sheath, "sparks": sparks, "sheath_sparks": sheath_sparks, "flash": flash, "light": light}
func _abort_ramp() -> GradientTexture1D:
var g := Gradient.new()
g.offsets = PackedFloat32Array([0.0, 0.15, 0.45, 1.0])
g.colors = PackedColorArray([
Color(1.0, 0.97, 0.92, 1.0),
Color(1.0, 0.46, 0.12, 0.9),
Color(0.55, 0.16, 0.05, 0.45),
Color(0.25, 0.05, 0.01, 0.0),
])
var tex := GradientTexture1D.new()
tex.gradient = g
return tex