# 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 . @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