mirror of
https://github.com/ElHombreAlex/FTL-Faster-Than-Light-VR.git
synced 2026-10-06 04:04:10 +02:00
Fix Flagship visuals, beam aiming, results and Frame controls
This commit is contained in:
1 parent
e857f4eee9
commit
cf9cfca866
27 files changed
+1084
-96
No files matched your search
@@ -17,6 +17,11 @@ var unit_beam_mesh: CylinderMesh
|
||||
|
||||
|
||||
func spawn_shot(event: Dictionary, sender: Node3D, receiver: Node3D) -> void:
|
||||
var projectile_id := str(event.get("projectile_id", ""))
|
||||
for shot in shots:
|
||||
if not projectile_id.is_empty() and shot["projectile_id"] == projectile_id:
|
||||
# Repeated fire delivery cannot restart an already visible native flight.
|
||||
return
|
||||
var kind := str(event.get("kind", "laser"))
|
||||
var origin_ship := sender
|
||||
if event.has("origin_space") and int(event["origin_space"]) == int(receiver.get("enemy")):
|
||||
@@ -24,6 +29,8 @@ func spawn_shot(event: Dictionary, sender: Node3D, receiver: Node3D) -> void:
|
||||
if event.has("target_space") and int(event["target_space"]) == int(sender.get("enemy")):
|
||||
receiver = sender
|
||||
var start: Vector3 = sender.weapon_origin(int(event.get("weapon_slot", 0)))
|
||||
if event.has("artillery_slot"):
|
||||
start = sender.artillery_origin(int(event["artillery_slot"]))
|
||||
var drone_id := str(event.get("drone_id", ""))
|
||||
var drone: Node3D = _drone(origin_ship, drone_id)
|
||||
if drone != null:
|
||||
@@ -61,15 +68,17 @@ func spawn_shot(event: Dictionary, sender: Node3D, receiver: Node3D) -> void:
|
||||
node.visible = false
|
||||
# Bombs appear at their destination rather than crossing space.
|
||||
shots.append({"node": node, "start": start, "end": end, "beam_end": beam_end,
|
||||
"projectile_id": str(event.get("projectile_id", "")), "sender": sender,
|
||||
"projectile_id": projectile_id, "sender": sender,
|
||||
"created_ms": Time.get_ticks_msec(), "native_present": false,
|
||||
"visual_scale": maxf(0.1, (origin_ship if not drone_id.is_empty() else sender).global_basis.get_scale().abs().x),
|
||||
"live_progress": 0.0, "wanted_progress": 0.0, "missed": false, "miss_feedback": false,
|
||||
"target_end": end, "miss_origin_progress": 0.0, "miss_interval": 1.0,
|
||||
"end_point": event.get("end_point", {}),
|
||||
"origin_point": event.get("origin_point", {}), "origin_ship": origin_ship,
|
||||
"drone_id": drone_id, "launch_point": origin_ship.to_local(start),
|
||||
"target_point": event.get("target", {}), "beam_point": {},
|
||||
"slot": int(event.get("weapon_slot", 0)), "room": int(event.get("target_room", 0)),
|
||||
"slot": int(event.get("weapon_slot", 0)), "artillery_slot": int(event.get("artillery_slot", -1)),
|
||||
"room": int(event.get("target_room", 0)),
|
||||
"time": 0.0, "duration": duration, "kind": kind, "outcome": outcome, "receiver": receiver})
|
||||
|
||||
|
||||
@@ -116,13 +125,14 @@ func _process(delta: float) -> void:
|
||||
var drone: Node3D = _drone(shot["origin_ship"], shot["drone_id"])
|
||||
shot["start"] = drone.muzzle_position(shot["projectile_id"]) if shot["kind"] == "beam" and drone != null else shot["origin_ship"].to_global(shot["launch_point"])
|
||||
else:
|
||||
shot["start"] = shot["sender"].weapon_origin(shot["slot"])
|
||||
shot["start"] = shot["sender"].artillery_origin(shot["artillery_slot"]) if shot["artillery_slot"] >= 0 else shot["sender"].weapon_origin(shot["slot"])
|
||||
if shot["drone_id"].is_empty() and not shot["origin_point"].is_empty():
|
||||
shot["start"] = shot["origin_ship"].to_global(shot["origin_ship"].pixel_point(shot["origin_point"]))
|
||||
if shot["outcome"] == "pending":
|
||||
shot["end"] = shot["receiver"].room_target(shot["room"])
|
||||
if not shot["target_point"].is_empty():
|
||||
shot["end"] = shot["receiver"].to_global(shot["receiver"].pixel_point(shot["target_point"]))
|
||||
shot["target_end"] = shot["end"]
|
||||
if shot["missed"]:
|
||||
shot["end"] = _miss_endpoint(shot["start"], shot["end"], shot["receiver"])
|
||||
if not shot["end_point"].is_empty():
|
||||
@@ -130,7 +140,8 @@ func _process(delta: float) -> void:
|
||||
var progress := clampf(float(shot["time"]) / float(shot["duration"]), 0.0, 1.0)
|
||||
if shot["outcome"] == "pending":
|
||||
if not simulation_paused:
|
||||
shot["live_progress"] = lerpf(shot["live_progress"], shot["wanted_progress"], minf(1.0, delta * 20.0))
|
||||
var next_progress := lerpf(shot["live_progress"], shot["wanted_progress"], minf(1.0, delta * 20.0))
|
||||
shot["live_progress"] = next_progress if shot["kind"] == "beam" else maxf(shot["live_progress"], next_progress)
|
||||
progress = shot["live_progress"]
|
||||
var node: MeshInstance3D = shot["node"]
|
||||
if shot["kind"] == "beam":
|
||||
@@ -149,8 +160,10 @@ func _process(delta: float) -> void:
|
||||
_segment(node.get_node("BeamCore"), shot["start"], beam_target, (0.007 if not shot["drone_id"].is_empty() else 0.012) * shot["visual_scale"])
|
||||
_segment(node.get_node("BeamGlow"), shot["start"], beam_target, (0.018 if not shot["drone_id"].is_empty() else 0.032) * shot["visual_scale"])
|
||||
elif shot["kind"] != "bomb":
|
||||
node.global_position = Vector3(shot["start"]).lerp(shot["end"], progress)
|
||||
node.global_position = _flight_position(shot, progress)
|
||||
var direction: Vector3 = Vector3(shot["end"]) - Vector3(shot["start"])
|
||||
if shot["outcome"] == "pending" and shot["missed"]:
|
||||
direction = Vector3(shot["end"]) - Vector3(shot["start"]).lerp(shot["target_end"], shot["miss_origin_progress"])
|
||||
if direction.length_squared() > 0.000001:
|
||||
var up := Vector3.RIGHT if absf(direction.normalized().dot(Vector3.UP)) > 0.98 else Vector3.UP
|
||||
node.global_basis = Basis.looking_at(direction.normalized(), up).scaled(Vector3.ONE * shot["visual_scale"])
|
||||
@@ -178,7 +191,7 @@ func resolve_live(event: Dictionary, receiver: Node3D) -> void:
|
||||
if event.get("outcome", "") == "miss":
|
||||
# Evasion is reported at the native collision decision. The shot
|
||||
# may still be flying; native snapshots decide when it disappears.
|
||||
shots[i]["missed"] = true
|
||||
_mark_missed(shots[i])
|
||||
_show_shot_miss(shots[i])
|
||||
return
|
||||
kind = str(shots[i]["kind"])
|
||||
@@ -208,8 +221,15 @@ func update_live_projectiles(projectiles: Array) -> void:
|
||||
if present.has(shot["projectile_id"]):
|
||||
var projectile: Dictionary = present[shot["projectile_id"]]
|
||||
shot["native_present"] = true
|
||||
shot["wanted_progress"] = float(projectile.get("progress", 0))
|
||||
shot["missed"] = shot["missed"] or bool(projectile.get("missed", false))
|
||||
if bool(projectile.get("missed", false)):
|
||||
_mark_missed(shot)
|
||||
var native_progress := maxf(0.0, float(projectile.get("progress", 0)))
|
||||
if shot["kind"] == "beam" or not shot["missed"]:
|
||||
native_progress = minf(1.0, native_progress)
|
||||
# Older bridges measured remaining radial distance to the target; that
|
||||
# value decreases again after a miss flies past it. Out-of-order native
|
||||
# snapshots must likewise never pull a projectile back toward its sender.
|
||||
shot["wanted_progress"] = native_progress if shot["kind"] == "beam" else maxf(shot["wanted_progress"], native_progress)
|
||||
if shot["missed"]:
|
||||
_show_shot_miss(shot)
|
||||
shot["beam_point"] = projectile.get("beam_point", {})
|
||||
@@ -222,6 +242,27 @@ func update_live_projectiles(projectiles: Array) -> void:
|
||||
shots.remove_at(i)
|
||||
|
||||
|
||||
func _mark_missed(shot: Dictionary) -> void:
|
||||
if shot["missed"]:
|
||||
return
|
||||
shot["missed"] = true
|
||||
shot["miss_origin_progress"] = float(shot["live_progress"])
|
||||
shot["miss_interval"] = maxf(0.25, 1.0 - float(shot["miss_origin_progress"]))
|
||||
|
||||
|
||||
func _flight_position(shot: Dictionary, progress: float) -> Vector3:
|
||||
if shot["outcome"] != "pending" or not shot["missed"]:
|
||||
return Vector3(shot["start"]).lerp(shot["end"], progress)
|
||||
# Begin the passing path at the exact already-presented point. Switching to
|
||||
# a native miss cannot jump the bullet to a different segment or reset it.
|
||||
# New native progress may exceed one after passing the target; extrapolate
|
||||
# forward until native absence, which ends the visual without an impact.
|
||||
var origin_progress := float(shot["miss_origin_progress"])
|
||||
var origin: Vector3 = Vector3(shot["start"]).lerp(shot["target_end"], origin_progress)
|
||||
var passing_progress := maxf(0.0, progress - origin_progress) / float(shot["miss_interval"])
|
||||
return origin.lerp(shot["end"], passing_progress)
|
||||
|
||||
|
||||
func _impact(point: Vector3, kind: String = "laser", shield: bool = false) -> void:
|
||||
var flash := MeshInstance3D.new()
|
||||
var sphere_key := "large" if kind in ["missile", "bomb"] else "small"
|
||||
|
||||
Reference in new issue
Block a user