diff --git a/Code/Factories/ComponentFactory.cs b/Code/Factories/ComponentFactory.cs index 0a109ba..3d5a703 100644 --- a/Code/Factories/ComponentFactory.cs +++ b/Code/Factories/ComponentFactory.cs @@ -9,6 +9,7 @@ using GameCore.ECS.Interfaces; using GameCore.Input; using GameCore.Interaction; using GameCore.Inventory; +using GameCore.Logic; using GameCore.Movement; using GameCore.Physics; using GameCore.Player; @@ -21,11 +22,13 @@ public class ComponentFactory private readonly Dictionary> _factories = new(); private readonly EffectFactory _effectFactory; private readonly InteractionRequirementFactory _requirementFactory; + private readonly TriggerActionFactory _triggerActionFactory; - public ComponentFactory(EffectFactory effectFactory, InteractionRequirementFactory requirementFactory) + public ComponentFactory(EffectFactory effectFactory, InteractionRequirementFactory requirementFactory, TriggerActionFactory triggerActionFactory) { _effectFactory = effectFactory; _requirementFactory = requirementFactory; + _triggerActionFactory = triggerActionFactory; Register(CreateAttributeComponent); Register(CreateWeaponComponent); @@ -40,6 +43,9 @@ public class ComponentFactory Register(CreatePickupComponent); Register(_ => new EquipmentComponent()); Register(CreateDoorComponent); + Register(res => new WorldIdComponent(res.WorldId)); + Register(CreateButtonComponent); + Register(CreateLogicSequenceComponent); } public IComponent Create(Resource resource) @@ -129,4 +135,47 @@ public class ComponentFactory return component; } + + private ButtonComponent CreateButtonComponent(ButtonComponentResource resource) + { + var component = new ButtonComponent + { + ChannelId = resource.ChannelId, + IsToggle = resource.IsToggle, + IsOneTimeUse = resource.IsOneTimeUse, + IsPressed = false, + HasBeenUsed = false, + }; + + foreach (var reqResource in resource.Requirements) + { + var requirement = _requirementFactory.Create(reqResource); + if (requirement != null) + { + component.Requirements.Add(requirement); + } + } + + return component; + } + + private LogicSequenceComponent CreateLogicSequenceComponent(LogicSequenceComponentResource resource) + { + var component = new LogicSequenceComponent + { + RequiredChannels = resource.RequiredChannels.ToList(), + IsOneTimeTrigger = resource.IsOneTimeTrigger, + }; + + foreach (var actionResource in resource.OnCompleteActions) + { + var action = _triggerActionFactory.Create(actionResource); + if (action != null) + { + component.OnCompleteActions.Add(action); + } + } + + return component; + } } \ No newline at end of file diff --git a/Code/Factories/TriggerActionFactory.cs b/Code/Factories/TriggerActionFactory.cs new file mode 100644 index 0000000..a9c832f --- /dev/null +++ b/Code/Factories/TriggerActionFactory.cs @@ -0,0 +1,21 @@ +using System; +using CryptonymThunder.Code.Resources; +using GameCore.Logic; +using GameCore.Logic.Interfaces; + +namespace CryptonymThunder.Code.Factories; + +public class TriggerActionFactory +{ + public ITriggerAction Create(TriggerActionResource resource) + { + return resource switch + { + UnlockDoorActionResource unlock => new UnlockDoorAction(unlock.TargetWorldId), + SpawnEntityActionResource spawn => new SpawnEntityAction(spawn.ArchetypeId, spawn.SpawnerWorldId), + DebugMessageActionResource debug => new DebugMessageAction(debug.Message), + _ => throw new ArgumentOutOfRangeException(nameof(resource), + $"TriggerAction type {resource.GetType().Name} not recognized") + }; + } +} \ No newline at end of file diff --git a/Code/Factories/TriggerActionFactory.cs.uid b/Code/Factories/TriggerActionFactory.cs.uid new file mode 100644 index 0000000..9d94922 --- /dev/null +++ b/Code/Factories/TriggerActionFactory.cs.uid @@ -0,0 +1 @@ +uid://jjayuu6hrfqj diff --git a/Code/Presenters/GamePresenter.cs b/Code/Presenters/GamePresenter.cs index 64b9619..4d47873 100644 --- a/Code/Presenters/GamePresenter.cs +++ b/Code/Presenters/GamePresenter.cs @@ -15,6 +15,7 @@ using GameCore.Interaction; using GameCore.Inventory; using GameCore.Logging; using GameCore.Logging.Interfaces; +using GameCore.Logic; using GameCore.Movement; using GameCore.Player; using Godot; @@ -64,7 +65,8 @@ public partial class GamePresenter : Node var effectFactory = new EffectFactory(); var requirementFactory = new InteractionRequirementFactory(); - var componentFactory = new ComponentFactory(effectFactory, requirementFactory); + var triggerActionFactory = new TriggerActionFactory(); + var componentFactory = new ComponentFactory(effectFactory, requirementFactory, triggerActionFactory); var weaponDataService = new GodotWeaponDataService(WeaponDatabase, effectFactory); _presenterFactory = new PresenterFactory(_world, componentFactory, _presenterRegistry, this); @@ -85,6 +87,7 @@ public partial class GamePresenter : Node _world.RegisterSystem(new InteractionSystem(InteractionRange)); _world.RegisterSystem(new DoorSystem()); + _world.RegisterSystem(new LogicSequenceSystem(_world)); _world.RegisterSystem(new WeaponSystem()); _world.RegisterSystem(new ProjectileSystem()); diff --git a/Code/Presenters/HudPresenterComponent.cs b/Code/Presenters/HudPresenterComponent.cs index c0aa35f..08e7721 100644 --- a/Code/Presenters/HudPresenterComponent.cs +++ b/Code/Presenters/HudPresenterComponent.cs @@ -125,10 +125,12 @@ public partial class HudPresenterComponent : Control, IPresenterComponent var lookingAt = _world.GetComponent(_playerEntity); if (lookingAt != null) { - var door = _world.GetComponent(lookingAt.Target); + var targetEntity = lookingAt.Target; + var interactKey = "F"; + + var door = _world.GetComponent(targetEntity); if (door != null) { - var interactKey = "F"; _interactLabel.Text = door.CurrentState switch { DoorComponent.DoorState.Locked => $"[{interactKey}] Interact (Locked)", @@ -140,7 +142,26 @@ public partial class HudPresenterComponent : Control, IPresenterComponent } else { - _interactLabel.Visible = false; + var button = _world.GetComponent(targetEntity); + if (button != null) + { + if (button.IsOneTimeUse && button.HasBeenUsed) + { + _interactLabel.Text = "(Used)"; + } + else if (button.IsToggle) + { + _interactLabel.Text = button.IsPressed ? $"[{interactKey}] Deactivate" : $"[{interactKey}] Activate"; + } + else + { + _interactLabel.Text = $"[{interactKey}] Press Button"; + } + _interactLabel.Visible = true; + } else + { + _interactLabel.Visible = false; + } } } else diff --git a/Code/Resources/ButtonComponentResource.cs b/Code/Resources/ButtonComponentResource.cs new file mode 100644 index 0000000..1017fcd --- /dev/null +++ b/Code/Resources/ButtonComponentResource.cs @@ -0,0 +1,15 @@ +using Godot; +using Godot.Collections; + +namespace CryptonymThunder.Code.Resources; + +[GlobalClass] +public partial class ButtonComponentResource : Resource +{ + [Export] public string ChannelId { get; set; } = "default_channel"; + [Export] public bool IsToggle { get; set; } = false; + [Export] public bool IsOneTimeUse { get; set; } = false; + + [ExportGroup("Requirements")] + [Export] public Array Requirements { get; set; } = []; +} \ No newline at end of file diff --git a/Code/Resources/ButtonComponentResource.cs.uid b/Code/Resources/ButtonComponentResource.cs.uid new file mode 100644 index 0000000..df05ef9 --- /dev/null +++ b/Code/Resources/ButtonComponentResource.cs.uid @@ -0,0 +1 @@ +uid://cc1okvlx8p0tr diff --git a/Code/Resources/DebugMessageActionResource.cs b/Code/Resources/DebugMessageActionResource.cs new file mode 100644 index 0000000..7467783 --- /dev/null +++ b/Code/Resources/DebugMessageActionResource.cs @@ -0,0 +1,9 @@ +using Godot; + +namespace CryptonymThunder.Code.Resources; + +[GlobalClass] +public partial class DebugMessageActionResource : TriggerActionResource +{ + [Export(PropertyHint.MultilineText)] public string Message { get; set; } = "Trigger Fired!"; +} \ No newline at end of file diff --git a/Code/Resources/DebugMessageActionResource.cs.uid b/Code/Resources/DebugMessageActionResource.cs.uid new file mode 100644 index 0000000..10a8577 --- /dev/null +++ b/Code/Resources/DebugMessageActionResource.cs.uid @@ -0,0 +1 @@ +uid://duqvidui7v7bk diff --git a/Code/Resources/LogicSequenceComponentResource.cs b/Code/Resources/LogicSequenceComponentResource.cs new file mode 100644 index 0000000..869a8a6 --- /dev/null +++ b/Code/Resources/LogicSequenceComponentResource.cs @@ -0,0 +1,12 @@ +using Godot; +using Godot.Collections; + +namespace CryptonymThunder.Code.Resources; + +[GlobalClass] +public partial class LogicSequenceComponentResource : Resource +{ + [Export] public Array RequiredChannels { get; set; } = []; + [Export] public Array OnCompleteActions { get; set; } = []; + [Export] public bool IsOneTimeTrigger { get; set; } = true; +} \ No newline at end of file diff --git a/Code/Resources/LogicSequenceComponentResource.cs.uid b/Code/Resources/LogicSequenceComponentResource.cs.uid new file mode 100644 index 0000000..8ded3b6 --- /dev/null +++ b/Code/Resources/LogicSequenceComponentResource.cs.uid @@ -0,0 +1 @@ +uid://c4csquqmqqqww diff --git a/Code/Resources/SpawnEntityActionResource.cs b/Code/Resources/SpawnEntityActionResource.cs new file mode 100644 index 0000000..9b19b1d --- /dev/null +++ b/Code/Resources/SpawnEntityActionResource.cs @@ -0,0 +1,10 @@ +using Godot; + +namespace CryptonymThunder.Code.Resources; + +[GlobalClass] +public partial class SpawnEntityActionResource : TriggerActionResource +{ + [Export] public string ArchetypeId { get; set; } = "enemy_grunt"; + [Export] public string SpawnerWorldId { get; set; } = "spawner_location_1"; +} \ No newline at end of file diff --git a/Code/Resources/SpawnEntityActionResource.cs.uid b/Code/Resources/SpawnEntityActionResource.cs.uid new file mode 100644 index 0000000..4d88a01 --- /dev/null +++ b/Code/Resources/SpawnEntityActionResource.cs.uid @@ -0,0 +1 @@ +uid://crcl8s0sk5ye4 diff --git a/Code/Resources/TriggerActionResource.cs b/Code/Resources/TriggerActionResource.cs new file mode 100644 index 0000000..ebb006d --- /dev/null +++ b/Code/Resources/TriggerActionResource.cs @@ -0,0 +1,8 @@ +using Godot; + +namespace CryptonymThunder.Code.Resources; + +public partial class TriggerActionResource : Resource +{ + +} \ No newline at end of file diff --git a/Code/Resources/TriggerActionResource.cs.uid b/Code/Resources/TriggerActionResource.cs.uid new file mode 100644 index 0000000..8e20234 --- /dev/null +++ b/Code/Resources/TriggerActionResource.cs.uid @@ -0,0 +1 @@ +uid://nygfwfh0v684 diff --git a/Code/Resources/UnlockDoorActionResource.cs b/Code/Resources/UnlockDoorActionResource.cs new file mode 100644 index 0000000..7ca1608 --- /dev/null +++ b/Code/Resources/UnlockDoorActionResource.cs @@ -0,0 +1,9 @@ +using Godot; + +namespace CryptonymThunder.Code.Resources; + +[GlobalClass] +public partial class UnlockDoorActionResource : TriggerActionResource +{ + [Export] public string TargetWorldId { get; set; } = "door_to_unlock"; +} \ No newline at end of file diff --git a/Code/Resources/UnlockDoorActionResource.cs.uid b/Code/Resources/UnlockDoorActionResource.cs.uid new file mode 100644 index 0000000..4851e33 --- /dev/null +++ b/Code/Resources/UnlockDoorActionResource.cs.uid @@ -0,0 +1 @@ +uid://cgsqrgdok7ovp diff --git a/Code/Resources/WorldIdComponentResource.cs b/Code/Resources/WorldIdComponentResource.cs new file mode 100644 index 0000000..96dda89 --- /dev/null +++ b/Code/Resources/WorldIdComponentResource.cs @@ -0,0 +1,9 @@ +using Godot; + +namespace CryptonymThunder.Code.Resources; + +[GlobalClass] +public partial class WorldIdComponentResource : Resource +{ + [Export] public string WorldId { get; set; } = "unique_id_01"; +} \ No newline at end of file diff --git a/Code/Resources/WorldIdComponentResource.cs.uid b/Code/Resources/WorldIdComponentResource.cs.uid new file mode 100644 index 0000000..bbfa824 --- /dev/null +++ b/Code/Resources/WorldIdComponentResource.cs.uid @@ -0,0 +1 @@ +uid://rd33g3u352g6 diff --git a/Objects/green_door.tscn b/Objects/green_door.tscn index 9691da2..e70ddb1 100644 --- a/Objects/green_door.tscn +++ b/Objects/green_door.tscn @@ -3,8 +3,8 @@ [ext_resource type="Script" uid="uid://bxqite0b1di2b" path="res://Code/Presenters/DoorPresenter.cs" id="1_0k8gl"] [ext_resource type="Script" uid="uid://cratjw4trngpr" path="res://Code/Resources/LerpDoorBehavior.cs" id="2_3dbp0"] [ext_resource type="Script" uid="uid://b6x8llipvutqs" path="res://Code/Presenters/SceneEntity.cs" id="2_l5dry"] -[ext_resource type="Script" uid="uid://dnyfoaprv6bhw" path="res://Code/Resources/RequiresItemRequirementResource.cs" id="3_3dbp0"] [ext_resource type="Script" uid="uid://ymtyxkea76mv" path="res://Code/Resources/DoorComponentResource.cs" id="4_g4ryb"] +[ext_resource type="Script" uid="uid://rd33g3u352g6" path="res://Code/Resources/WorldIdComponentResource.cs" id="6_g4ryb"] [sub_resource type="Resource" id="Resource_3dbp0"] script = ExtResource("2_3dbp0") @@ -21,16 +21,17 @@ albedo_color = Color(0.14891627, 0.744422, 0, 1) [sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_l5dry"] points = PackedVector3Array(-0.5, -1, -0.15, -0.5, -1, 0.15, -0.5, 1, -0.15, 0.5, -1, -0.15, 0.5, -1, 0.15, -0.5, 1, 0.15, 0.5, 1, -0.15, 0.5, 1, 0.15) -[sub_resource type="Resource" id="Resource_g2hal"] -script = ExtResource("3_3dbp0") -metadata/_custom_type_script = "uid://dnyfoaprv6bhw" - [sub_resource type="Resource" id="Resource_fyehb"] script = ExtResource("4_g4ryb") InitialState = 0 -Requirements = Array[Object]([SubResource("Resource_g2hal")]) +Requirements = Array[Object]([]) metadata/_custom_type_script = "uid://ymtyxkea76mv" +[sub_resource type="Resource" id="Resource_rv1pd"] +script = ExtResource("6_g4ryb") +WorldId = "green_door" +metadata/_custom_type_script = "uid://rd33g3u352g6" + [node name="GreenDoor" type="CharacterBody3D"] script = ExtResource("1_0k8gl") _behavior = SubResource("Resource_3dbp0") @@ -44,5 +45,5 @@ shape = SubResource("ConvexPolygonShape3D_l5dry") [node name="SceneEntity" type="Node" parent="." groups=["SceneEntities"]] script = ExtResource("2_l5dry") -ComponentResources = Array[Resource]([SubResource("Resource_fyehb")]) +ComponentResources = Array[Resource]([SubResource("Resource_fyehb"), SubResource("Resource_rv1pd")]) metadata/_custom_type_script = "uid://b6x8llipvutqs" diff --git a/Objects/green_door_button.tscn b/Objects/green_door_button.tscn new file mode 100644 index 0000000..00ad8fc --- /dev/null +++ b/Objects/green_door_button.tscn @@ -0,0 +1,35 @@ +[gd_scene load_steps=8 format=3 uid="uid://bjbsk8nhi5e4i"] + +[ext_resource type="Script" uid="uid://cb7vaw6xqjs1i" path="res://Code/Presenters/EntityPresenter.cs" id="1_qhhav"] +[ext_resource type="Script" uid="uid://b6x8llipvutqs" path="res://Code/Presenters/SceneEntity.cs" id="2_apu07"] +[ext_resource type="Script" uid="uid://cc1okvlx8p0tr" path="res://Code/Resources/ButtonComponentResource.cs" id="3_8x8af"] + +[sub_resource type="BoxMesh" id="BoxMesh_kgm0y"] +size = Vector3(0.1, 0.1, 0.1) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_o42jp"] +albedo_color = Color(0.20152658, 0.20152658, 0.20152658, 1) + +[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_qhhav"] +points = PackedVector3Array(-0.049999997, -0.04999998, -0.04999998, 0.049997684, 0.049999997, 0.049999997, 0.049997684, 0.049999997, -0.049999997, 0.049997684, -0.049999997, 0.049999997, -0.049999997, 0.04999998, 0.04999998, 0.049997684, -0.049999997, -0.049999997, -0.049999997, 0.04999998, -0.04999998, -0.049999997, -0.04999998, 0.04999998) + +[sub_resource type="Resource" id="Resource_nak1n"] +script = ExtResource("3_8x8af") +ChannelId = "green_door_button" +Requirements = null +metadata/_custom_type_script = "uid://cc1okvlx8p0tr" + +[node name="Button" type="StaticBody3D"] +script = ExtResource("1_qhhav") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +mesh = SubResource("BoxMesh_kgm0y") +surface_material_override/0 = SubResource("StandardMaterial3D_o42jp") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("ConvexPolygonShape3D_qhhav") + +[node name="SceneEntity" type="Node" parent="." groups=["SceneEntities"]] +script = ExtResource("2_apu07") +ComponentResources = Array[Resource]([SubResource("Resource_nak1n")]) +metadata/_custom_type_script = "uid://b6x8llipvutqs" diff --git a/Scenes/game_world.tscn b/Scenes/game_world.tscn index 2d6b794..ec600d4 100644 --- a/Scenes/game_world.tscn +++ b/Scenes/game_world.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=27 format=4 uid="uid://bkvgcsb8d3v7p"] +[gd_scene load_steps=32 format=4 uid="uid://bkvgcsb8d3v7p"] [ext_resource type="Script" uid="uid://cfpm5p102f65x" path="res://Code/Presenters/GamePresenter.cs" id="1_qvgq0"] [ext_resource type="Resource" uid="uid://biev6ri5s8kyf" path="res://Resources/Entities/player.tres" id="2_alii3"] @@ -14,6 +14,9 @@ [ext_resource type="PackedScene" uid="uid://bfnu4py7n2sv5" path="res://Objects/pistol_pickup.tscn" id="12_00aki"] [ext_resource type="PackedScene" uid="uid://b1d2gc8goj6gx" path="res://Objects/green_door.tscn" id="13_00aki"] [ext_resource type="PackedScene" uid="uid://cww3lcsxldnt3" path="res://Objects/green_card_pickup.tscn" id="14_5qvjo"] +[ext_resource type="PackedScene" uid="uid://bjbsk8nhi5e4i" path="res://Objects/green_door_button.tscn" id="15_g7kif"] +[ext_resource type="Script" uid="uid://cgsqrgdok7ovp" path="res://Code/Resources/UnlockDoorActionResource.cs" id="16_vpkaq"] +[ext_resource type="Script" uid="uid://c4csquqmqqqww" path="res://Code/Resources/LogicSequenceComponentResource.cs" id="17_df4ul"] [sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_ucfah"] data = PackedVector3Array(-4.282257, -0.5, 4.977783, -4.282257, -0.5, -4.977783, -4.282257, 0.5, -4.977783, 4.282257, -0.5, -4.977783, -4.282257, -0.5, -4.977783, -4.282257, -0.5, 4.977783, -4.282257, 0.5, -4.977783, -4.282257, -0.5, -4.977783, 4.282257, -0.5, -4.977783, -4.282257, 0.5, -4.977783, -4.282257, 0.5, 4.977783, -4.282257, -0.5, 4.977783, -4.282257, -0.5, 4.977783, -4.282257, 0.5, 4.977783, 4.282257, 0.5, 4.977783, 4.282257, 0.5, 4.977783, -4.282257, 0.5, 4.977783, -4.282257, 0.5, -4.977783, -4.282257, -0.5, 4.977783, 4.282257, -0.5, 4.977783, 4.282257, -0.5, -4.977783, 4.282257, 0.5, 4.977783, 4.282257, -0.5, 4.977783, -4.282257, -0.5, 4.977783, 4.282257, -0.5, -4.977783, 4.282257, -0.5, 4.977783, 4.282257, 0.5, 4.977783, 4.282257, -0.5, -4.977783, 4.282257, 0.5, -4.977783, -4.282257, 0.5, -4.977783, -4.282257, 0.5, -4.977783, 4.282257, 0.5, -4.977783, 4.282257, 0.5, 4.977783, 4.282257, 0.5, 4.977783, 4.282257, 0.5, -4.977783, 4.282257, -0.5, -4.977783) @@ -65,6 +68,17 @@ BaseValues = Dictionary[int, float]({ }) metadata/_custom_type_script = "uid://dc7wq2ij5kwj5" +[sub_resource type="Resource" id="Resource_q0a86"] +script = ExtResource("16_vpkaq") +TargetWorldId = "green_door" +metadata/_custom_type_script = "uid://cgsqrgdok7ovp" + +[sub_resource type="Resource" id="Resource_3hp7m"] +script = ExtResource("17_df4ul") +RequiredChannels = Array[String](["green_door_button"]) +OnCompleteActions = Array[Resource]([SubResource("Resource_q0a86")]) +metadata/_custom_type_script = "uid://c4csquqmqqqww" + [node name="GameWorld" type="Node3D"] [node name="Geometry" type="Node" parent="."] @@ -251,6 +265,19 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.7087288, -0.8145535, 4.614 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.122588, -0.81455374, 1.582226) [node name="GreenDoor" parent="." instance=ExtResource("13_00aki")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.8655286, -0.0645535, 5.593994) [node name="Green Card Pickup" parent="." instance=ExtResource("14_5qvjo")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.2713692, -0.86455375, 3.3032908) + +[node name="DoorButton" parent="." instance=ExtResource("15_g7kif")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.097641, 0.08375314, 4.357219) + +[node name="DoorLogic" type="Node3D" parent="."] +script = ExtResource("5_d0bjv") +metadata/_custom_type_script = "uid://cb7vaw6xqjs1i" + +[node name="SceneEntity" type="Node" parent="DoorLogic" groups=["SceneEntities"]] +script = ExtResource("5_f1ejf") +ComponentResources = Array[Resource]([SubResource("Resource_3hp7m")]) +metadata/_custom_type_script = "uid://b6x8llipvutqs"