diff --git a/Assets/Scripts/Core/GameManager.cs b/Assets/Scripts/Core/GameManager.cs index 3701cfa3..84f03721 100644 --- a/Assets/Scripts/Core/GameManager.cs +++ b/Assets/Scripts/Core/GameManager.cs @@ -50,7 +50,7 @@ public class GameManager : MonoBehaviour public float ManualMoveSmooth => gameSettings != null ? gameSettings.manualMoveSmooth : 8f; public float ThresholdFar => gameSettings != null ? gameSettings.thresholdFar : 2.5f; public float ThresholdNear => gameSettings != null ? gameSettings.thresholdNear : 0.5f; - public float StopThreshold => gameSettings != null ? gameSettings.stopThreshold : 0.1f; + public float StopThreshold => gameSettings != null ? gameSettings.stopThreshold : 0.5f; public float MoveSpeed => gameSettings != null ? gameSettings.moveSpeed : 5f; public float StopDistance => gameSettings != null ? gameSettings.stopDistance : 0.1f; public bool UseRigidbody => gameSettings != null ? gameSettings.useRigidbody : true; diff --git a/Assets/Scripts/Data.meta b/Assets/Scripts/Data.meta new file mode 100644 index 00000000..85e71fb9 --- /dev/null +++ b/Assets/Scripts/Data.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e0b15b90103942c3b0e630462ecc5de1 +timeCreated: 1757518020 \ No newline at end of file diff --git a/Assets/Scripts/Data/ItemCombinationManager.cs b/Assets/Scripts/Data/ItemCombinationManager.cs new file mode 100644 index 00000000..e02abfc9 --- /dev/null +++ b/Assets/Scripts/Data/ItemCombinationManager.cs @@ -0,0 +1 @@ + diff --git a/Assets/Scripts/Data/ItemCombinationManager.cs.meta b/Assets/Scripts/Data/ItemCombinationManager.cs.meta new file mode 100644 index 00000000..8d07764a --- /dev/null +++ b/Assets/Scripts/Data/ItemCombinationManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a54fc1a3945f46c580a83e74f9436526 +timeCreated: 1757518020 \ No newline at end of file diff --git a/Assets/Scripts/Interactions/CombineWithBehavior.cs b/Assets/Scripts/Interactions/CombineWithBehavior.cs index 70638d52..8aa1247c 100644 --- a/Assets/Scripts/Interactions/CombineWithBehavior.cs +++ b/Assets/Scripts/Interactions/CombineWithBehavior.cs @@ -13,7 +13,7 @@ public class CombineWithBehavior : InteractionRequirementBase /// True if the combination was successful, false otherwise. public override bool TryInteract(FollowerController follower) { - var heldItem = follower.CurrentlyHeldItem; + var heldItem = follower.GetHeldPickupObject(); var pickup = GetComponent(); if (heldItem == null) { @@ -27,36 +27,17 @@ public class CombineWithBehavior : InteractionRequirementBase OnFailure?.Invoke(); return false; } - var rule = GameManager.Instance.GetCombinationRule(heldItem, pickup.itemData); - if (rule != null && rule.resultPrefab != null) + var combinedItem = InteractionOrchestrator.Instance.CombineItems(heldItem, pickup.gameObject); + if (combinedItem != null) { - // Instantiate the result prefab at the pickup's position - var resultObj = GameObject.Instantiate(rule.resultPrefab, pickup.transform.position, Quaternion.identity); - var resultPickup = resultObj.GetComponent(); - if (resultPickup != null) - { - // Hide and parent to follower - resultObj.SetActive(false); - resultObj.transform.SetParent(follower.transform); - // Set held item and icon from the spawned prefab - follower.SetHeldItem(resultPickup.itemData, resultPickup.iconRenderer); - // Cache the spawned object as the held item - follower.CacheHeldPickupObject(resultObj); - follower.justCombined = true; - OnSuccess?.Invoke(); - return true; - } - else - { - Debug.LogWarning("Result prefab does not have a Pickup component."); - GameObject.Destroy(resultObj); - OnFailure?.Invoke(); - return false; - } + InteractionOrchestrator.Instance.PickupItem(follower, combinedItem); + follower.justCombined = true; + OnSuccess?.Invoke(); + return true; } else { - // DebugUIMessage.Show($"Cannot combine {heldItem.itemName ?? \"an item\"} with {pickup.itemData.itemName ?? \"target item\"}."); + // DebugUIMessage.Show($"Cannot combine {follower.CurrentlyHeldItem?.itemName ?? "an item"} with {pickup.itemData.itemName ?? "target item"}."); OnFailure?.Invoke(); return true; } diff --git a/Assets/Scripts/Interactions/InteractionOrchestrator.cs b/Assets/Scripts/Interactions/InteractionOrchestrator.cs index 3621e793..8899092e 100644 --- a/Assets/Scripts/Interactions/InteractionOrchestrator.cs +++ b/Assets/Scripts/Interactions/InteractionOrchestrator.cs @@ -151,4 +151,68 @@ public class InteractionOrchestrator : MonoBehaviour interactable.CompleteInteraction(false); } } + + // --- ITEM MANAGEMENT API --- + public void PickupItem(FollowerController follower, GameObject item) + { + if (item == null || follower == null) return; + item.SetActive(false); + item.transform.SetParent(null); + follower.SetHeldItemFromObject(item); + // Optionally: fire event, update UI, etc. + } + + public void DropItem(FollowerController follower, Vector3 position) + { + var item = follower.GetHeldPickupObject(); + if (item == null) return; + item.transform.position = position; + item.transform.SetParent(null); + item.SetActive(true); + follower.ClearHeldItem(); + // Optionally: fire event, update UI, etc. + } + + public void SlotItem(SlotItemBehavior slot, GameObject item) + { + if (slot == null || item == null) return; + item.SetActive(false); + item.transform.SetParent(null); + slot.SetSlottedObject(item); + // Optionally: update visuals, fire event, etc. + } + + public void SwapItems(FollowerController follower, SlotItemBehavior slot) + { + var heldObj = follower.GetHeldPickupObject(); + var slotObj = slot.GetSlottedObject(); + // 1. Slot the follower's held object + SlotItem(slot, heldObj); + // 2. Give the slot's object to the follower + PickupItem(follower, slotObj); + } + + public GameObject CombineItems(GameObject itemA, GameObject itemB) + { + if (itemA == null || itemB == null) return null; + var pickupA = itemA.GetComponent(); + var pickupB = itemB.GetComponent(); + if (pickupA == null || pickupB == null) { + if (itemA != null) Destroy(itemA); + if (itemB != null) Destroy(itemB); + return null; + } + var rule = GameManager.Instance.GetCombinationRule(pickupA.itemData, pickupB.itemData); + Vector3 spawnPos = itemA.transform.position; + if (rule != null && rule.resultPrefab != null) { + var newItem = Instantiate(rule.resultPrefab, spawnPos, Quaternion.identity); + Destroy(itemA); + Destroy(itemB); + return newItem; + } + // If no combination found, just destroy both + Destroy(itemA); + Destroy(itemB); + return null; + } } diff --git a/Assets/Scripts/Interactions/SlotItemBehavior.cs b/Assets/Scripts/Interactions/SlotItemBehavior.cs index e45b3012..9189e40d 100644 --- a/Assets/Scripts/Interactions/SlotItemBehavior.cs +++ b/Assets/Scripts/Interactions/SlotItemBehavior.cs @@ -21,8 +21,12 @@ public class SlotItemBehavior : InteractionRequirementBase private GameObject _cachedSlottedObject = null; - // Helper for slotting an object, with option to skip destruction (for swap) - private void SetSlottedObject(GameObject obj) + public GameObject GetSlottedObject() + { + return _cachedSlottedObject; + } + + public void SetSlottedObject(GameObject obj) { _cachedSlottedObject = obj; if (_cachedSlottedObject != null) @@ -31,32 +35,6 @@ public class SlotItemBehavior : InteractionRequirementBase } } - private void RemoveSlottedObject() - { - if (_cachedSlottedObject != null) - { - Destroy(_cachedSlottedObject); - _cachedSlottedObject = null; - } - } - - private void CacheSlottedObject(GameObject obj) - { - // Only destroy if not swapping - RemoveSlottedObject(); - SetSlottedObject(obj); - } - - private void RestoreSlottedObject() - { - if (_cachedSlottedObject != null) - { - _cachedSlottedObject.transform.SetParent(null); - // Do NOT activate or move the object here; it stays hidden until dropped - // Activation is handled by the drop logic elsewhere - } - } - /// /// Attempts to interact with the slot, handling slotting, swapping, or picking up items. /// @@ -75,9 +53,7 @@ public class SlotItemBehavior : InteractionRequirementBase // CASE 1: No held item, slot has item -> pick up slotted item if (heldItem == null && _cachedSlottedObject != null) { - // Give the hidden slotted object to the follower (do NOT activate or move it) - RestoreSlottedObject(); - follower.SetHeldItemFromObject(_cachedSlottedObject); + InteractionOrchestrator.Instance.PickupItem(follower, _cachedSlottedObject); _cachedSlottedObject = null; currentlySlottedItem = null; UpdateSlottedSprite(); @@ -86,20 +62,9 @@ public class SlotItemBehavior : InteractionRequirementBase // CASE 2: Held item, slot has item -> swap if (heldItem != null && _cachedSlottedObject != null) { - var followerHeldObj = heldObj; - var followerHeldItem = heldItem; - var slotObj = _cachedSlottedObject; - var slotItemData = currentlySlottedItem; - - // 1. Slot the follower's held object (do NOT destroy the old one) - SetSlottedObject(followerHeldObj); - currentlySlottedItem = followerHeldItem; + InteractionOrchestrator.Instance.SwapItems(follower, this); + currentlySlottedItem = heldItem; UpdateSlottedSprite(); - - // 2. Give the slot's object to the follower (do NOT activate or move it) - RestoreSlottedObject(); - follower.SetHeldItemFromObject(slotObj); - return true; } // CASE 3: Held item, slot empty -> slot the held item @@ -110,7 +75,7 @@ public class SlotItemBehavior : InteractionRequirementBase DebugUIMessage.Show("Can't place that here."); return false; } - CacheSlottedObject(heldObj); + InteractionOrchestrator.Instance.SlotItem(this, heldObj); currentlySlottedItem = heldItem; UpdateSlottedSprite(); follower.ClearHeldItem(); diff --git a/Assets/Scripts/Movement/FollowerController.cs b/Assets/Scripts/Movement/FollowerController.cs index 3c081ae9..f194bb81 100644 --- a/Assets/Scripts/Movement/FollowerController.cs +++ b/Assets/Scripts/Movement/FollowerController.cs @@ -325,7 +325,7 @@ public class FollowerController : Character if (pickup != null) { SetHeldItem(pickup.itemData, pickup.iconRenderer); - CacheHeldPickupObject(obj); + _cachedPickupObject = obj; } else { @@ -335,11 +335,7 @@ public class FollowerController : Character public void ClearHeldItem() { - if (_cachedPickupObject != null) - { - // Destroy(_cachedPickupObject); - _cachedPickupObject = null; - } + _cachedPickupObject = null; _currentlyHeldItem = null; if (heldObjectRenderer != null) { @@ -348,6 +344,11 @@ public class FollowerController : Character } } + public void DropHeldItemAt(Vector3 position) + { + InteractionOrchestrator.Instance.DropItem(this, position); + } + private System.Collections.IEnumerator PickupSequence(Vector2 itemPosition, Transform playerTransform) { _isManualFollowing = false; @@ -376,26 +377,21 @@ public class FollowerController : Character var slotBehavior = pickup.GetComponent(); if (slotBehavior != null) { - // Slot item: do not destroy or swap, just return to player + // Slot item: orchestrator handles slotting break; } if (justCombined) { - GameObject.Destroy(pickup.gameObject); + InteractionOrchestrator.Instance.CombineItems(pickup.gameObject, _cachedPickupObject); justCombined = false; break; } // Swap logic: if holding an item, drop it here if (_currentlyHeldItem != null && _cachedPickupObject != null) { - // Drop the cached object at the pickup's position - _cachedPickupObject.transform.position = pickup.transform.position; - _cachedPickupObject.transform.SetParent(null); - _cachedPickupObject.SetActive(true); - _cachedPickupObject = null; + InteractionOrchestrator.Instance.DropItem(this, pickup.transform.position); } - SetHeldItem(pickup.itemData, pickup.iconRenderer); - CacheHeldPickupObject(pickup.gameObject); + InteractionOrchestrator.Instance.PickupItem(this, pickup.gameObject); break; } } @@ -425,27 +421,6 @@ public class FollowerController : Character _pickupCoroutine = null; } - /// - /// Drop the held item at the specified position, unparenting and activating it. - /// - /// The world position to drop the item at. - public void DropHeldItemAt(Vector3 position) - { - if (_cachedPickupObject != null) - { - _cachedPickupObject.transform.position = position; - _cachedPickupObject.transform.SetParent(null); - _cachedPickupObject.SetActive(true); - _cachedPickupObject = null; - _currentlyHeldItem = null; - if (heldObjectRenderer != null) - { - heldObjectRenderer.sprite = null; - heldObjectRenderer.enabled = false; - } - } - } - void OnDrawGizmos() { if (debugDrawTarget && Application.isPlaying)