mirror of
https://codeberg.org/sunder/sunder.git
synced 2026-07-14 13:34:34 +00:00
94 lines
3.1 KiB
GDScript
94 lines
3.1 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/>.
|
|
class_name Flag extends RigidBody3D
|
|
|
|
signal grabbed(by:Node)
|
|
signal dropped(by:Node)
|
|
|
|
const scene:PackedScene = preload("res://scenes/entities/flag/flag.tscn")
|
|
|
|
static func instantiate() -> Flag:
|
|
return scene.instantiate()
|
|
|
|
enum FlagState {
|
|
## The flag is fresh and at its initial position
|
|
ON_STAND,
|
|
## The flag is dropped by a [FlagHolder]
|
|
DROPPED,
|
|
## The flag is taken and being carried by a [FlagHolder]
|
|
TAKEN
|
|
}
|
|
|
|
@export var state:FlagState = FlagState.ON_STAND
|
|
@export var last_carrier:Node
|
|
|
|
@onready var area:Area3D = $GripArea
|
|
@onready var mesh:Node3D = $Mesh
|
|
@onready var waypoint:Waypoint3D = $Waypoint
|
|
|
|
# @TODO: move this variable to a server.cfg
|
|
var dropped_max_duration := 30.
|
|
|
|
## This timer is responsible for returning the flag when it is dropped for more than [member dropped_max_duration].
|
|
var respawn_timer := Timer.new()
|
|
|
|
func _ready() -> void:
|
|
area.body_entered.connect(_on_body_entered)
|
|
grabbed.connect(_on_grabbed)
|
|
dropped.connect(_on_dropped)
|
|
if multiplayer.is_server():
|
|
respawn_timer.wait_time = dropped_max_duration
|
|
respawn_timer.one_shot = true
|
|
add_child(respawn_timer)
|
|
|
|
func _process(_delta:float) -> void:
|
|
if state == FlagState.DROPPED and not respawn_timer.is_stopped():
|
|
waypoint.text = "%.2f s" % respawn_timer.time_left
|
|
else:
|
|
waypoint.text = ""
|
|
|
|
# @NOTE: simple way to deal with dynamic collision for distant objects
|
|
#func _physics_process(delta:float) -> void:
|
|
#var root := get_tree().current_scene
|
|
#var distance_to_camera := global_position.distance_to(get_viewport().get_camera_3d().global_position)
|
|
## Determine if terrain collision is active (or too far from camera when using dynamic terrain colliton mode)
|
|
#var using_fake_ground:bool = distance_to_camera > root.map.collision_radius
|
|
#if using_fake_ground:
|
|
#global_position.y = root.map.data.get_height(global_position) # ground_height
|
|
#linear_velocity.y = 0
|
|
|
|
func _on_body_entered(body: Node) -> void:
|
|
if body is Player:
|
|
assert(body.flag_holder)
|
|
body.flag_holder.grab(self)
|
|
|
|
## This method is called immediatly after the flag is grabbed
|
|
func _on_grabbed(by:Node) -> void:
|
|
assert(state < FlagState.TAKEN)
|
|
state = FlagState.TAKEN
|
|
freeze = true
|
|
area.set_deferred("monitoring", false)
|
|
last_carrier = by
|
|
hide()
|
|
|
|
func _on_dropped(by:Node) -> void:
|
|
assert(state == FlagState.TAKEN)
|
|
state = FlagState.DROPPED
|
|
freeze = false
|
|
# enable monitoring back after some delay
|
|
var _timer := get_tree().create_timer(1.)
|
|
_timer.timeout.connect(func() -> void: area.monitoring = true)
|
|
last_carrier = by
|
|
show()
|