using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using Watermelon.SquadShooter; using Random = UnityEngine.Random; namespace Watermelon.LevelSystem { public static class Drop { private static List dropItems = new List(); private static DropAnimation[] dropAnimations; private static List activeObjects = new List(); /// /// Initializes the drop system with the specified settings. /// /// The settings for the drop system. public static void Init(DropableItemSettings dropSettings) { if (dropSettings == null) { Debug.LogError("DropableItemSettings cannot be null"); return; } activeObjects = new List(); dropAnimations = dropSettings.DropAnimations; foreach (CustomDropItem customDropItem in dropSettings.CustomDropItems) { RegisterDropItem(customDropItem); } // Register currencies drop CurrencyDropItem currencyDropItem = new CurrencyDropItem(); currencyDropItem.SetCurrencies(CurrencyController.Currencies); RegisterDropItem(currencyDropItem); // Register weapons drop RegisterDropItem(new WeaponDropItem()); // Register characters drop RegisterDropItem(new CharacterDropItem()); } /// /// Automatically collects all auto-pickable items. /// public static void AutoCollect() { if (!activeObjects.IsNullOrEmpty()) { foreach (BaseDropBehavior item in activeObjects) { if (!item.IsPicked && item.IsAutoPickable) { item.ApplyReward(true); } } } } /// /// Unloads all registered drop items and clears the drop system. /// public static void Unload() { if (!dropItems.IsNullOrEmpty()) { foreach (IDropItem item in dropItems) { item.Unload(); } dropItems.Clear(); } dropAnimations = null; } /// /// Called when a room is loaded, destroys all active drop objects. /// public static void OnRoomLoaded() { if (activeObjects.Count > 0) DestroyActiveObjects(); } /// /// Destroys all active drop objects. /// public static void DestroyActiveObjects() { if (activeObjects.IsNullOrEmpty()) return; foreach (BaseDropBehavior activeObject in activeObjects) { activeObject?.Unload(); } activeObjects.Clear(); } /// /// Removes a drop object from the list of active objects. /// /// The drop object to remove. public static void RemoveObject(BaseDropBehavior dropObject) { activeObjects.Remove(dropObject); } /// /// Registers a new drop item. /// /// The drop item to register. public static void RegisterDropItem(IDropItem dropItem) { if (dropItem == null) { Debug.LogError("Drop item cannot be null."); return; } #if UNITY_EDITOR if (dropItems.Exists(item => item.DropItemType == dropItem.DropItemType)) { Debug.LogError($"Drop item with type {dropItem.DropItemType} is already registered!"); return; } #endif dropItems.Add(dropItem); dropItem.Init(); } /// /// Gets a drop item by its type. /// /// The type of the drop item. /// The drop item if found, otherwise null. public static IDropItem GetDropItem(DropableItemType dropableItemType) { return dropItems.Find(item => item.DropItemType == dropableItemType); } /// /// Gets a drop animation by its falling style. /// /// The falling style of the drop animation. /// The drop animation if found, otherwise null. public static DropAnimation GetAnimation(DropFallingStyle dropFallingStyle) { return dropAnimations?.FirstOrDefault(animation => animation.FallStyle == dropFallingStyle); } /// /// Drops an item at the specified position with the given parameters. /// /// The data for the drop. /// The position to spawn the drop. /// The rotation of the drop. /// The falling style of the drop. /// The delay before the item can be picked up. /// The delay before the item is automatically picked up. /// Whether the drop is rewarded. /// The game object of the dropped item. private static GameObject DropItem(DropData dropData, Vector3 spawnPosition, Vector3 rotation, DropFallingStyle fallingStyle, float availableToPickDelay = -1f, float autoPickDelay = -1f, bool rewarded = false) { IDropItem dropItem = GetDropItem(dropData.DropType); if (dropItem == null) return null; GameObject dropPrefab = dropItem.GetDropObject(dropData); if (dropPrefab == null) return null; GameObject itemGameObject = GameObject.Instantiate(dropItem.GetDropObject(dropData)); BaseDropBehavior item = itemGameObject.GetComponent(); item.Init(dropData, availableToPickDelay, autoPickDelay); item.IsRewarded = rewarded; itemGameObject.transform.position = spawnPosition + (Random.insideUnitSphere * 0.05f); itemGameObject.transform.localScale = Vector3.one; itemGameObject.transform.eulerAngles = rotation; itemGameObject.SetActive(true); activeObjects.Add(item); return itemGameObject; } public static void ThrowItem(BaseDropBehavior baseDropBehavior, DropFallingStyle fallingStyle) { DropAnimation dropAnimation = GetAnimation(fallingStyle); Transform itemTransform = baseDropBehavior.transform; Vector3 spawnPosition = itemTransform.position; itemTransform.position = itemTransform.position + new Vector3(0, dropAnimation.OffsetY, 0); Vector3 targetPosition = spawnPosition.GetRandomPositionAroundObject(dropAnimation.Radius * 0.9f, dropAnimation.Radius * 1.2f).AddToY(0.1f); baseDropBehavior.Throw(targetPosition, dropAnimation, dropAnimation.FallTime); } public static void SpawnDropItem(DropData dropData, Vector3 spawnPosition, Vector3 rotation, bool isRewarded, Action spawnCallback = null) { if (dropData.DropType == DropableItemType.Currency) { int itemsAmount = Mathf.Clamp(Random.Range(9, 11), 1, dropData.Amount); List itemValues = LevelController.SplitIntEqually(dropData.Amount, itemsAmount); for (int j = 0; j < itemsAmount; j++) { int tempIndex = j; Tween.DelayedCall(j * 0.01f, () => { DropData data = dropData.Clone(); data.Amount = itemValues[tempIndex]; GameObject dropObject = Drop.DropItem(data, spawnPosition, Vector3.zero.SetY(Random.Range(0f, 360f)), DropFallingStyle.Coin, itemValues[tempIndex], 0.5f, rewarded: isRewarded); if (dropObject != null) { CurrencyDropBehavior dropBehavior = dropObject.GetComponent(); if (dropBehavior != null) { dropBehavior.SetCurrencyData(data.CurrencyType, itemValues[tempIndex]); spawnCallback?.Invoke(dropBehavior, DropFallingStyle.Coin); } } }); } } else if (dropData.DropType == DropableItemType.WeaponCard) { for (int j = 0; j < dropData.Amount; j++) { GameObject dropObject = Drop.DropItem(dropData, spawnPosition, Vector3.zero, DropFallingStyle.Default, 1, 0.6f); if (dropObject != null) { WeaponCardDropBehavior card = dropObject.GetComponent(); if(card != null) { card.SetCardData(dropData.Weapon); spawnCallback?.Invoke(card, DropFallingStyle.Default); } } } } else if (dropData.DropType == DropableItemType.Character) { GameObject dropObject = Drop.DropItem(dropData, spawnPosition, Vector3.zero.SetY(Random.Range(0f, 360f)), DropFallingStyle.Default, 1); if (dropObject != null) { CharacterDropBehavior characterDropBehavior = dropObject.GetComponent(); if(characterDropBehavior != null) { characterDropBehavior.SetCharacterData(dropData.Character, dropData.Level); spawnCallback?.Invoke(characterDropBehavior, DropFallingStyle.Default); } } } else if (dropData.DropType == DropableItemType.Weapon) { GameObject dropObject = Drop.DropItem(dropData, spawnPosition, Vector3.zero.SetY(Random.Range(0f, 360f)), DropFallingStyle.Default, 1); if (dropObject != null) { WeaponDropBehavior weaponDropBehavior = dropObject.GetComponent(); if(weaponDropBehavior != null) { weaponDropBehavior.SetWeaponData(dropData.Weapon, dropData.Level); spawnCallback?.Invoke(weaponDropBehavior, DropFallingStyle.Default); } } } else if (dropData.DropType == DropableItemType.Heal) { GameObject dropObject = Drop.DropItem(dropData, spawnPosition, Vector3.zero.SetY(Random.Range(0f, 360f)), DropFallingStyle.Default, 1); if (dropObject != null) { HealDropBehaviour healDropBehaviour = dropObject.GetComponent(); if (healDropBehaviour != null) { healDropBehaviour.SetData(dropData.Amount); spawnCallback?.Invoke(healDropBehaviour, DropFallingStyle.Default); } } } else { GameObject dropObject = Drop.DropItem(dropData, spawnPosition, Vector3.zero.SetY(Random.Range(0f, 360f)), DropFallingStyle.Default, 1); if (dropObject != null) { BaseDropBehavior dropBehavior = dropObject.GetComponent(); if (dropBehavior != null) { spawnCallback?.Invoke(dropBehavior, DropFallingStyle.Default); } } } } } }