This commit is contained in:
Patrick_Pluto 2025-07-18 19:32:37 +01:00
commit fadea22b9d
26 changed files with 741 additions and 0 deletions

22
entities/coffin.gd Normal file
View file

@ -0,0 +1,22 @@
class_name Coffin
extends StaticBody3D
var caught_player: Player = null
func _on_dropoff(body: Node3D) -> void:
if multiplayer.is_server() and body is Player:
var player: Player = body
if player.caught_player and !caught_player:
caught_player = player.caught_player
player.caught_player.get_imprisoned.rpc_id(player.caught_player.get_multiplayer_authority(), get_path())
player.released_player.rpc_id(player.get_multiplayer_authority())
(player.get_node("ReleaseTimer") as Timer).stop()
($DamageTimer as Timer).start()
elif !player.hunter and player.visible and caught_player and caught_player.health > 0:
caught_player.go_free.rpc_id(caught_player.get_multiplayer_authority())
caught_player = null
($DamageTimer as Timer).stop()
func _on_damage_timer_timeout() -> void:
if multiplayer.is_server() and caught_player.health > 0:
caught_player.damage_player.rpc_id(caught_player.get_multiplayer_authority())

1
entities/coffin.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://oaxiyitfsq2q

32
entities/coffin.tscn Normal file
View file

@ -0,0 +1,32 @@
[gd_scene load_steps=4 format=3 uid="uid://dx0yaqaccakh"]
[ext_resource type="Script" uid="uid://oaxiyitfsq2q" path="res://entities/coffin.gd" id="1_0x4dk"]
[sub_resource type="BoxShape3D" id="BoxShape3D_0x4dk"]
size = Vector3(3, 1.2, 1.4)
[sub_resource type="BoxShape3D" id="BoxShape3D_cvqjw"]
size = Vector3(4, 1.4, 2.4)
[node name="Coffin" type="StaticBody3D"]
script = ExtResource("1_0x4dk")
[node name="Mesh" type="CSGBox3D" parent="."]
size = Vector3(3, 1.2, 1.4)
[node name="Collision" type="CollisionShape3D" parent="."]
shape = SubResource("BoxShape3D_0x4dk")
[node name="DropoffZone" type="Area3D" parent="."]
[node name="Collision" type="CollisionShape3D" parent="DropoffZone"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
shape = SubResource("BoxShape3D_cvqjw")
[node name="DamageTimer" type="Timer" parent="."]
[node name="RespawnPoint" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0.75, 0)
[connection signal="body_entered" from="DropoffZone" to="." method="_on_dropoff"]
[connection signal="timeout" from="DamageTimer" to="." method="_on_damage_timer_timeout"]

147
entities/player.gd Normal file
View file

@ -0,0 +1,147 @@
class_name Player
extends CharacterBody3D
const SPEED: float = 5.0
const JUMP_VELOCITY: float = 4.5
@onready var camera_x: Node3D = $ViewY/ViewX
@onready var camera: Camera3D = $ViewY/ViewX/View
@onready var syringe: Node3D = $Syringe
@onready var needle: Area3D = $Syringe/SyringeNeedle
@onready var bag: Node3D = $Bag
@onready var captured: Node3D = $Bag/Captured
var hunter: bool = true
var caught_player: Player = null
var new_spawn: Vector3
@export var health: int = 100
func _ready() -> void:
if is_multiplayer_authority():
camera.current = true
($HUD as Control).visible = true
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
if hunter:
syringe.visible = true
bag.visible = true
else:
needle.monitoring = false
func _physics_process(delta: float) -> void:
# Zoom
if Input.is_action_just_released("zoom_in") and camera.position.z > 0:
camera.position.z += -1
elif Input.is_action_just_released("zoom_out"):
camera.position.z += 1
if is_multiplayer_authority():
# Focus
if Input.is_action_just_pressed("unfocus"):
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
elif Input.is_action_just_pressed("focus"):
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
pass
if visible:
# Gravity
if not is_on_floor():
velocity += get_gravity() * delta
# Jumping
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Movement
var input_dir: Vector2 = Input.get_vector("move_left", "move_right", "move_forwards", "move_backwards")
var direction: Vector3 = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
# Hunter specific
if hunter:
if Input.is_action_pressed("stab"):
syringe.position.z -= 0.1
else:
syringe.position.z += 0.1
syringe.position.z = clampf(syringe.position.z, -0.8, -0.3)
if move_and_slide():
pass
func _unhandled_input(event: InputEvent) -> void:
# Camera Movement
if event is InputEventMouseMotion:
var mouse_event: InputEventMouseMotion = event
if is_multiplayer_authority():
rotate_y(deg_to_rad(-mouse_event.relative.x))
else:
($ViewY as Node3D).rotate_y(deg_to_rad(-mouse_event.relative.x))
camera_x.rotate_x(deg_to_rad(-mouse_event.relative.y))
camera_x.rotation.x = clampf(camera_x.rotation.x, -1.6, 1.6)
# Gets called when the Player gets stabbed by the syringe.
func _on_stab(body: Node3D) -> void:
if multiplayer.is_server() and body is Player and body.visible == true:
var player: Player = body
caught_player = player
player.get_caught.rpc_id(player.get_multiplayer_authority(), camera.get_path())
capture_player.rpc_id(get_multiplayer_authority(), player.get_path())
($ReleaseTimer as Timer).start()
# Player gets released through the timer
func _on_release() -> void:
if multiplayer.is_server():
caught_player.go_free.rpc_id(caught_player.get_multiplayer_authority())
released_player.rpc_id(get_multiplayer_authority())
# This is called on any player that was just stabbed/caught.
@rpc("any_peer", "call_local", "reliable")
func get_caught(spectator_camera_path: NodePath) -> void:
if multiplayer.get_remote_sender_id() == 1:
var spectator_camera: Camera3D = get_node(spectator_camera_path)
visible = false
($Collision as CollisionShape3D).disabled = true
spectator_camera.current = true
new_spawn = position
# This is called on any player when they go free.
@rpc("any_peer", "call_local", "reliable")
func go_free() -> void:
if multiplayer.get_remote_sender_id() == 1:
camera.current = true
visible = true
($Collision as CollisionShape3D).disabled = false
position = new_spawn
# This is called on any player when they go free.
@rpc("any_peer", "call_local", "reliable")
func get_imprisoned(coffin_path: NodePath) -> void:
if multiplayer.get_remote_sender_id() == 1:
var coffin: Coffin = get_node(coffin_path)
camera.current = true
position = coffin.position
new_spawn = (coffin.get_node("RespawnPoint") as Node3D).position
# This is called on any player that has just stabbed/caught another.
@rpc("any_peer", "call_local", "reliable")
func capture_player(player_path: NodePath) -> void:
if multiplayer.get_remote_sender_id() == 1:
var player: Player = get_node(player_path)
caught_player = player
captured.visible = true
# This is called on any player that was just stabbed/caught.
@rpc("any_peer", "call_local", "reliable")
func released_player() -> void:
if multiplayer.get_remote_sender_id() == 1:
caught_player = null
captured.visible = false
# Damages the player
@rpc("any_peer", "call_local", "reliable")
func damage_player() -> void:
if multiplayer.get_remote_sender_id() == 1:
health -= 2
($HUD/Health as Label).text = "Health: " + str(health)

1
entities/player.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://dtlssj0xohnpc

99
entities/player.tscn Normal file
View file

@ -0,0 +1,99 @@
[gd_scene load_steps=6 format=3 uid="uid://4hmftsrl305n"]
[ext_resource type="Script" uid="uid://dtlssj0xohnpc" path="res://entities/player.gd" id="1_merdl"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_u3f3p"]
radius = 0.4
height = 1.8
[sub_resource type="CapsuleMesh" id="CapsuleMesh_merdl"]
radius = 0.4
height = 1.8
[sub_resource type="CylinderShape3D" id="CylinderShape3D_merdl"]
height = 0.2
radius = 0.05
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_merdl"]
properties/0/path = NodePath(".:position")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath(".:rotation")
properties/1/spawn = true
properties/1/replication_mode = 1
properties/2/path = NodePath("Syringe:position")
properties/2/spawn = true
properties/2/replication_mode = 1
properties/3/path = NodePath(".:visible")
properties/3/spawn = true
properties/3/replication_mode = 1
properties/4/path = NodePath(".:health")
properties/4/spawn = true
properties/4/replication_mode = 1
[node name="Player" type="CharacterBody3D"]
script = ExtResource("1_merdl")
[node name="Collision" type="CollisionShape3D" parent="."]
shape = SubResource("CapsuleShape3D_u3f3p")
[node name="Mesh" type="MeshInstance3D" parent="."]
mesh = SubResource("CapsuleMesh_merdl")
[node name="Syringe" type="CSGCylinder3D" parent="."]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.4, 0, -0.3)
visible = false
radius = 0.05
height = 1.0
[node name="SyringeNeedle" type="Area3D" parent="Syringe"]
[node name="Collision" type="CollisionShape3D" parent="Syringe/SyringeNeedle"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.4, 0)
shape = SubResource("CylinderShape3D_merdl")
[node name="Bag" type="CSGCylinder3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.8)
visible = false
radius = 0.4
height = 1.0
[node name="Captured" type="CSGSphere3D" parent="Bag"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
visible = false
radius = 0.3
[node name="ViewY" type="Node3D" parent="."]
[node name="ViewX" type="Node3D" parent="ViewY"]
transform = Transform3D(1, 0, 0, 0, 0.866025, 0.5, 0, -0.5, 0.866025, 0, 0.5, 0)
[node name="View" type="Camera3D" parent="ViewY/ViewX"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 4)
size = 5.0
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
replication_config = SubResource("SceneReplicationConfig_merdl")
[node name="ReleaseTimer" type="Timer" parent="."]
wait_time = 30.0
one_shot = true
[node name="HUD" type="Control" parent="."]
visible = false
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
[node name="Health" type="Label" parent="HUD"]
layout_mode = 1
offset_right = 88.0
offset_bottom = 23.0
text = "Health: 100"
[connection signal="body_entered" from="Syringe/SyringeNeedle" to="." method="_on_stab"]
[connection signal="timeout" from="ReleaseTimer" to="." method="_on_release"]

View file

@ -0,0 +1,21 @@
class_name PlayerSpawner
extends Node3D
const PLAYER_SCENE: PackedScene = preload("res://entities/player.tscn")
func _spawn_player(player: Dictionary) -> CharacterBody3D:
var player_instance: Player = PLAYER_SCENE.instantiate()
var id: int = player.id
player_instance.position = position
player_instance.hunter = player.hunter
player_instance.set_multiplayer_authority(id)
return player_instance
func _ready() -> void:
if $MultiplayerSpawner is MultiplayerSpawner:
($MultiplayerSpawner as MultiplayerSpawner).spawn_function = _spawn_player
func spawn_player(player: Dictionary) -> void:
if $MultiplayerSpawner is MultiplayerSpawner:
if ($MultiplayerSpawner as MultiplayerSpawner).spawn(player) == null:
print("Failed to spawn player.")

View file

@ -0,0 +1 @@
uid://rhk1kmfu2hjo

View file

@ -0,0 +1,9 @@
[gd_scene load_steps=2 format=3 uid="uid://cu1d6uwha7jm2"]
[ext_resource type="Script" uid="uid://rhk1kmfu2hjo" path="res://entities/player_spawner.gd" id="1_q56n2"]
[node name="PlayerSpawner" type="Node3D"]
script = ExtResource("1_q56n2")
[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="."]
spawn_path = NodePath("../..")