mirror of
https://gitlab.com/open-fpsz/open-fpsz.git
synced 2026-01-19 19:44:46 +00:00
66 lines
2.8 KiB
GDScript
66 lines
2.8 KiB
GDScript
# This file is part of open-fpsz.
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU 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 General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
## This class defines an explosive damage area.
|
|
##
|
|
## It detects nearby bodies within a radius defined by a child [CollisionShape3D]
|
|
## or [CollisionPolygon3D] and also initiates a blast that applies impulse and
|
|
## damages to detected bodies based on their distance from the explosion.
|
|
class_name ExplosiveDamage extends Area3D
|
|
|
|
## The base amount of damage.
|
|
@export var damage: int = 1
|
|
## The magnitude of blast force, in Newtons.
|
|
@export var blast_force: int = 1500
|
|
## A factor that determines how damage decreases with distance from the explosion center.
|
|
@export var falloff: Curve
|
|
## The entity responsible for dealing damage.
|
|
var source: Node = null
|
|
# The number of physics frames to process for blast detection.
|
|
var _blast_frames: int = 0
|
|
|
|
func _init() -> void:
|
|
if not body_shape_entered.is_connected(_on_body_shape_entered):
|
|
body_shape_entered.connect(_on_body_shape_entered)
|
|
|
|
# queue free area after processing few frames (enough for body detection)
|
|
func _physics_process(_delta: float) -> void:
|
|
_blast_frames += 1
|
|
if _blast_frames >= 2:
|
|
queue_free()
|
|
|
|
# overlapping bodies signal handler
|
|
func _on_body_shape_entered(_body_rid: RID, body: Node, _body_shape_idx: int, local_shape_idx: int) -> void:
|
|
if multiplayer.is_server():
|
|
# retrieve area shape
|
|
var shape : SphereShape3D = shape_owner_get_shape(
|
|
shape_find_owner(local_shape_idx), local_shape_idx)
|
|
# retrieve vector from current node origin to body global center of mass
|
|
var direction: Vector3 = (body.global_transform.origin + body.center_of_mass) - global_transform.origin
|
|
# sample curve texture if any to get falloff value at current distance
|
|
var weight := 1.0
|
|
if falloff:
|
|
weight = falloff.sample(direction.length() / shape.radius)
|
|
# handle blast
|
|
if body is RigidBody3D:
|
|
var impulse: Vector3 = direction.normalized() * (1000 * weight)
|
|
# apply body impulse based on distance from explosion origin
|
|
body.apply_impulse(impulse, global_transform.origin)
|
|
# handle blast damages
|
|
if body is Player:
|
|
# deal damage based on distance from explosion origin
|
|
body.damage.emit(source, body, damage * weight)
|
|
if body is Flag:
|
|
body.respawn_timer.start(clampf(body.respawn_timer.time_left + 5., 0., body.dropped_duration_max))
|