Make a generic booster pack giver

This commit is contained in:
Michal Pikulski
2025-12-15 11:59:40 +01:00
parent e2b74b1ea5
commit bb332933ec
64 changed files with 1228 additions and 312 deletions

View File

@@ -3,6 +3,7 @@ using Core;
using UnityEngine;
using UnityEngine.UI;
using AppleHills.Core.Settings;
using Core.Settings;
namespace UI.CardSystem
{

View File

@@ -4,6 +4,7 @@ using UnityEngine;
using System;
using AppleHills.Core.Settings;
using Core;
using Core.Settings;
namespace UI.CardSystem.StateMachine
{

View File

@@ -2,6 +2,7 @@
using Core.SaveLoad;
using UnityEngine;
using AppleHills.Core.Settings;
using Core.Settings;
using Pixelplacement;
namespace UI.CardSystem.StateMachine.States

View File

@@ -2,6 +2,7 @@
using UnityEngine;
using Core;
using AppleHills.Core.Settings;
using Core.Settings;
namespace UI.CardSystem.StateMachine.States
{

View File

@@ -2,6 +2,7 @@
using UnityEngine;
using AppleHills.Core.Settings;
using Core;
using Core.Settings;
namespace UI.CardSystem.StateMachine.States
{

View File

@@ -3,6 +3,7 @@ using UnityEngine;
using AppleHills.Core.Settings;
using Core;
using AppleHills.Data.CardSystem;
using Core.Settings;
namespace UI.CardSystem.StateMachine.States
{

View File

@@ -5,6 +5,7 @@ using UnityEngine.EventSystems;
using AppleHills.Core.Settings;
using AppleHills.Data.CardSystem;
using Core;
using Core.Settings;
namespace UI.CardSystem.StateMachine.States
{

View File

@@ -9,10 +9,9 @@ using UnityEngine.UI;
namespace UI.CardSystem
{
/// <summary>
/// Singleton UI component for granting booster packs from minigames.
/// Displays a booster pack with glow effect, waits for user to click continue,
/// then shows the scrapbook button and animates the pack flying to it before granting the reward.
/// The scrapbook button is automatically hidden after the animation completes.
/// UI component for granting booster packs from minigames.
/// Supports awarding 1 to N booster packs with visual animations.
/// Shows up to 3 booster packs visually. For more than 3, duplicates the first pack and tweens them sequentially.
/// </summary>
public class MinigameBoosterGiver : MonoBehaviour
{
@@ -20,8 +19,8 @@ namespace UI.CardSystem
[Header("Visual References")]
[SerializeField] private GameObject visualContainer;
[SerializeField] private RectTransform boosterImage;
[SerializeField] private RectTransform glowImage;
[SerializeField] private RectTransform[] boosterImages; // Up to 3 booster pack visuals
[SerializeField] private RectTransform glowImage; // Single glow effect for all boosters
[SerializeField] private Button continueButton;
[Header("Animation Settings")]
@@ -32,14 +31,16 @@ namespace UI.CardSystem
[Header("Disappear Animation")]
[SerializeField] private Vector2 targetBottomLeftOffset = new Vector2(100f, 100f);
[SerializeField] private float disappearDuration = 0.8f;
[SerializeField] private float tweenDuration = 0.8f;
[SerializeField] private float delayBetweenTweens = 0.2f;
[SerializeField] private float disappearScale = 0.2f;
private Vector3 _boosterInitialPosition;
private Vector3 _boosterInitialScale;
private Vector3[] _boosterInitialPositions;
private Vector3[] _boosterInitialScales;
private Vector3 _glowInitialScale;
private Coroutine _currentSequence;
private Action _onCompleteCallback;
private int _totalPackCount = 1;
private void Awake()
{
@@ -53,11 +54,20 @@ namespace UI.CardSystem
Instance = this;
// Cache initial values
if (boosterImage != null)
// Cache initial values for all booster images
if (boosterImages != null && boosterImages.Length > 0)
{
_boosterInitialPosition = boosterImage.localPosition;
_boosterInitialScale = boosterImage.localScale;
_boosterInitialPositions = new Vector3[boosterImages.Length];
_boosterInitialScales = new Vector3[boosterImages.Length];
for (int i = 0; i < boosterImages.Length; i++)
{
if (boosterImages[i] != null)
{
_boosterInitialPositions[i] = boosterImages[i].localPosition;
_boosterInitialScales[i] = boosterImages[i].localScale;
}
}
}
if (glowImage != null)
@@ -78,6 +88,30 @@ namespace UI.CardSystem
}
}
/// <summary>
/// Initialize the booster giver with a specific pack count.
/// Shows up to 3 booster visuals based on count.
/// </summary>
/// <param name="packCount">Number of booster packs to grant</param>
public void Initialize(int packCount)
{
_totalPackCount = Mathf.Max(1, packCount);
// Show up to 3 booster visuals
int visualCount = Mathf.Min(_totalPackCount, boosterImages.Length);
for (int i = 0; i < boosterImages.Length; i++)
{
bool shouldShow = i < visualCount;
if (boosterImages[i] != null)
{
boosterImages[i].gameObject.SetActive(shouldShow);
}
}
Logging.Debug($"[MinigameBoosterGiver] Initialized with {_totalPackCount} packs, showing {visualCount} visuals");
}
private void OnDestroy()
{
if (Instance == this)
@@ -115,13 +149,19 @@ namespace UI.CardSystem
visualContainer.SetActive(true);
}
// Reset positions and scales
if (boosterImage != null)
// Reset positions and scales for visible boosters
int visualCount = Mathf.Min(_totalPackCount, boosterImages.Length);
for (int i = 0; i < visualCount; i++)
{
boosterImage.localPosition = _boosterInitialPosition;
boosterImage.localScale = _boosterInitialScale;
if (boosterImages[i] != null)
{
boosterImages[i].localPosition = _boosterInitialPositions[i];
boosterImages[i].localScale = _boosterInitialScales[i];
}
}
// Reset glow scale
if (glowImage != null)
{
glowImage.localScale = _glowInitialScale;
@@ -133,14 +173,17 @@ namespace UI.CardSystem
continueButton.interactable = true;
}
// Start idle hovering animation on booster (ping-pong)
if (boosterImage != null)
// Start idle hovering animation on all visible boosters (ping-pong)
for (int i = 0; i < visualCount; i++)
{
Vector3 hoverTarget = _boosterInitialPosition + Vector3.up * hoverAmount;
Tween.LocalPosition(boosterImage, hoverTarget, hoverDuration, 0f, Tween.EaseLinear, Tween.LoopType.PingPong);
if (boosterImages[i] != null)
{
Vector3 hoverTarget = _boosterInitialPositions[i] + Vector3.up * hoverAmount;
Tween.LocalPosition(boosterImages[i], hoverTarget, hoverDuration, 0f, Tween.EaseLinear, Tween.LoopType.PingPong);
}
}
// Start pulsing animation on glow (ping-pong scale)
// Start pulsing animation on the single glow (ping-pong scale)
if (glowImage != null)
{
Vector3 glowPulseScale = _glowInitialScale * glowPulseMax;
@@ -158,41 +201,23 @@ namespace UI.CardSystem
return; // Not in a sequence
}
// Disable button to prevent double-clicks
// Disable and hide button to prevent double-clicks
if (continueButton != null)
{
continueButton.interactable = false;
continueButton.gameObject.SetActive(false);
}
// Stop the ongoing animations by stopping all tweens on these objects
if (boosterImage != null)
{
Tween.Stop(boosterImage.GetInstanceID());
}
if (glowImage != null)
{
Tween.Stop(glowImage.GetInstanceID());
// Fade out the glow
Tween.LocalScale(glowImage, Vector3.zero, disappearDuration * 0.5f, 0f, Tween.EaseInBack);
}
// Start disappear animation
StartCoroutine(DisappearSequence());
// Start moving all boosters to backpack
StartCoroutine(MoveAllBoostersToBackpack());
}
private IEnumerator DisappearSequence()
private IEnumerator MoveAllBoostersToBackpack()
{
if (boosterImage == null)
{
yield break;
}
// Show scrapbook button temporarily using HUD visibility context
PlayerHudManager.HudVisibilityContext hudContext = null;
GameObject scrapbookButton = null;
GameObject scrapbookButton = PlayerHudManager.Instance?.GetScrabookButton();
scrapbookButton = PlayerHudManager.Instance.GetScrabookButton();
if (scrapbookButton != null)
{
hudContext = PlayerHudManager.Instance.ShowElementTemporarily(scrapbookButton);
@@ -202,75 +227,86 @@ namespace UI.CardSystem
Logging.Warning("[MinigameBoosterGiver] Scrapbook button not found in PlayerHudManager.");
}
// Calculate target position - use scrapbook button position if available
Vector3 targetPosition;
// Calculate target position once
Vector3 targetPosition = GetTargetPosition(scrapbookButton);
if (scrapbookButton != null)
int remaining = _totalPackCount;
int visualCount = Mathf.Min(_totalPackCount, boosterImages.Length);
// Stop and fade out the single glow immediately
if (glowImage != null)
{
// Get the scrapbook button's position in the same coordinate space as boosterImage
RectTransform scrapbookRect = scrapbookButton.GetComponent<RectTransform>();
if (scrapbookRect != null)
Tween.Stop(glowImage.GetInstanceID());
Tween.LocalScale(glowImage, Vector3.zero, tweenDuration * 0.5f, 0f, Tween.EaseInBack);
}
// Phase 1: Animate duplicates for packs above 3 (if any)
int duplicatesToAnimate = Mathf.Max(0, _totalPackCount - 3);
for (int i = 0; i < duplicatesToAnimate; i++)
{
// Spawn duplicate at the first booster's current position
if (boosterImages.Length > 0 && boosterImages[0] != null)
{
// Convert scrapbook button's world position to local position relative to boosterImage's parent
Canvas canvas = GetComponentInParent<Canvas>();
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
{
// For overlay canvas, convert screen position to local position
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, scrapbookRect.position);
RectTransformUtility.ScreenPointToLocalPointInRectangle(
boosterImage.parent as RectTransform,
screenPos,
null,
out Vector2 localPoint);
targetPosition = localPoint;
}
else
{
// For world space or camera canvas
targetPosition = boosterImage.parent.InverseTransformPoint(scrapbookRect.position);
}
StartCoroutine(TweenPackToBackpack(boosterImages[0], targetPosition, isDuplicate: true));
}
else
remaining--;
// Wait for stagger delay before next
if (i < duplicatesToAnimate - 1 || remaining > 0)
{
Logging.Warning("[MinigameBoosterGiver] Scrapbook button has no RectTransform, using fallback position.");
targetPosition = GetFallbackPosition();
yield return new WaitForSeconds(delayBetweenTweens);
}
}
else
// Phase 2: Animate the actual visible packs (up to 3)
for (int i = 0; i < visualCount && i < remaining; i++)
{
// Fallback to bottom-left corner
targetPosition = GetFallbackPosition();
if (boosterImages[i] != null)
{
// Stop hover animations first
Tween.Stop(boosterImages[i].GetInstanceID());
// Tween the actual booster
StartCoroutine(TweenPackToBackpack(boosterImages[i], targetPosition, isDuplicate: false));
}
// Wait for stagger delay before next (except after last one)
if (i < visualCount - 1 && i < remaining - 1)
{
yield return new WaitForSeconds(delayBetweenTweens);
}
}
// Tween to scrapbook button position
Tween.LocalPosition(boosterImage, targetPosition, disappearDuration, 0f, Tween.EaseInBack);
// Scale down
Vector3 targetScale = _boosterInitialScale * disappearScale;
Tween.LocalScale(boosterImage, targetScale, disappearDuration, 0f, Tween.EaseInBack);
// Wait for animation to complete
yield return new WaitForSeconds(disappearDuration);
// Grant the booster pack
// Wait for the last tween to complete
yield return new WaitForSeconds(tweenDuration);
// Grant all booster packs at once
if (CardSystemManager.Instance != null)
{
CardSystemManager.Instance.AddBoosterPack(1);
Logging.Debug("[MinigameBoosterGiver] Booster pack granted!");
CardSystemManager.Instance.AddBoosterPack(_totalPackCount);
Logging.Debug($"[MinigameBoosterGiver] Granted {_totalPackCount} booster pack(s)!");
}
else
{
Logging.Warning("[MinigameBoosterGiver] CardSystemManager not found, cannot grant booster pack.");
Logging.Warning("[MinigameBoosterGiver] CardSystemManager not found, cannot grant booster packs.");
}
// Hide scrapbook button by disposing the context
hudContext?.Dispose();
// Hide the visual
// Hide the visual container
if (visualContainer != null)
{
visualContainer.SetActive(false);
}
// Show button again for next use
if (continueButton != null)
{
continueButton.gameObject.SetActive(true);
}
// Invoke completion callback
_onCompleteCallback?.Invoke();
@@ -279,6 +315,92 @@ namespace UI.CardSystem
// Clear sequence reference
_currentSequence = null;
}
/// <summary>
/// Generic method to tween a booster pack to the backpack button.
/// Handles both duplicates (instantiated clones) and actual booster visuals.
/// </summary>
private IEnumerator TweenPackToBackpack(RectTransform sourceRect, Vector3 targetPosition, bool isDuplicate)
{
RectTransform packToAnimate;
if (isDuplicate)
{
// Create a clone at the source position
GameObject clone = Instantiate(sourceRect.gameObject, sourceRect.parent);
packToAnimate = clone.GetComponent<RectTransform>();
if (packToAnimate != null)
{
packToAnimate.localPosition = sourceRect.localPosition;
packToAnimate.localScale = sourceRect.localScale;
packToAnimate.gameObject.SetActive(true);
}
}
else
{
packToAnimate = sourceRect;
}
if (packToAnimate == null)
{
yield break;
}
// Tween to target position
Tween.LocalPosition(packToAnimate, targetPosition, tweenDuration, 0f, Tween.EaseInBack);
// Scale down
Vector3 targetScale = packToAnimate.localScale * disappearScale;
Tween.LocalScale(packToAnimate, targetScale, tweenDuration, 0f, Tween.EaseInBack);
// Don't wait here - let animations overlap
// Hide/destroy the booster after tween completes (duplicate or not)
// Since we destroy the entire UI instance anyway, just clean up visual artifacts
yield return new WaitForSeconds(tweenDuration);
if (packToAnimate != null)
{
packToAnimate.gameObject.SetActive(false);
}
yield break;
}
/// <summary>
/// Get the target position for the booster pack animation (scrapbook button or fallback).
/// </summary>
private Vector3 GetTargetPosition(GameObject scrapbookButton)
{
if (scrapbookButton != null && boosterImages.Length > 0 && boosterImages[0] != null)
{
RectTransform scrapbookRect = scrapbookButton.GetComponent<RectTransform>();
if (scrapbookRect != null)
{
// Convert scrapbook button's world position to local position relative to booster's parent
Canvas canvas = GetComponentInParent<Canvas>();
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
{
// For overlay canvas, convert screen position to local position
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, scrapbookRect.position);
RectTransformUtility.ScreenPointToLocalPointInRectangle(
boosterImages[0].parent as RectTransform,
screenPos,
null,
out Vector2 localPoint);
return localPoint;
}
else
{
// For world space or camera canvas
return boosterImages[0].parent.InverseTransformPoint(scrapbookRect.position);
}
}
}
// Fallback position
return GetFallbackPosition();
}
private Vector3 GetFallbackPosition()
{
@@ -292,7 +414,11 @@ namespace UI.CardSystem
else
{
// Ultimate fallback if no canvas found
return _boosterInitialPosition + new Vector3(-500f, -500f, 0f);
if (boosterImages.Length > 0 && _boosterInitialPositions != null && _boosterInitialPositions.Length > 0)
{
return _boosterInitialPositions[0] + new Vector3(-500f, -500f, 0f);
}
return new Vector3(-500f, -500f, 0f);
}
}
}

View File

@@ -307,6 +307,92 @@ namespace Core
}
}
/// <summary>
/// Displays the booster pack reward UI and grants the specified number of booster packs.
/// This method is awaitable and handles input mode switching automatically.
/// Supports awarding 1 to N booster packs with animated visuals.
/// </summary>
/// <param name="count">Number of booster packs to grant</param>
/// <returns>Task that completes when the UI sequence is finished</returns>
public async System.Threading.Tasks.Task GiveBoosterPacksAsync(int count)
{
Logging.Debug($"[GameManager] GiveBoosterPacksAsync called with count: {count}");
// Get prefab from settings
var settings = GetSettingsObject<ICardSystemSettings>();
if (settings?.BoosterPackRewardPrefab == null)
{
Logging.Warning("[GameManager] BoosterPackRewardPrefab not set in CardSystemSettings. Cannot show reward UI.");
return;
}
// Find main canvas
GameObject mainCanvasObj = GameObject.FindGameObjectWithTag("MainCanvas");
if (mainCanvasObj == null)
{
Logging.Warning("[GameManager] MainCanvas not found in scene. Cannot show reward UI.");
return;
}
// Switch to UI input mode
InputManager.Instance?.SetInputMode(InputMode.UI);
Logging.Debug("[GameManager] Switched to UI input mode");
// Instantiate UI prefab
GameObject uiInstance = Instantiate(settings.BoosterPackRewardPrefab);
var component = uiInstance.GetComponent<UI.CardSystem.MinigameBoosterGiver>();
if (component == null)
{
Logging.Warning("[GameManager] BoosterPackRewardPrefab does not have MinigameBoosterGiver component!");
Destroy(uiInstance);
InputManager.Instance?.SetInputMode(InputMode.GameAndUI);
return;
}
// Parent to main canvas and set stretch-fill anchoring
RectTransform rectTransform = uiInstance.GetComponent<RectTransform>();
if (rectTransform != null)
{
rectTransform.SetParent(mainCanvasObj.transform, false);
// Set anchors to stretch-fill (all corners)
rectTransform.anchorMin = Vector2.zero;
rectTransform.anchorMax = Vector2.one;
rectTransform.offsetMin = Vector2.zero;
rectTransform.offsetMax = Vector2.zero;
Logging.Debug("[GameManager] UI parented to MainCanvas with stretch-fill anchoring");
}
else
{
// Fallback: just parent without RectTransform adjustments
uiInstance.transform.SetParent(mainCanvasObj.transform, false);
Logging.Warning("[GameManager] UI does not have RectTransform, parented without anchor adjustment");
}
// Create TaskCompletionSource for awaiting
var tcs = new System.Threading.Tasks.TaskCompletionSource<bool>();
// Initialize the component with pack count
component.Initialize(count);
// Call GiveBooster to start the sequence
component.GiveBooster(() =>
{
Logging.Debug("[GameManager] Booster reward UI sequence completed");
Destroy(uiInstance);
tcs.SetResult(true);
});
// Await completion
await tcs.Task;
// Restore input mode to GameAndUI (default gameplay mode)
InputManager.Instance?.SetInputMode(InputMode.GameAndUI);
Logging.Debug("[GameManager] Restored to GameAndUI input mode");
}
// Helper method to get settings
private T GetSettings<T>() where T : class

View File

@@ -1,6 +1,7 @@
using UnityEngine;
using AppleHills.Core.Settings;
using UnityEngine;
namespace AppleHills.Core.Settings
namespace Core.Settings
{
/// <summary>
/// Settings for the card system - controls animations, interactions, and progression
@@ -47,6 +48,10 @@ namespace AppleHills.Core.Settings
[Tooltip("Default animation duration when not specified in seconds")]
[SerializeField] private float defaultAnimationDuration = 0.3f;
[Header("UI Prefabs")]
[Tooltip("Prefab for the booster pack reward UI displayed after minigames")]
[SerializeField] private GameObject boosterPackRewardPrefab;
// ICardSystemSettings implementation - Idle Hover Animations
public float IdleHoverHeight => idleHoverHeight;
public float IdleHoverDuration => idleHoverDuration;
@@ -70,6 +75,9 @@ namespace AppleHills.Core.Settings
// ICardSystemSettings implementation - General Animation
public float DefaultAnimationDuration => defaultAnimationDuration;
// ICardSystemSettings implementation - UI Prefabs
public GameObject BoosterPackRewardPrefab => boosterPackRewardPrefab;
public override void OnValidate()
{
base.OnValidate();

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using Core.Settings;
using UnityEngine;
namespace AppleHills.Core.Settings
{

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Core.Settings;
using UnityEngine;
using Interactions;

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using Core.Settings;
using UnityEngine;
namespace AppleHills.Core.Settings
{

View File

@@ -1,8 +1,9 @@
using UnityEngine;
using System.Collections.Generic;
using System.Collections.Generic;
using AppleHills.Core.Settings;
using Minigames.StatueDressup.Data;
using UnityEngine;
namespace AppleHills.Core.Settings
namespace Core.Settings
{
/// <summary>
/// Enum defining the different input modes for photo taking
@@ -177,6 +178,9 @@ namespace AppleHills.Core.Settings
// General Animation
float DefaultAnimationDuration { get; }
// UI Prefabs
GameObject BoosterPackRewardPrefab { get; }
}
/// <summary>
@@ -244,8 +248,8 @@ namespace AppleHills.Core.Settings
Common.Input.SlingshotConfig SlingshotSettings { get; }
// Block configurations
System.Collections.Generic.List<Minigames.FortFight.Settings.BlockMaterialConfig> MaterialConfigs { get; }
System.Collections.Generic.List<Minigames.FortFight.Settings.BlockSizeConfig> SizeConfigs { get; }
List<Minigames.FortFight.Settings.BlockMaterialConfig> MaterialConfigs { get; }
List<Minigames.FortFight.Settings.BlockSizeConfig> SizeConfigs { get; }
// AI Difficulty Settings
Minigames.FortFight.Data.AIDifficulty DefaultAIDifficulty { get; } // Default difficulty level for AI
@@ -286,7 +290,7 @@ namespace AppleHills.Core.Settings
float CeilingFanDropSpeed { get; } // Downward velocity when dropping (m/s)
// Projectile Configurations
System.Collections.Generic.IReadOnlyList<Minigames.FortFight.Data.ProjectileConfig> ProjectileConfigs { get; }
IReadOnlyList<Minigames.FortFight.Data.ProjectileConfig> ProjectileConfigs { get; }
Minigames.FortFight.Data.ProjectileConfig GetProjectileConfig(Minigames.FortFight.Data.ProjectileType type);
Minigames.FortFight.Data.ProjectileConfig GetProjectileConfigById(string projectileId);

View File

@@ -1,4 +1,5 @@
using Core;
using Core.Settings;
using UnityEngine;
namespace AppleHills
@@ -103,7 +104,7 @@ namespace AppleHills
}
#endif
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IInteractionSettings>();
var settings = GameManager.GetSettingsObject<IInteractionSettings>();
return settings?.InteractionOutlineColors;
}

View File

@@ -3,6 +3,7 @@ using Pathfinding;
using AppleHills.Core.Settings;
using Core;
using Core.Lifecycle;
using Core.Settings;
namespace Input
{

View File

@@ -6,6 +6,7 @@ using UnityEngine.SceneManagement;
using AppleHills.Core.Settings;
using Core;
using Core.Lifecycle;
using Core.Settings;
namespace Input
{

View File

@@ -1,6 +1,7 @@
using UnityEngine;
using AppleHills.Core.Settings;
using Core;
using Core.Settings;
namespace Input
{

View File

@@ -4,7 +4,8 @@ using UnityEngine;
using UnityEngine.Events;
using System; // for Action<T>
using Core; // register with ItemManager
using AppleHills.Core.Settings; // Added for IInteractionSettings
using AppleHills.Core.Settings;
using Core.Settings; // Added for IInteractionSettings
namespace Interactions
{

View File

@@ -4,6 +4,7 @@ using Core;
using Input;
using Interactions;
using System.Threading.Tasks;
using Core.Settings;
using UnityEngine;
namespace Levels

View File

@@ -4,6 +4,7 @@ using Core;
using Input;
using Interactions;
using System.Threading.Tasks;
using Core.Settings;
using PuzzleS;
using UnityEngine;

View File

@@ -1,5 +1,6 @@
using AppleHills.Core.Settings;
using Core;
using Core.Settings;
using Minigames.Airplane.Data;
namespace Minigames.Airplane.Abilities

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections;
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.Airplane.Abilities;
using Minigames.Airplane.Data;
using UnityEngine;
@@ -81,7 +82,7 @@ namespace Minigames.Airplane.Core
base.OnManagedAwake();
// Load settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IAirplaneSettings>();
var settings = GameManager.GetSettingsObject<IAirplaneSettings>();
if (settings != null)
{
mass = settings.AirplaneMass;
@@ -231,7 +232,7 @@ namespace Minigames.Airplane.Core
}
// Check if it's ground (by layer)
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IAirplaneSettings>();
var settings = GameManager.GetSettingsObject<IAirplaneSettings>();
if (settings != null && other.gameObject.layer == settings.GroundLayer)
{
if (showDebugLogs) Logging.Debug($"[AirplaneController] Hit ground at Y={transform.position.y:F2}");
@@ -302,7 +303,7 @@ namespace Minigames.Airplane.Core
public void Initialize(AirplaneAbilityType abilityType)
{
// Get settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IAirplaneSettings>();
var settings = GameManager.GetSettingsObject<IAirplaneSettings>();
if (settings == null)
{
Logging.Error("[AirplaneController] Cannot initialize - settings not found!");

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections;
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.Airplane.Data;
using UnityEngine;
@@ -261,7 +262,7 @@ namespace Minigames.Airplane.Core
Logging.Warning("[AirplaneGameManager] Using default airplane type from settings as fallback.");
// Fallback: use default type from settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IAirplaneSettings>();
var settings = GameManager.GetSettingsObject<IAirplaneSettings>();
if (settings != null)
{
_selectedAirplaneType = settings.DefaultAirplaneType;

View File

@@ -2,6 +2,7 @@ using System;
using AppleHills.Core.Settings;
using Common.Input;
using Core;
using Core.Settings;
using Minigames.Airplane.Data;
using UnityEngine;
@@ -142,7 +143,7 @@ namespace Minigames.Airplane.Core
}
// Get settings and airplane config
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IAirplaneSettings>();
var settings = GameManager.GetSettingsObject<IAirplaneSettings>();
if (settings == null)
{
Logging.Error("[AirplaneLaunchController] Cannot spawn - settings not found!");

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using AppleHills.Core.Settings;
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.Airplane.Data;
using Minigames.Airplane.UI;
using UnityEngine;

View File

@@ -1,5 +1,6 @@
using AppleHills.Core.Settings;
using Common.Input;
using Core.Settings;
using UnityEngine;
namespace Minigames.Airplane.Settings

View File

@@ -1,5 +1,6 @@
using System;
using Core;
using Core.Settings;
using Minigames.Airplane.Data;
using UnityEngine;
using UnityEngine.UI;
@@ -233,7 +234,7 @@ namespace Minigames.Airplane.UI
private void PopulateButtonIcons()
{
// Get airplane settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IAirplaneSettings>();
var settings = GameManager.GetSettingsObject<IAirplaneSettings>();
if (settings == null)
{
if (showDebugLogs)

View File

@@ -2,6 +2,7 @@
using AppleHills.Core.Interfaces;
using AppleHills.Core.Settings;
using Core;
using Core.Settings;
using UnityEngine;
using Random = UnityEngine.Random;

View File

@@ -1,5 +1,4 @@
using AppleHills.Core.Interfaces;
using AppleHills.Core.Settings;
using Cinematics;
using Core;
using Core.Lifecycle;
@@ -8,10 +7,10 @@ using Minigames.DivingForPictures.PictureCamera;
using System;
using System.Collections;
using System.Collections.Generic;
using Core.Settings;
using Minigames.DivingForPictures.Bubbles;
using UI.Core;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Playables;
namespace Minigames.DivingForPictures
@@ -664,40 +663,64 @@ namespace Minigames.DivingForPictures
_activeMonsters.Clear();
// 1) Call the booster pack giver if available
bool completed = false;
var giver = UI.CardSystem.MinigameBoosterGiver.Instance;
if (giver != null)
{
UIPageController.Instance.ShowAllUI();
Logging.Debug("[DivingGameManager] Starting booster giver sequence");
giver.GiveBooster(() =>
{
completed = true;
Logging.Debug("[DivingGameManager] Booster giver completed callback received");
});
// Calculate booster pack reward based on pictures taken
int boosterPackCount = CalculateBoosterPackReward();
Logging.Debug($"[DivingGameManager] Pictures taken: {picturesTaken}, awarding {boosterPackCount} booster pack(s)");
// 2) Wait for it to finish (NO timeout - wait indefinitely for user interaction)
while (!completed)
{
yield return null;
}
Logging.Debug("[DivingGameManager] Booster giver sequence finished, proceeding to game over");
// Show UI and grant booster packs using new async method
UIPageController.Instance.ShowAllUI();
Logging.Debug("[DivingGameManager] Starting booster giver sequence via GameManager");
// Use the new GameManager method to handle the booster pack reward
var task = GameManager.Instance.GiveBoosterPacksAsync(boosterPackCount);
// Wait for the task to complete
while (!task.IsCompleted)
{
yield return null;
}
// Check for exceptions
if (task.IsFaulted)
{
Logging.Warning($"[DivingGameManager] Booster pack reward failed: {task.Exception?.GetBaseException().Message}");
}
else
{
// If no giver is present, proceed immediately
Logging.Debug("[DivingGameManager] MinigameBoosterGiver not found; skipping booster animation.");
Logging.Debug("[DivingGameManager] Booster giver sequence finished, proceeding to game over");
}
// 3) Only then show the game over screen
// Show the game over screen
CinematicsManager.Instance.ShowGameOverScreen();
// Final score could be saved to player prefs or other persistence
Logging.Debug($"Final Score: {_playerScore}");
}
/// <summary>
/// Calculates how many booster packs to award based on the number of pictures taken.
/// </summary>
/// <returns>Number of booster packs to award</returns>
private int CalculateBoosterPackReward()
{
if (picturesTaken <= 3)
{
return 1;
}
else if (picturesTaken <= 5)
{
return 2;
}
else if (picturesTaken <= 10)
{
return 3;
}
else
{
return 4;
}
}
/// <summary>
/// Starts a smooth transition to the new velocity factor
/// </summary>

View File

@@ -5,6 +5,7 @@ using Pooling;
using Utils;
using AppleHills.Core.Interfaces;
using Core;
using Core.Settings;
namespace Minigames.DivingForPictures
{

View File

@@ -6,6 +6,7 @@ using Pooling;
using AppleHills.Core.Settings;
using AppleHills.Core.Interfaces;
using Core;
using Core.Settings;
namespace Minigames.DivingForPictures
{

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections;
using AppleHills.Core.Settings;
using Core;
using Core.Settings;
using UnityEngine.Audio;
namespace Minigames.DivingForPictures.PictureCamera

View File

@@ -4,6 +4,7 @@ using System.Collections;
using AppleHills.Core.Settings;
using AppleHills.Utilities;
using Core;
using Core.Settings;
using Minigames.DivingForPictures.Player;
namespace Minigames.DivingForPictures

View File

@@ -2,6 +2,7 @@
using AppleHills.Core.Settings;
using AppleHillsCamera;
using Core;
using Core.Settings;
using Input;
using UnityEngine;

View File

@@ -7,6 +7,7 @@ using AppleHills.Core.Settings;
using Utils;
using AppleHills.Core.Interfaces;
using Core;
using Core.Settings;
using Random = UnityEngine.Random;
namespace Minigames.DivingForPictures

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.FortFight.Core;
using Minigames.FortFight.Data;
using Minigames.FortFight.Fort;
@@ -41,7 +42,7 @@ namespace Minigames.FortFight.AI
private ProjectileType _selectedAmmo;
// Settings cache
private AppleHills.Core.Settings.IFortFightSettings _cachedSettings;
private IFortFightSettings _cachedSettings;
private AppleHills.Core.Settings.FortFightDeveloperSettings _cachedDevSettings;
private AIDifficultyData _currentDifficultyData;
@@ -55,7 +56,7 @@ namespace Minigames.FortFight.AI
public void Initialize()
{
// Load settings
_cachedSettings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
_cachedSettings = GameManager.GetSettingsObject<IFortFightSettings>();
_cachedDevSettings = GameManager.GetDeveloperSettings<AppleHills.Core.Settings.FortFightDeveloperSettings>();
if (_cachedSettings == null)

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using AppleHills.Core.Settings;
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.FortFight.Data;
using UnityEngine;

View File

@@ -2,6 +2,7 @@
using System.Linq;
using AppleHills.Core.Settings;
using Common.Input;
using Core.Settings;
using Minigames.FortFight.Data;
using Minigames.FortFight.Settings;
using UnityEngine;

View File

@@ -1,5 +1,6 @@
using AppleHills.Core.Settings;
using Core;
using Core.Settings;
using Minigames.FortFight.Data;
using Minigames.FortFight.Projectiles;
using UnityEngine;

View File

@@ -2,6 +2,7 @@
using AppleHills.Core.Settings;
using Common.Input;
using Core;
using Core.Settings;
using Minigames.FortFight.Data;
using Minigames.FortFight.Projectiles;
using UnityEngine;

View File

@@ -1,6 +1,7 @@
using System;
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.FortFight.Data;
using UnityEngine;
@@ -178,7 +179,7 @@ namespace Minigames.FortFight.Core
{
transitionTimer += Time.deltaTime;
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
float transitionDelay = settings?.TurnTransitionDelay ?? 1.5f;
if (transitionTimer >= transitionDelay)

View File

@@ -1,6 +1,7 @@
using System;
using Core;
using Core.Lifecycle;
using Core.Settings;
using UnityEngine;
using Minigames.FortFight.Data;
@@ -70,14 +71,14 @@ namespace Minigames.FortFight.Fort
private bool isDestroyed = false;
// Cached settings
private AppleHills.Core.Settings.IFortFightSettings _cachedSettings;
private AppleHills.Core.Settings.IFortFightSettings CachedSettings
private IFortFightSettings _cachedSettings;
private IFortFightSettings CachedSettings
{
get
{
if (_cachedSettings == null)
{
_cachedSettings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
_cachedSettings = GameManager.GetSettingsObject<IFortFightSettings>();
}
return _cachedSettings;
}
@@ -210,7 +211,7 @@ namespace Minigames.FortFight.Fort
{
if (spriteRenderer == null) return;
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
Color targetColor = settings?.DamageColorTint ?? new Color(0.5f, 0.5f, 0.5f);
// Darken sprite based on damage

View File

@@ -5,6 +5,7 @@ using Core;
using Core.Lifecycle;
using UnityEngine;
using AppleHills.Core.Settings;
using Core.Settings;
namespace Minigames.FortFight.Fort
{

View File

@@ -1,5 +1,6 @@
using System.Collections;
using Core;
using Core.Settings;
using UnityEngine;
namespace Minigames.FortFight.Projectiles
@@ -34,7 +35,7 @@ namespace Minigames.FortFight.Projectiles
private IEnumerator ActivationDelayCoroutine()
{
// Get activation delay from settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
float activationDelay = settings?.CeilingFanActivationDelay ?? 0.5f;
// Wait for delay
@@ -82,7 +83,7 @@ namespace Minigames.FortFight.Projectiles
}
// Get drop configuration from settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
float dropDelay = settings?.CeilingFanDropDelay ?? 0.2f;
float dropSpeed = settings?.CeilingFanDropSpeed ?? 20f;

View File

@@ -1,6 +1,7 @@
using System;
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.FortFight.Fort;
using UnityEngine;
@@ -83,7 +84,7 @@ namespace Minigames.FortFight.Projectiles
ProjectileType = projectileType;
// Load damage and mass from settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
if (settings != null)
{
var config = settings.GetProjectileConfig(projectileType);
@@ -120,7 +121,7 @@ namespace Minigames.FortFight.Projectiles
base.OnManagedAwake();
// Automatically assign projectile to correct layer from settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
if (settings != null && settings.ProjectileLayer >= 0 && gameObject.layer != settings.ProjectileLayer)
{
gameObject.layer = settings.ProjectileLayer;

View File

@@ -1,4 +1,5 @@
using Core;
using Core.Settings;
using UnityEngine;
namespace Minigames.FortFight.Projectiles
@@ -24,7 +25,7 @@ namespace Minigames.FortFight.Projectiles
}
// Get settings for trash pieces
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
int pieceCount = settings?.TrashBagPieceCount ?? 8;
Logging.Debug($"[TrashBagProjectile] Splitting into {pieceCount} pieces");
@@ -53,7 +54,7 @@ namespace Minigames.FortFight.Projectiles
}
// Get settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
int pieceCount = settings?.TrashBagPieceCount ?? 8;
float pieceForce = settings?.TrashBagPieceForce ?? 10f;
float spreadAngle = settings?.TrashBagSpreadAngle ?? 60f;

View File

@@ -1,4 +1,5 @@
using Core;
using Core.Settings;
using UnityEngine;
namespace Minigames.FortFight.Projectiles
@@ -19,7 +20,7 @@ namespace Minigames.FortFight.Projectiles
private void Start()
{
// Get configuration from settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
damage = settings?.TrashPieceDamage ?? 5f;
float lifetime = settings?.TrashPieceLifetime ?? 5f;

View File

@@ -1,4 +1,5 @@
using Core;
using Core.Settings;
using UnityEngine;
namespace Minigames.FortFight.Projectiles
@@ -26,7 +27,7 @@ namespace Minigames.FortFight.Projectiles
SpawnImpactEffect(collision.contacts[0].point);
// Get damage from settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
float blockDamage = settings?.VacuumBlockDamage ?? 999f;
// Deal high damage to destroy block instantly
@@ -62,7 +63,7 @@ namespace Minigames.FortFight.Projectiles
isSliding = true;
// Get settings
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
if (settings != null)
{
maxBlocksToDestroy = settings.VacuumDestroyBlockCount;
@@ -85,7 +86,7 @@ namespace Minigames.FortFight.Projectiles
if (isSliding && rb2D != null)
{
// Set constant velocity in slide direction
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
float slideSpeed = settings?.VacuumSlideSpeed ?? 10f;
rb2D.linearVelocity = slideDirection * slideSpeed;

View File

@@ -1,5 +1,6 @@
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.FortFight.Core;
using Minigames.FortFight.Data;
using UnityEngine;
@@ -97,7 +98,7 @@ namespace Minigames.FortFight.UI
// Get available projectile types from settings
var availableTypes = AmmunitionManager.Instance.GetAvailableProjectileTypes();
var settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IFortFightSettings>();
var settings = GameManager.GetSettingsObject<IFortFightSettings>();
if (settings == null)
{

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using Core;
using Core.Lifecycle;
using Core.Settings;
using Minigames.StatueDressup.Data;
using UnityEngine;
using UnityEngine.ResourceManagement.AsyncOperations;
@@ -18,7 +19,7 @@ namespace Minigames.StatueDressup.Controllers
// Static callback queue for when instance doesn't exist yet
private static readonly List<System.Action> PendingCallbacks = new List<System.Action>();
private AppleHills.Core.Settings.IStatueDressupSettings settings;
private IStatueDressupSettings settings;
private Dictionary<string, DecorationData> decorationDataDict;
private AsyncOperationHandle<System.Collections.Generic.IList<DecorationData>> decorationDataHandle;
private bool isLoaded;
@@ -26,7 +27,7 @@ namespace Minigames.StatueDressup.Controllers
/// <summary>
/// Get the settings instance
/// </summary>
public AppleHills.Core.Settings.IStatueDressupSettings Settings => settings;
public IStatueDressupSettings Settings => settings;
/// <summary>
/// Check if data is loaded and ready (implements IReadyNotifier)
@@ -102,7 +103,7 @@ namespace Minigames.StatueDressup.Controllers
Logging.Debug("[DecorationDataManager] Waiting for GameManager to be accessible...");
// Wait until GameManager is accessible and settings can be retrieved
settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
settings = GameManager.GetSettingsObject<IStatueDressupSettings>();
Logging.Debug("[DecorationDataManager] Settings loaded successfully");

View File

@@ -1,4 +1,5 @@
using Minigames.StatueDressup.Data;
using Core.Settings;
using Minigames.StatueDressup.Data;
using UnityEngine;
namespace Minigames.StatueDressup.DragDrop
@@ -37,7 +38,7 @@ namespace Minigames.StatueDressup.DragDrop
/// <summary>
/// Settings for the minigame
/// </summary>
public AppleHills.Core.Settings.IStatueDressupSettings Settings { get; set; }
public IStatueDressupSettings Settings { get; set; }
/// <summary>
/// Callback when drag operation finishes (success or failure)
@@ -67,7 +68,7 @@ namespace Minigames.StatueDressup.DragDrop
RectTransform statueOutline,
Transform statueParent,
Controllers.StatueDecorationController controller,
AppleHills.Core.Settings.IStatueDressupSettings settings,
IStatueDressupSettings settings,
System.Action onFinished,
System.Action onShowOutline,
System.Action onHideOutline)
@@ -92,7 +93,7 @@ namespace Minigames.StatueDressup.DragDrop
public static DecorationDragContext CreateForPlaced(
DecorationData data,
Controllers.StatueDecorationController controller,
AppleHills.Core.Settings.IStatueDressupSettings settings,
IStatueDressupSettings settings,
RectTransform statueOutline = null,
Transform canvasParent = null,
System.Action onShowOutline = null,

View File

@@ -1,4 +1,5 @@
using Core;
using Core.Settings;
using Minigames.StatueDressup.Controllers;
using Minigames.StatueDressup.Data;
using Minigames.StatueDressup.Events;
@@ -28,7 +29,7 @@ namespace Minigames.StatueDressup.DragDrop
private RectTransform _statueOutline;
private Transform _statueParent;
private StatueDecorationController _controller;
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
private IStatueDressupSettings _settings;
private System.Action _onFinishedCallback;
private System.Action _onShowOutlineCallback;
private System.Action _onHideOutlineCallback;
@@ -123,7 +124,7 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary>
[System.Obsolete("Use InitializeWithContext instead")]
public void Initialize(DecorationData data, RectTransform pStatueOutline, Transform pStatueParent,
StatueDecorationController pController, AppleHills.Core.Settings.IStatueDressupSettings pSettings,
StatueDecorationController pController, IStatueDressupSettings pSettings,
System.Action pOnFinishedCallback, System.Action onShowOutline = null, System.Action onHideOutline = null)
{
var context = DecorationDragContext.CreateForNewDrag(
@@ -138,7 +139,7 @@ namespace Minigames.StatueDressup.DragDrop
/// </summary>
[System.Obsolete("Use InitializeWithContext instead")]
public void InitializeAsPlaced(DecorationData data, StatueDecorationController pController,
AppleHills.Core.Settings.IStatueDressupSettings pSettings, RectTransform pStatueOutline = null,
IStatueDressupSettings pSettings, RectTransform pStatueOutline = null,
Transform pCanvasParent = null, System.Action onShowOutline = null, System.Action onHideOutline = null,
System.Action onFinished = null)
{

View File

@@ -1,4 +1,5 @@
using Core;
using Core.Settings;
using Minigames.StatueDressup.Controllers;
using Minigames.StatueDressup.DragDrop;
using UnityEngine;
@@ -24,7 +25,7 @@ namespace Minigames.StatueDressup.UI
[SerializeField] private int activeDecorationSortOrder = 100;
private DecorationDraggableInstance _targetDecoration;
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
private IStatueDressupSettings _settings;
private bool _isInitialized;
// Canvas management for rendering order

View File

@@ -2,6 +2,7 @@ using Core;
using UnityEngine;
using Input;
using AppleHills.Core.Settings;
using Core.Settings;
namespace Minigames.TrashMaze.Core
{

View File

@@ -3,6 +3,7 @@ using Minigames.TrashMaze.Core;
using UnityEngine;
using System.Collections;
using AppleHills.Core.Settings;
using Core.Settings;
namespace Minigames.TrashMaze.Objects
{

View File

@@ -5,6 +5,7 @@ using Utils;
using AppleHills.Core.Settings;
using Core;
using Core.Lifecycle;
using Core.Settings;
using UnityEngine.Events;
/// <summary>

View File

@@ -7,6 +7,7 @@ using UnityEngine.SceneManagement;
using AppleHills.Core.Settings;
using Core;
using Core.Lifecycle;
using Core.Settings;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using Utils;

View File

@@ -3,6 +3,7 @@ using System.Linq;
using UnityEngine;
using AppleHills.Core.Settings;
using Core;
using Core.Settings;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.ResourceLocations;