sunder/scripts/entities/components/flag_holder.gd
2026-03-16 10:43:26 -04:00

89 lines
3.3 KiB
GDScript

# This file is part of sunder.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
@icon("res://assets/icons/flag_holder.svg")
## This component is a unified system to manage [Flag] ownership, interaction
## logic, and visual displays for the owning Entity.
class_name FlagHolder extends Node3D
@export var throw_force:int = 16
## The radial progress bar to display the throwing force
@onready var texture_progress:TextureProgressBar = $ThrowForce
@onready var timer:Timer = $ThrowTimer
## The flag mesh to display when the owner carries the flag
@onready var mesh: Node3D = $Mesh
## The [Flag] instance to hold
var flag:Flag
func _process(_delta: float) -> void:
if is_visible_in_tree() and not timer.is_stopped():
var time_elapsed: float = timer.wait_time - timer.time_left
texture_progress.value = time_elapsed / (timer.wait_time / 2) * 100
## This method grabs a [Flag] which set the mesh visible, holds a reference to it
## and emits the [Flag.grabbed] signal to handle further state changes
func grab(p_flag:Flag) -> void:
if p_flag.state < Flag.FlagState.TAKEN:
flag = p_flag
flag.grabbed.emit(self)
show()
func drop() -> void:
if multiplayer.is_server() and flag and flag.state == flag.FlagState.TAKEN:
flag.global_position = global_position
flag.global_rotation.y = global_rotation.y
# inheritance
if owner is RigidBody3D:
flag.global_rotation.y = -flag.global_basis.z.dot(owner.linear_velocity)
flag.apply_impulse.call_deferred(flag.mass * owner.linear_velocity)
hide()
flag.dropped.emit(self)
flag = null
## This method displays throw force progress on the [HUD] of a client and upon release
## it throws the [Flag]. It has no effect when holding no flag or flag is not [member Flag.FlagState.TAKEN]
func throw(pressed:bool) -> void:
if flag and flag.state == flag.FlagState.TAKEN:
if pressed:
timer.start()
texture_progress.visible = true
timer.timeout.connect(func() -> void: texture_progress.visible = false)
else:
if timer.is_stopped():
return
var time_elapsed:float = timer.wait_time - timer.time_left
timer.stop()
texture_progress.visible = false
var pumped_force:float = clampf(time_elapsed / timer.wait_time * throw_force, 6., throw_force)
var throw_velocity:Vector3 = -global_basis.z * pumped_force
if owner is Player:
# player has camera and linear velocity
flag.global_position = owner.global_position
flag.global_rotation.y = owner.camera.global_rotation.y
throw_velocity = -owner.camera.global_basis.z * pumped_force + owner.linear_velocity
else:
flag.global_position = global_position
flag.global_position.y = global_rotation.y
var impulse:Vector3 = flag.mass * throw_velocity
flag.apply_impulse.call_deferred(impulse)
hide()
flag.dropped.emit(self)
flag = null