Files
Blockline/scripts/rope_lift.gd
T

51 lines
1.9 KiB
GDScript

class_name RopeLift
extends RefCounted
static func nearby(p: Fighter) -> Dictionary:
for lift: Dictionary in p.game.arena.lifts:
for endpoint in ["bottom", "top"]:
if p.global_position.distance_to(lift[endpoint]) < 1.6:
return {"lift": lift, "up": endpoint == "bottom"}
return {}
static func start(p: Fighter) -> void:
if not p.game.is_host or p.hp <= 0 or p.mantle_left > 0 or not p.rope_path.is_empty(): return
var candidate := nearby(p)
if candidate.is_empty(): return
var lift: Dictionary = candidate.lift
var above_roof := Vector3(lift.top.x, lift.over.y, lift.top.z)
var destination: Vector3 = lift.top if candidate.up else lift.bottom
for other: Fighter in p.game.players.values():
if other != p and other.hp > 0 and other.global_position.distance_to(destination) < 1.0: return
# Validate the full capsule corridor before mounting; no teleport through walls.
var route := PackedVector3Array([lift.bottom, lift.over, above_roof, lift.top]) if candidate.up else PackedVector3Array([lift.top, above_roof, lift.over, lift.bottom])
var pose := p.global_transform
for point in route:
if p.test_move(pose, point - pose.origin): return
pose.origin = point
p.rope_path = route
p.rope_active = true
p.reload_left = 0
p.aiming = false
p.protection = 0
static func advance(p: Fighter, dt: float) -> void:
if p.input_data.get("jump", false):
p.input_data["jump"] = false
p.rope_path.clear()
p.rope_active = false
return
if p.rope_path.is_empty():
p.rope_active = false
return
var target := p.rope_path[0]
var motion := p.global_position.move_toward(target, dt * 5.5) - p.global_position
if p.test_move(p.global_transform, motion):
p.rope_path.clear()
p.rope_active = false
return
p.global_position += motion
p.velocity = Vector3.ZERO
if p.global_position.distance_to(target) < 0.015: p.rope_path.remove_at(0)
p.rope_active = not p.rope_path.is_empty()