diff --git a/components/explosive_damage_component.gd b/entities/components/explosive_damage_component.gd similarity index 100% rename from components/explosive_damage_component.gd rename to entities/components/explosive_damage_component.gd diff --git a/components/explosive_damage_component.tscn b/entities/components/explosive_damage_component.tscn similarity index 65% rename from components/explosive_damage_component.tscn rename to entities/components/explosive_damage_component.tscn index a1589de..3a35a9a 100644 --- a/components/explosive_damage_component.tscn +++ b/entities/components/explosive_damage_component.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://ds1hekx1dq1bg"] -[ext_resource type="Script" path="res://components/explosive_damage_component.gd" id="1_2uehk"] +[ext_resource type="Script" path="res://entities/components/explosive_damage_component.gd" id="1_2uehk"] [node name="ExplosiveDamage" type="Area3D"] collision_layer = 0 diff --git a/components/flag_carry_component.gd b/entities/components/flag_carry_component.gd similarity index 100% rename from components/flag_carry_component.gd rename to entities/components/flag_carry_component.gd diff --git a/components/flag_carry_component.tscn b/entities/components/flag_carry_component.tscn similarity index 58% rename from components/flag_carry_component.tscn rename to entities/components/flag_carry_component.tscn index 17603b8..6587f8c 100644 --- a/components/flag_carry_component.tscn +++ b/entities/components/flag_carry_component.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://2t8ql8pkxv6c"] -[ext_resource type="Script" path="res://components/flag_carry_component.gd" id="1_b6ee8"] +[ext_resource type="Script" path="res://entities/components/flag_carry_component.gd" id="1_b6ee8"] [node name="FlagCarryComponent" type="Node3D"] script = ExtResource("1_b6ee8") diff --git a/components/health_component.gd b/entities/components/health_component.gd similarity index 84% rename from components/health_component.gd rename to entities/components/health_component.gd index 750b51a..9a07e95 100644 --- a/components/health_component.gd +++ b/entities/components/health_component.gd @@ -28,13 +28,13 @@ func _ready() -> void: heal_full() @rpc("call_local", "reliable") -func damage(amount : float, damage_dealer_id : int, damage_dealer_team_id : int) -> void: - if damage_dealer_team_id == _player.team_id: +func damage(amount : float, damage_dealer_player_id : int, damage_dealer_team_id : int) -> void: + if (damage_dealer_team_id == _player.team_id) and (damage_dealer_player_id != _player.player_id): return health = clampf(health - amount, 0.0, max_health) if health == 0.0: - health_zeroed.emit(damage_dealer_id) + health_zeroed.emit(damage_dealer_player_id) @rpc("call_local", "reliable") func _heal(amount : float) -> void: diff --git a/components/health_component.tscn b/entities/components/health_component.tscn similarity index 64% rename from components/health_component.tscn rename to entities/components/health_component.tscn index 6dd6121..5943234 100644 --- a/components/health_component.tscn +++ b/entities/components/health_component.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://bof3mg7wgxrmn"] -[ext_resource type="Script" path="res://components/health_component.gd" id="1_00xis"] +[ext_resource type="Script" path="res://entities/components/health_component.gd" id="1_00xis"] [node name="HealthComponent" type="Area3D"] collision_layer = 4 diff --git a/entities/player/player.tscn b/entities/player/player.tscn index f53ba92..9ed7cb5 100644 --- a/entities/player/player.tscn +++ b/entities/player/player.tscn @@ -5,10 +5,10 @@ [ext_resource type="Shape3D" uid="uid://cb8esdlnottdn" path="res://entities/player/collision_shape.tres" id="2_vjqny"] [ext_resource type="PackedScene" uid="uid://bcv81ku26xo" path="res://interfaces/hud/hud.tscn" id="3_ccety"] [ext_resource type="PackedScene" uid="uid://c8co0qa2omjmh" path="res://entities/weapons/space_gun/space_gun.tscn" id="4_6jh57"] -[ext_resource type="PackedScene" uid="uid://bof3mg7wgxrmn" path="res://components/health_component.tscn" id="5_t6i6e"] +[ext_resource type="PackedScene" uid="uid://bof3mg7wgxrmn" path="res://entities/components/health_component.tscn" id="4_jxn63"] [ext_resource type="Script" path="res://entities/player/player_input.gd" id="6_ymcrr"] [ext_resource type="PackedScene" uid="uid://dsysi2rd3bu76" path="res://interfaces/hud/iffs/iff.tscn" id="7_8hc80"] -[ext_resource type="PackedScene" uid="uid://2t8ql8pkxv6c" path="res://components/flag_carry_component.tscn" id="7_e7s1a"] +[ext_resource type="PackedScene" uid="uid://2t8ql8pkxv6c" path="res://entities/components/flag_carry_component.tscn" id="8_ej011"] [ext_resource type="PackedScene" uid="uid://d3l7fvbdg6m5g" path="res://entities/flag/assets/flag.glb" id="9_fce2y"] [ext_resource type="Script" path="res://addons/smoothing/smoothing.gd" id="11_k330l"] [ext_resource type="Texture2D" uid="uid://ct1v5iadtpadm" path="res://entities/player/assets/jetpackfx/smoke_01.png" id="12_ypuho"] @@ -240,7 +240,7 @@ shape = ExtResource("2_vjqny") [node name="HUD" parent="." instance=ExtResource("3_ccety")] -[node name="HealthComponent" parent="." node_paths=PackedStringArray("_player") instance=ExtResource("5_t6i6e")] +[node name="HealthComponent" parent="." node_paths=PackedStringArray("_player") instance=ExtResource("4_jxn63")] _player = NodePath("..") [node name="CollisionShape3D" type="CollisionShape3D" parent="HealthComponent"] @@ -285,7 +285,7 @@ holder = NodePath("../../../..") [node name="SpineIKTarget" type="Node3D" parent="Smoothing/SpringArm3D"] transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0) -[node name="FlagCarryComponent" parent="Smoothing/SpringArm3D" node_paths=PackedStringArray("sensor", "carrier") instance=ExtResource("7_e7s1a")] +[node name="FlagCarryComponent" parent="Smoothing/SpringArm3D" node_paths=PackedStringArray("sensor", "carrier") instance=ExtResource("8_ej011")] transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0.150603) visible = false sensor = NodePath("../../../Sensor") diff --git a/entities/target_dummy/target_dummy.tscn b/entities/target_dummy/target_dummy.tscn index 472bc8a..b87ef2b 100644 --- a/entities/target_dummy/target_dummy.tscn +++ b/entities/target_dummy/target_dummy.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://entities/target_dummy/target_dummy.gd" id="1_iup5v"] [ext_resource type="Shape3D" uid="uid://cb8esdlnottdn" path="res://entities/player/collision_shape.tres" id="2_i5k5j"] [ext_resource type="PackedScene" uid="uid://chuein4frnvwt" path="res://entities/target_dummy/assets/player_mesh.glb" id="4_fuync"] -[ext_resource type="PackedScene" uid="uid://bof3mg7wgxrmn" path="res://components/health_component.tscn" id="4_l1exy"] +[ext_resource type="PackedScene" uid="uid://bof3mg7wgxrmn" path="res://entities/components/health_component.tscn" id="4_l1exy"] [node name="DummyTarget" type="RigidBody3D"] collision_layer = 2147483649 diff --git a/entities/weapons/space_gun/projectile_explosion.tscn b/entities/weapons/space_gun/projectile_explosion.tscn index d1e26f0..1639644 100644 --- a/entities/weapons/space_gun/projectile_explosion.tscn +++ b/entities/weapons/space_gun/projectile_explosion.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=9 format=3 uid="uid://8atq41j7wd55"] [ext_resource type="Script" path="res://entities/weapons/space_gun/projectile_explosion.gd" id="1_fp5td"] -[ext_resource type="PackedScene" uid="uid://ds1hekx1dq1bg" path="res://components/explosive_damage_component.tscn" id="2_d4sf4"] +[ext_resource type="PackedScene" uid="uid://ds1hekx1dq1bg" path="res://entities/components/explosive_damage_component.tscn" id="2_d4sf4"] [sub_resource type="Curve" id="Curve_rg204"] _data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] diff --git a/maps/components/deathmatch_scoring_component.gd b/maps/components/deathmatch_scoring_component.gd new file mode 100644 index 0000000..2c069bb --- /dev/null +++ b/maps/components/deathmatch_scoring_component.gd @@ -0,0 +1,36 @@ +# 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 . +class_name DeathmatchScoringComponent extends Node + +@export var ON_KILL_SCORE : int = 10 + +# this is the node that contains all players, typically the one populated via MultiplayerSpawner +@export var _players : Node +@export var _scoreboard : Scoreboard + +# only subscribe once per player, per match +func subscribe_player(player : Player) -> void: + player.died.connect(_on_player_died) + +func unsubscribe_player(player : Player) -> void: + player.died.disconnect(_on_player_died) + +func _on_player_died(player : Player, killer_id : int) -> void: + if player.player_id != killer_id: + var node_name : String = str(killer_id) + if _players.has_node(node_name): + var killer : Player = _players.get_node(node_name) + _scoreboard.increment_kill_count(killer) + _scoreboard.add_score_to_player(killer, 10) diff --git a/maps/components/rabbit_scoring_component.gd b/maps/components/rabbit_scoring_component.gd new file mode 100644 index 0000000..215ef9a --- /dev/null +++ b/maps/components/rabbit_scoring_component.gd @@ -0,0 +1,53 @@ +# 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 . +class_name RabbitScoringComponent extends Node + +@export var ON_GRAB_SCORE : int = 10 +@export var ON_HOLD_SCORE : int = 10 +@export var HOLD_SCORING_TIMER : float = 10.0 # seconds + +@export var _scoreboard : Scoreboard + +var _flag_carrier_scoring_timer : Timer = Timer.new() +var _team_chasers : Team +var _team_rabbit : Team + +func _ready() -> void: + _flag_carrier_scoring_timer.wait_time = HOLD_SCORING_TIMER + add_child(_flag_carrier_scoring_timer) + _team_chasers = Team.new(0) + _team_rabbit = Team.new(1) + +# setup only once per match, per flag (tested only with one flag so far) +func setup(flag : Flag) -> void: + _flag_carrier_scoring_timer.timeout.connect(_on_flag_carrier_scoring_timer_timeout.bind(flag)) + flag.grabbed.connect(_on_flag_grabbed) + flag.regrabbed.connect(_on_flag_regrabbed) + flag.dropped.connect(_on_flag_dropped) + +func _on_flag_grabbed(grabber : Player) -> void: + grabber.team_id = _team_rabbit.team_id + _scoreboard.add_score_to_player(grabber, ON_GRAB_SCORE) + _flag_carrier_scoring_timer.start() + +func _on_flag_regrabbed(grabber : Player) -> void: + grabber.team_id = _team_rabbit.team_id + +func _on_flag_dropped(dropper : Player) -> void: + dropper.team_id = _team_chasers.team_id + _flag_carrier_scoring_timer.stop() + +func _on_flag_carrier_scoring_timer_timeout(flag : Flag) -> void: + _scoreboard.add_score_to_player(flag.last_carrier, ON_HOLD_SCORE) diff --git a/modes/multiplayer.gd b/modes/multiplayer.gd index 0741b61..f249179 100644 --- a/modes/multiplayer.gd +++ b/modes/multiplayer.gd @@ -26,24 +26,10 @@ class_name Multiplayer extends Node @onready var scoreboard : Scoreboard = $Scoreboard var _map_manager : Map -var _flag : Flag -var _flag_carrier_scoring_timer : Timer = Timer.new() - -var team_chasers : Team -var team_rabbit : Team signal connected_to_server signal connection_failed -func _ready() -> void: - _flag_carrier_scoring_timer.wait_time = 10.0 - _flag_carrier_scoring_timer.timeout.connect(_on_flag_carrier_scoring_timer_timeout) - add_child(_flag_carrier_scoring_timer) - team_chasers = Team.new() - team_chasers.team_id = 0 - team_rabbit = Team.new() - team_rabbit.team_id = 1 - func start_server(config : Dictionary) -> void: # Check if required parameters are missing var required_params : Array[String] = ["port", "map", "nickname"] @@ -74,13 +60,7 @@ func _on_connected_to_server(nickname : String) -> void: func _on_connection_failed() -> void: connection_failed.emit() -func _on_player_died(player : Player, killer_id : int) -> void: - if player.player_id != killer_id: - var node_name : String = str(killer_id) - if players.has_node(node_name): - var killer : Player = players.get_node(node_name) - scoreboard.increment_kill_count(killer) - scoreboard.add_score_to_player(killer, 10) +func _on_player_died(player : Player, _killer_id : int) -> void: await get_tree().create_timer(RESPAWN_TIME).timeout respawn_player(player) @@ -92,11 +72,12 @@ func add_player(peer_id : int, nickname : String) -> void: var player : Player = PLAYER.instantiate() player.name = str(peer_id) player.player_id = peer_id - player.team_id = team_chasers.team_id + player.team_id = ($RabbitScoringComponent as RabbitScoringComponent)._team_chasers.team_id player.nickname = nickname - player.global_position = _map_manager.get_player_spawn().position players.add_child(player) + player.global_position = _map_manager.get_player_spawn().position player.died.connect(_on_player_died) + $DeathmatchScoringComponent.subscribe_player(player) scoreboard.add_player(player) print("Peer `%s` connected" % player.name) @@ -106,45 +87,29 @@ func remove_player(peer_id : int) -> void: var player : Player = players.get_node(node_name) scoreboard.remove_player(player) player.died.disconnect(_on_player_died) + $DeathmatchScoringComponent.unsubscribe_player(player) player.queue_free() print("Peer `%s` disconnected" % node_name) func _load_map(scene : PackedScene, nickname : String) -> void: var map_scene : Node = scene.instantiate() - _map_manager = map_scene map_scene.ready.connect(_add_flag) + _map_manager = map_scene + map.add_child(map_scene) if DisplayServer.get_name() != "headless": add_player(1, nickname) - map.add_child(map_scene) func _add_flag() -> void: - _flag = FLAG.instantiate() - _flag.grabbed.connect(_on_flag_grabbed) - _flag.regrabbed.connect(_on_flag_regrabbed) - _flag.dropped.connect(_on_flag_dropped) - _flag.global_position = _map_manager.get_flagstand().global_position - objectives.add_child(_flag) + var flag : Flag = FLAG.instantiate() + $RabbitScoringComponent.setup(flag) + objectives.add_child(flag) + flag.global_position = _map_manager.get_flagstand().global_position @rpc("any_peer", "reliable") func _join_match(nickname : String) -> void: if is_multiplayer_authority(): add_player(multiplayer.get_remote_sender_id(), nickname) -func _on_flag_grabbed(grabber : Player) -> void: - grabber.team_id = team_rabbit.team_id - scoreboard.add_score_to_player(grabber, 10) - _flag_carrier_scoring_timer.start() - -func _on_flag_regrabbed(grabber : Player) -> void: - grabber.team_id = team_rabbit.team_id - -func _on_flag_dropped(dropper : Player) -> void: - dropper.team_id = team_chasers.team_id - _flag_carrier_scoring_timer.stop() - -func _on_flag_carrier_scoring_timer_timeout() -> void: - scoreboard.add_score_to_player(_flag.last_carrier, 10) - func _exit_tree() -> void: if is_multiplayer_authority(): multiplayer.peer_disconnected.disconnect(remove_player) diff --git a/modes/multiplayer.tscn b/modes/multiplayer.tscn index bf5c98c..4bd355f 100644 --- a/modes/multiplayer.tscn +++ b/modes/multiplayer.tscn @@ -1,9 +1,11 @@ -[gd_scene load_steps=5 format=3 uid="uid://bvwxfgygm2xb8"] +[gd_scene load_steps=7 format=3 uid="uid://bvwxfgygm2xb8"] [ext_resource type="Script" path="res://modes/multiplayer.gd" id="1_r1kd6"] [ext_resource type="PackedScene" uid="uid://cbhx1xme0sb7k" path="res://entities/player/player.tscn" id="2_og1vb"] [ext_resource type="PackedScene" uid="uid://c88l3h0ph00c7" path="res://entities/flag/flag.tscn" id="3_h0rie"] +[ext_resource type="Script" path="res://maps/components/rabbit_scoring_component.gd" id="5_7woao"] [ext_resource type="PackedScene" uid="uid://b8bosdd0o1lu7" path="res://interfaces/scoreboard/scoreboard.tscn" id="5_uj0pp"] +[ext_resource type="Script" path="res://maps/components/deathmatch_scoring_component.gd" id="6_iov4u"] [node name="Multiplayer" type="Node"] script = ExtResource("1_r1kd6") @@ -31,3 +33,12 @@ spawn_path = NodePath("../Objectives") [node name="Scoreboard" parent="." instance=ExtResource("5_uj0pp")] visible = false + +[node name="RabbitScoringComponent" type="Node" parent="." node_paths=PackedStringArray("_scoreboard")] +script = ExtResource("5_7woao") +_scoreboard = NodePath("../Scoreboard") + +[node name="DeathmatchScoringComponent" type="Node" parent="." node_paths=PackedStringArray("_players", "_scoreboard")] +script = ExtResource("6_iov4u") +_players = NodePath("../Players") +_scoreboard = NodePath("../Scoreboard") diff --git a/modes/team.gd b/modes/team.gd index 2bcfc84..e49c853 100644 --- a/modes/team.gd +++ b/modes/team.gd @@ -1,3 +1,6 @@ class_name Team extends Object var team_id : int + +func _init(id : int) -> void: + team_id = id